[geary/bug/728002-webkit2: 57/140] Add Geary.TimeoutManager as a high-level interface to GLib.Timeout.
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/bug/728002-webkit2: 57/140] Add Geary.TimeoutManager as a high-level interface to GLib.Timeout.
- Date: Tue, 31 Jan 2017 23:03:20 +0000 (UTC)
commit 271b9460ec8f7e721f45e2577ce4a582441a1c45
Author: Michael James Gratton <mike vee net>
Date: Tue Jan 3 20:16:06 2017 +1100
Add Geary.TimeoutManager as a high-level interface to GLib.Timeout.
src/CMakeLists.txt | 1 +
src/engine/util/util-timeout-manager.vala | 114 ++++++++++++++++++++++++++++
test/CMakeLists.txt | 1 +
test/engine/util-timeout-manager-test.vala | 64 ++++++++++++++++
test/main.vala | 1 +
5 files changed, 181 insertions(+), 0 deletions(-)
---
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dfab7bf..a91beda 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -307,6 +307,7 @@ engine/util/util-stream.vala
engine/util/util-string.vala
engine/util/util-synchronization.vala
engine/util/util-time.vala
+engine/util/util-timeout-manager.vala
engine/util/util-trillian.vala
${CMAKE_BINARY_DIR}/geary-version.vala
diff --git a/src/engine/util/util-timeout-manager.vala b/src/engine/util/util-timeout-manager.vala
new file mode 100644
index 0000000..92adfdc
--- /dev/null
+++ b/src/engine/util/util-timeout-manager.vala
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+/**
+ * Executes a function after a certain period of time has elapsed.
+ *
+ * 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.TimeoutManager : BaseObject {
+
+
+ /** Specifies the priority the timeout 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 timeout should fire once or continuously. */
+ public enum Repeat { ONCE, FOREVER; }
+
+ /** The timeout callback function prototype. */
+ public delegate void TimeoutFunc(TimeoutManager manager);
+
+
+ /** Determines if {@link interval} represent seconds. */
+ public bool use_seconds;
+
+ /** The interval after which the timeout is fired, in seconds or milliseconds */
+ public uint interval;
+
+ /** Determines if this timeout will continue to fire after the first time. */
+ public Repeat repetition = Repeat.ONCE;
+
+ /** Determines the priority this timeout will receive on the main loop. */
+ public Priority priority = Priority.DEFAULT;
+
+ /** Determines if the timeout is waiting to fire or not. */
+ public bool is_running {
+ get { return this.source_id >= 0; }
+ }
+
+ private TimeoutFunc callback;
+ private int source_id = -1;
+
+
+ /**
+ * Constructs a new timeout with an interval in seconds.
+ *
+ * The timeout will be by default not running, and hence needs to be
+ * started by a call to {@link start}.
+ */
+ public TimeoutManager.seconds(uint interval, TimeoutFunc callback) {
+ this.use_seconds = true;
+ this.interval = interval;
+ this.callback = callback;
+ }
+
+ ~TimeoutManager() {
+ reset();
+ }
+
+ /**
+ * Schedules the timeout to fire after the given interval.
+ *
+ * If the timeout is already running, it will first be reset.
+ */
+ public void start() {
+ reset();
+ this.source_id = (int) (
+ (this.use_seconds)
+ ? GLib.Timeout.add_seconds(this.interval, on_trigger, this.priority)
+ : GLib.Timeout.add(this.interval, on_trigger, this.priority)
+ );
+ }
+
+ /**
+ * Prevents the timeout from firing.
+ *
+ * After a call to this timeout will not fire again, regardless of
+ * the specified repetition for the timeout.
+ *
+ * @return `true` if the timeout was already running, 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() {
+ callback(this);
+ bool ret = Source.CONTINUE;
+ if (this.repetition == Repeat.ONCE) {
+ this.source_id = -1;
+ ret = Source.REMOVE;
+ }
+ return ret;
+ }
+
+}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 87a977e..92af56e 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-timeout-manager-test.vala
client/application/geary-configuration-test.vala
client/components/client-web-view-test-case.vala
diff --git a/test/engine/util-timeout-manager-test.vala b/test/engine/util-timeout-manager-test.vala
new file mode 100644
index 0000000..99851d6
--- /dev/null
+++ b/test/engine/util-timeout-manager-test.vala
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016 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.TimeoutManagerTest : Gee.TestCase {
+
+ // add_seconds seems to vary wildly, so needs a large epsilon
+ private const double SECONDS_EPSILON = 1.8;
+
+ public TimeoutManagerTest() {
+ base("Geary.TimeoutManagerTest");
+ add_test("start_reset", start_reset);
+ add_test("test_seconds", test_seconds);
+ add_test("test_repeat_forever", test_repeat_forever);
+ }
+
+ public void start_reset() {
+ TimeoutManager test = new TimeoutManager.seconds(1, () => { /* noop */ });
+ assert(!test.is_running);
+ test.start();
+ assert(test.is_running);
+ test.reset();
+ assert(!test.is_running);
+ }
+
+ public void test_seconds() {
+ Timer timer = new Timer();
+
+ TimeoutManager test = new TimeoutManager.seconds(1, () => { timer.stop(); });
+ test.start();
+
+ timer.start();
+ while (test.is_running && timer.elapsed() < SECONDS_EPSILON) {
+ Gtk.main_iteration();
+ }
+
+ assert_epsilon(timer.elapsed(), 1.0, SECONDS_EPSILON);
+ }
+
+ public void test_repeat_forever() {
+ Timer timer = new Timer();
+ int count = 0;
+
+ TimeoutManager test = new TimeoutManager.seconds(1, () => { count++; });
+ test.repetition = TimeoutManager.Repeat.FOREVER;
+ test.start();
+
+ timer.start();
+ while (count < 2 && timer.elapsed() < SECONDS_EPSILON * 2) {
+ Gtk.main_iteration();
+ }
+ timer.stop();
+
+ assert_epsilon(timer.elapsed(), 2.0, SECONDS_EPSILON * 2);
+ }
+
+ private inline void assert_epsilon(double actual, double expected, double epsilon) {
+ assert(actual + epsilon >= expected && actual - epsilon <= expected);
+ }
+
+}
diff --git a/test/main.vala b/test/main.vala
index c82e569..7fb7842 100644
--- a/test/main.vala
+++ b/test/main.vala
@@ -42,6 +42,7 @@ int main(string[] args) {
engine.add_suite(new Geary.RFC822.MessageTest().get_suite());
engine.add_suite(new Geary.RFC822.MessageDataTest().get_suite());
engine.add_suite(new Geary.RFC822.Utils.Test().get_suite());
+ engine.add_suite(new Geary.TimeoutManagerTest().get_suite());
TestSuite client = new TestSuite("client");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]