[gnome-todo] timer: introduce GtdTimer



commit 65f6770a38e63b85e95e060a3b602a68a6af4804
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sun Apr 23 13:59:57 2017 -0300

    timer: introduce GtdTimer
    
    A new class to notify us when we should update our
    lists.

 src/Makefile.am          |    5 +
 src/engine/gtd-manager.c |   44 +++++++++
 src/engine/gtd-manager.h |    2 +
 src/gtd-timer.c          |  232 ++++++++++++++++++++++++++++++++++++++++++++++
 src/gtd-timer.h          |   37 ++++++++
 src/gtd-types.h          |    1 +
 6 files changed, 321 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 1dd5749..99dc43b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -87,6 +87,8 @@ gnome_todo_SOURCES = \
        gtd-task-list-view.h \
        gtd-task-row.c \
        gtd-task-row.h \
+       gtd-timer.c \
+       gtd-timer.h \
        gtd-types.h \
        gtd-window.c \
        gtd-window.h \
@@ -142,6 +144,7 @@ nobase_gnome_todo_include_HEADERS = \
        gtd-task.h \
        gtd-task-list.h \
        gtd-task-list-view.h \
+       gtd-timer.h \
        gtd-window.h \
        gtd-types.h \
        gnome-todo.h
@@ -223,6 +226,8 @@ introspection_sources = \
        gtd-task-list.h \
        gtd-task-list-view.c \
        gtd-task-list-view.h \
+       gtd-timer.c \
+       gtd-timer.h \
        gtd-window.c \
        gtd-window.h \
        gtd-types.h \
diff --git a/src/engine/gtd-manager.c b/src/engine/gtd-manager.c
index 84ff314..fe0dca1 100644
--- a/src/engine/gtd-manager.c
+++ b/src/engine/gtd-manager.c
@@ -23,6 +23,7 @@
 #include "gtd-plugin-manager.h"
 #include "gtd-task.h"
 #include "gtd-task-list.h"
+#include "gtd-timer.h"
 
 #include <glib/gi18n.h>
 
@@ -50,6 +51,7 @@ typedef struct
   GList                 *providers;
   GList                 *panels;
   GtdProvider           *default_provider;
+  GtdTimer              *timer;
 } GtdManagerPrivate;
 
 struct _GtdManager
@@ -83,6 +85,7 @@ enum
   PROP_0,
   PROP_DEFAULT_PROVIDER,
   PROP_DEFAULT_TASKLIST,
+  PROP_TIMER,
   PROP_PLUGIN_MANAGER,
   LAST_PROP
 };
@@ -124,6 +127,7 @@ gtd_manager_finalize (GObject *object)
 
   g_clear_object (&self->priv->plugin_manager);
   g_clear_object (&self->priv->settings);
+  g_clear_object (&self->priv->timer);
 
   G_OBJECT_CLASS (gtd_manager_parent_class)->finalize (object);
 }
@@ -146,6 +150,10 @@ gtd_manager_get_property (GObject    *object,
       g_value_set_object (value, gtd_provider_get_default_task_list (priv->default_provider));
       break;
 
+    case PROP_TIMER:
+      g_value_set_object (value, priv->timer);
+      break;
+
     case PROP_PLUGIN_MANAGER:
       g_value_set_object (value, priv->plugin_manager);
       break;
@@ -221,6 +229,20 @@ gtd_manager_class_init (GtdManagerClass *klass)
                              G_PARAM_READWRITE));
 
   /**
+   * GtdManager::timer:
+   *
+   * The underlying timer of GNOME To DO.
+   */
+  g_object_class_install_property (
+        object_class,
+        PROP_TIMER,
+        g_param_spec_object ("timer",
+                             "The timer",
+                             "The timer of the application",
+                             GTD_TYPE_TIMER,
+                             G_PARAM_READABLE));
+
+  /**
    * GtdManager::plugin-manager:
    *
    * The plugin manager.
@@ -551,6 +573,7 @@ gtd_manager_init (GtdManager *self)
   self->priv = gtd_manager_get_instance_private (self);
   self->priv->settings = g_settings_new ("org.gnome.todo");
   self->priv->plugin_manager = gtd_plugin_manager_new ();
+  self->priv->timer = gtd_timer_new ();
 }
 
 /**
@@ -943,6 +966,27 @@ gtd_manager_emit_error_message (GtdManager  *manager,
                            secondary_message);
 }
 
+/**
+ * gtd_manager_get_timer:
+ * @self: a #GtdManager
+ *
+ * Retrieves the #GtdTimer from @self. You can use the
+ * timer to know when your code should be updated.
+ *
+ * Returns: (transfer none): a #GtdTimer
+ */
+GtdTimer*
+gtd_manager_get_timer (GtdManager *self)
+{
+  GtdManagerPrivate *priv;
+
+  g_return_val_if_fail (GTD_IS_MANAGER (self), NULL);
+
+  priv = gtd_manager_get_instance_private (self);
+
+  return priv->timer;
+}
+
 void
 gtd_manager_load_plugins (GtdManager *manager)
 {
diff --git a/src/engine/gtd-manager.h b/src/engine/gtd-manager.h
index 6e7f12e..d9f5bb2 100644
--- a/src/engine/gtd-manager.h
+++ b/src/engine/gtd-manager.h
@@ -82,6 +82,8 @@ void                    gtd_manager_emit_error_message    (GtdManager
                                                            const gchar          *primary_message,
                                                            const gchar          *secondary_message);
 
+GtdTimer*               gtd_manager_get_timer             (GtdManager           *self);
+
 G_END_DECLS
 
 #endif /* GTD_MANAGER_H */
diff --git a/src/gtd-timer.c b/src/gtd-timer.c
new file mode 100644
index 0000000..de936bb
--- /dev/null
+++ b/src/gtd-timer.c
@@ -0,0 +1,232 @@
+/* gtd-timer.c
+ *
+ * Copyright (C) 2017 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtd-timer.h"
+
+#include <gio/gio.h>
+
+struct _GtdTimer
+{
+  GtdObject           parent;
+
+  guint               update_timeout_id;
+
+  GDBusProxy         *logind;
+  GCancellable       *cancellable;
+};
+
+static gboolean      update_for_day_change                       (gpointer           user_data);
+
+G_DEFINE_TYPE (GtdTimer, gtd_timer, GTD_TYPE_OBJECT)
+
+enum
+{
+  UPDATE,
+  N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0, };
+
+/*
+ * Auxiliary methods
+ */
+
+static void
+schedule_update_for_day_change (GtdTimer *self)
+{
+  g_autoptr (GDateTime) now;
+  guint seconds_between;
+
+  /* Remove the previous timeout if we came from resume */
+  if (self->update_timeout_id > 0)
+    {
+      g_source_remove (self->update_timeout_id);
+      self->update_timeout_id = 0;
+    }
+
+  now = g_date_time_new_now_local ();
+
+  seconds_between = (24 - g_date_time_get_hour (now)) * 3600 +
+                    (60 - g_date_time_get_minute (now)) * 60 +
+                    (60 - g_date_time_get_seconds (now));
+
+  self->update_timeout_id = g_timeout_add_seconds (seconds_between,
+                                                   update_for_day_change,
+                                                   self);
+}
+
+/*
+ * Callbacks
+ */
+
+static void
+logind_signal_received_cb (GDBusProxy  *logind,
+                           const gchar *sender,
+                           const gchar *signal,
+                           GVariant    *params,
+                           GtdTimer    *self)
+{
+  GVariant *child;
+  gboolean resuming;
+
+  if (!g_str_equal (signal, "PrepareForSleep"))
+    return;
+
+  child = g_variant_get_child_value (params, 0);
+  resuming = !g_variant_get_boolean (child);
+
+  /* Only emit :update when resuming */
+  if (resuming)
+    {
+      g_signal_emit (self, signals[UPDATE], 0);
+
+      /* Reschedule the daily timeout */
+      schedule_update_for_day_change (self);
+    }
+
+  g_clear_pointer (&child, g_variant_unref);
+}
+
+static void
+login_proxy_acquired_cb (GObject      *source,
+                         GAsyncResult *res,
+                         gpointer      user_data)
+{
+  GtdTimer *self;
+  GError *error;
+
+  self = GTD_TIMER (user_data);
+  error = NULL;
+
+  self->logind = g_dbus_proxy_new_for_bus_finish (res, &error);
+
+  g_signal_connect (self->logind,
+                    "g-signal",
+                    G_CALLBACK (logind_signal_received_cb),
+                    self);
+
+  gtd_object_set_ready (GTD_OBJECT (self), TRUE);
+}
+
+static gboolean
+update_for_day_change (gpointer user_data)
+{
+  GtdTimer *self = user_data;
+
+  /* Remove it first */
+  self->update_timeout_id = 0;
+
+  g_signal_emit (self, signals[UPDATE], 0);
+
+  /*
+   * Because we can't rely on the current timeout,
+   * reschedule it entirely.
+   */
+  schedule_update_for_day_change (self);
+
+  return G_SOURCE_REMOVE;
+}
+
+/*
+ * GObject overrides
+ */
+static void
+gtd_timer_finalize (GObject *object)
+{
+  GtdTimer *self = (GtdTimer *)object;
+
+  g_cancellable_cancel (self->cancellable);
+
+  if (self->update_timeout_id > 0)
+    {
+      g_source_remove (self->update_timeout_id);
+      self->update_timeout_id = 0;
+    }
+
+  g_clear_object (&self->cancellable);
+  g_clear_object (&self->logind);
+
+  G_OBJECT_CLASS (gtd_timer_parent_class)->finalize (object);
+}
+
+static void
+gtd_timer_get_property (GObject    *object,
+                        guint       prop_id,
+                        GValue     *value,
+                        GParamSpec *pspec)
+{
+  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+gtd_timer_set_property (GObject      *object,
+                        guint         prop_id,
+                        const GValue *value,
+                        GParamSpec   *pspec)
+{
+  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+gtd_timer_class_init (GtdTimerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gtd_timer_finalize;
+  object_class->get_property = gtd_timer_get_property;
+  object_class->set_property = gtd_timer_set_property;
+
+  /**
+   * GtdTimer:update:
+   *
+   * Emited when an update is required. This is emited usually
+   * after a session resume, or a day change.
+   */
+  signals[UPDATE] = g_signal_new ("update",
+                                  GTD_TYPE_TIMER,
+                                  G_SIGNAL_RUN_LAST,
+                                  0, NULL, NULL, NULL,
+                                  G_TYPE_NONE,
+                                  0);
+}
+
+static void
+gtd_timer_init (GtdTimer *self)
+{
+  gtd_object_set_ready (GTD_OBJECT (self), FALSE);
+
+  self->cancellable = g_cancellable_new ();
+
+  g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+                            G_DBUS_PROXY_FLAGS_NONE,
+                            NULL,
+                            "org.freedesktop.login1",
+                            "/org/freedesktop/login1",
+                            "org.freedesktop.login1.Manager",
+                            self->cancellable,
+                            login_proxy_acquired_cb,
+                            self);
+
+  schedule_update_for_day_change (self);
+}
+
+GtdTimer*
+gtd_timer_new (void)
+{
+  return g_object_new (GTD_TYPE_TIMER, NULL);
+}
diff --git a/src/gtd-timer.h b/src/gtd-timer.h
new file mode 100644
index 0000000..2eea02b
--- /dev/null
+++ b/src/gtd-timer.h
@@ -0,0 +1,37 @@
+/* gtd-timer.h
+ *
+ * Copyright (C) 2017 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTD_TIMER_H
+#define GTD_TIMER_H
+
+#include "gtd-object.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GTD_TYPE_TIMER (gtd_timer_get_type())
+
+G_DECLARE_FINAL_TYPE (GtdTimer, gtd_timer, GTD, TIMER, GtdObject)
+
+GtdTimer*            gtd_timer_new                               (void);
+
+G_END_DECLS
+
+#endif /* GTD_TIMER_H */
+
diff --git a/src/gtd-types.h b/src/gtd-types.h
index 174f43a..3becbd5 100644
--- a/src/gtd-types.h
+++ b/src/gtd-types.h
@@ -44,6 +44,7 @@ typedef struct _GtdTask                 GtdTask;
 typedef struct _GtdTaskList             GtdTaskList;
 typedef struct _GtdTaskListItem         GtdTaskListItem;
 typedef struct _GtdTaskRow              GtdTaskRow;
+typedef struct _GtdTimer                GtdTimer;
 typedef struct _GtdWindow               GtdWindow;
 
 G_END_DECLS


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