[geary] Add IdleManager class for sane main loop idle scheduling.



commit 31fbfd40470aedabec8f6779face91bacc99f7f8
Author: Michael James Gratton <mike vee net>
Date:   Thu Feb 9 10:54:45 2017 +1100

    Add IdleManager class for sane main loop idle scheduling.

 po/POTFILES.in                          |    1 +
 src/CMakeLists.txt                      |    1 +
 src/engine/util/util-idle-manager.vala  |  102 +++++++++++++++++++++++++++++++
 test/CMakeLists.txt                     |    1 +
 test/engine/util-idle-manager-test.vala |   40 ++++++++++++
 test/main.vala                          |    3 +-
 6 files changed, 147 insertions(+), 1 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5ee6610..345dcbf 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -368,6 +368,7 @@ src/engine/util/util-converter.vala
 src/engine/util/util-files.vala
 src/engine/util/util-generic-capabilities.vala
 src/engine/util/util-html.vala
+src/engine/util/util-idle-manager.vala
 src/engine/util/util-imap-utf7.vala
 src/engine/util/util-inet.vala
 src/engine/util/util-iterable.vala
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index eab8d3d..4b39a8f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -295,6 +295,7 @@ engine/util/util-converter.vala
 engine/util/util-files.vala
 engine/util/util-generic-capabilities.vala
 engine/util/util-html.vala
+engine/util/util-idle-manager.vala
 engine/util/util-imap-utf7.vala
 engine/util/util-inet.vala
 engine/util/util-iterable.vala
diff --git a/src/engine/util/util-idle-manager.vala b/src/engine/util/util-idle-manager.vala
new file mode 100644
index 0000000..fac46dc
--- /dev/null
+++ b/src/engine/util/util-idle-manager.vala
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2017 Michael Gratton <mike vee net>
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+/**
+ * Manages execution of a function on the main loop.
+ *
+ * This class is a convenience API for the GLib main loop and source
+ * infrastructure, automatically performing cleanup when destroyed.
+ *
+ * Note this class is not thread safe and should only be invoked from
+ * the main loop.
+ */
+public class Geary.IdleManager : BaseObject {
+
+
+    /** Specifies the priority the idle function should be given. */
+    public enum Priority {
+        HIGH = GLib.Priority.HIGH,
+        DEFAULT = GLib.Priority.DEFAULT,
+        HIGH_IDLE = GLib.Priority.HIGH_IDLE,
+        DEFAULT_IDLE = GLib.Priority.DEFAULT_IDLE,
+        LOW = GLib.Priority.LOW;
+    }
+
+    /** Specifies if the idle function should run once or be continuously. */
+    public enum Repeat { ONCE, FOREVER; }
+
+    /** The idle callback function prototype. */
+    public delegate void IdleFunc(IdleManager manager);
+
+    /** Determines if the function will be re-scheduled after being run. */
+    public Repeat repetition = Repeat.ONCE;
+
+    /** Determines the priority the function will receive on the main loop. */
+    public Priority priority = Priority.DEFAULT;
+
+    /** Determines if the function is waiting to fire or not. */
+    public bool is_running {
+        get { return this.source_id >= 0; }
+    }
+
+    private IdleFunc callback;
+    private int source_id = -1;
+
+
+    /**
+     * Constructs a new idle manager with an interval in seconds.
+     *
+     * The idle function will be by default not running, and hence
+     * needs to be started by a call to {@link start}.
+     */
+    public IdleManager(IdleFunc callback) {
+        this.callback = callback;
+    }
+
+    ~IdleManager() {
+        reset();
+    }
+
+    /**
+     * Schedules the idle function to run on the main loop.
+     *
+     * If the function is already waiting to run, it will first be reset.
+     */
+    public void schedule() {
+        reset();
+        this.source_id = (int) GLib.Idle.add_full(this.priority, on_trigger);
+    }
+
+    /**
+     * Prevents the idle function from being run.
+     *
+     * @return `true` if function was already scheduled, else `false`
+     */
+    public bool reset() {
+        bool is_running = this.is_running;
+        if (is_running) {
+            Source.remove(this.source_id);
+            this.source_id = -1;
+        }
+        return is_running;
+    }
+
+    private bool on_trigger() {
+        bool ret = Source.CONTINUE;
+        // If running only once, reset the source id now in case the
+        // callback resets the timer while it is executing, so we
+        // avoid removing the source just before it would be removed
+        // after this call anyway
+        if (this.repetition == Repeat.ONCE) {
+            this.source_id = -1;
+            ret = Source.REMOVE;
+        }
+        callback(this);
+        return ret;
+    }
+
+}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 3c688d4..be65cfc 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -11,6 +11,7 @@ set(TEST_SRC
   engine/rfc822-message-data-test.vala
   engine/rfc822-utils-test.vala
   engine/util-html-test.vala
+  engine/util-idle-manager-test.vala
   engine/util-inet-test.vala
   engine/util-js-test.vala
   engine/util-timeout-manager-test.vala
diff --git a/test/engine/util-idle-manager-test.vala b/test/engine/util-idle-manager-test.vala
new file mode 100644
index 0000000..c0bfa22
--- /dev/null
+++ b/test/engine/util-idle-manager-test.vala
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017 Michael Gratton <mike vee net>
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+class Geary.IdleManagerTest : Gee.TestCase {
+
+    public IdleManagerTest() {
+        base("Geary.IdleManagerTest");
+        add_test("start_reset", start_reset);
+        add_test("test_run", test_run);
+    }
+
+    public void start_reset() {
+        IdleManager test = new IdleManager(() => { /* noop */ });
+        assert(!test.is_running);
+        test.schedule();
+        assert(test.is_running);
+        test.reset();
+        assert(!test.is_running);
+    }
+
+    public void test_run() {
+        bool did_run = false;
+
+        IdleManager test = new IdleManager(() => { did_run = true; });
+        test.schedule();
+
+        // There should be at least one event pending
+        assert(Gtk.events_pending());
+
+        // Execute the idle function
+        Gtk.main_iteration();
+
+        assert(did_run);
+    }
+
+}
diff --git a/test/main.vala b/test/main.vala
index 74382e8..8d4dff1 100644
--- a/test/main.vala
+++ b/test/main.vala
@@ -38,8 +38,9 @@ int main(string[] args) {
     TestSuite engine = new TestSuite("engine");
 
     engine.add_suite(new Geary.HTML.UtilTest().get_suite());
-    engine.add_suite(new Geary.JS.Test().get_suite()); 
+    engine.add_suite(new Geary.IdleManagerTest().get_suite());
     engine.add_suite(new Geary.Inet.Test().get_suite());
+    engine.add_suite(new Geary.JS.Test().get_suite());
     engine.add_suite(new Geary.RFC822.MailboxAddressTest().get_suite());
     engine.add_suite(new Geary.RFC822.MessageTest().get_suite());
     engine.add_suite(new Geary.RFC822.MessageDataTest().get_suite());


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]