[gnome-todo] background: add a plugin to run To Do on background



commit db4bf1a4f1332340408de9bc1e948c6dfabc8d78
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Thu Apr 20 16:56:02 2017 -0300

    background: add a plugin to run To Do on background
    
    As part of a fluid experience, it's nice to run GNOME
    To Do in background for a few reasons.
    
    First, because it's bad to keep reloading the tasklists
    every time you reopen the app. This ultimately can cause
    our Google keys to reach the daily limits.
    
    Seconds, because now GNOME To Do can load when the session
    starts up, and show a nice notification of how many tasks
    do you have.
    
    Third, because it's cool.

 configure.ac                                       |    3 +
 data/org.gnome.todo.gschema.xml                    |    2 +-
 data/todo.gresource.xml                            |    6 +
 doc/reference/gnome-todo.types                     |   10 -
 plugins/Makefile.am                                |    4 +
 plugins/background/Makefile.am                     |   20 +
 plugins/background/background.plugin.in            |   13 +
 plugins/background/gtd-plugin-background.c         |  507 ++++++++++++++++++++
 plugins/background/gtd-plugin-background.h         |   36 ++
 .../org.gnome.todo.background.gschema.xml          |   15 +
 plugins/background/ui/preferences.ui               |  161 +++++++
 src/Makefile.am                                    |    6 +-
 12 files changed, 770 insertions(+), 13 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index c6d01de..5bd627d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -87,6 +87,8 @@ dnl ================================================================
 dnl Plugins
 dnl ================================================================
 GNOME_TODO_ADD_PLUGIN([eds], [Evolution-Data-Server], [yes])
+
+GNOME_TODO_ADD_PLUGIN([background], [Run In Background], [yes])
 GNOME_TODO_ADD_PLUGIN([dark-theme], [Dark theme], [yes])
 GNOME_TODO_ADD_PLUGIN([scheduled-panel], [Scheduled Panel], [yes])
 GNOME_TODO_ADD_PLUGIN([score], [Score], [yes])
@@ -137,6 +139,7 @@ echo "
 
     Plugins:
         Dark theme .............. ${enable_dark_theme_plugin}
+        Run in Background ....... ${enable_background_plugin}
         Scheduled panel ......... ${enable_scheduled_panel_plugin}
         Score ................... ${enable_score_plugin}
         Today panel ............. ${enable_today_panel_plugin}
diff --git a/data/org.gnome.todo.gschema.xml b/data/org.gnome.todo.gschema.xml
index 7e59be8..6fb5fe9 100644
--- a/data/org.gnome.todo.gschema.xml
+++ b/data/org.gnome.todo.gschema.xml
@@ -27,7 +27,7 @@
             <description>The identifier of the default provider to add new lists to</description>
         </key>
         <key name="active-extensions" type="as">
-            <default>["eds", "today-panel", "scheduled-panel"]</default>
+            <default>["background", "eds", "today-panel", "scheduled-panel"]</default>
             <summary>List of active extensions</summary>
             <description>The list of active extensions</description>
         </key>
diff --git a/data/todo.gresource.xml b/data/todo.gresource.xml
index 1052a9d..2a3b699 100644
--- a/data/todo.gresource.xml
+++ b/data/todo.gresource.xml
@@ -22,6 +22,12 @@
     <file compressed="true">theme/Adwaita.css</file>
   </gresource>
 
+  <!--Background-->
+  <gresource prefix="/org/gnome/todo">
+    <file alias="plugins/background/background.plugin">../plugins/background/background.plugin</file>
+    <file compressed="true" 
alias="ui/background/preferences.ui">../plugins/background/ui/preferences.ui</file>
+  </gresource>
+
   <!--Dark theme-->
   <gresource prefix="/org/gnome/todo">
     <file alias="plugins/dark-theme/dark-theme.plugin">../plugins/dark-theme/dark-theme.plugin</file>
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index e6afbd0..67184f5 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -1,5 +1,9 @@
 SUBDIRS = eds
 
+if BUILD_BACKGROUND_PLUGIN
+SUBDIRS += background
+endif
+
 if BUILD_DARK_THEME_PLUGIN
 SUBDIRS += dark-theme
 endif
diff --git a/plugins/background/Makefile.am b/plugins/background/Makefile.am
new file mode 100644
index 0000000..e05d33c
--- /dev/null
+++ b/plugins/background/Makefile.am
@@ -0,0 +1,20 @@
+gsettings_SCHEMAS = org.gnome.todo.background.gschema.xml
+
+@GSETTINGS_RULES@
+
+include $(top_srcdir)/common.am
+
+noinst_LTLIBRARIES = libbackground.la
+
+libbackground_la_SOURCES = \
+       gtd-plugin-background.c \
+       gtd-plugin-background.h
+
+libbackground_la_CFLAGS = \
+       $(GNOME_TODO_PLUGIN_CFLAGS) \
+       $(GNOME_TODO_PLUGIN_WARN_CFLAGS) \
+       -DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\"
+
+EXTRA_DIST = \
+       $(gsettings_SCHEMAS) \
+       background.plugin.in
diff --git a/plugins/background/background.plugin.in b/plugins/background/background.plugin.in
new file mode 100644
index 0000000..3aaebdb
--- /dev/null
+++ b/plugins/background/background.plugin.in
@@ -0,0 +1,13 @@
+[Plugin]
+Name = Run in background
+Module = background
+Description = Let GNOME To Do run in background and send notifications
+Version = @VERSION@
+Authors = Georges Basile Stavracas Neto <gbsneto gnome org>
+Copyright = Copyleft © The To Do maintainers
+Website = https://wiki.gnome.org/Apps/Todo
+Builtin = true
+License = GPL
+Loader = C
+Embedded = gtd_plugin_background_register_types
+Depends =
diff --git a/plugins/background/gtd-plugin-background.c b/plugins/background/gtd-plugin-background.c
new file mode 100644
index 0000000..703b6ca
--- /dev/null
+++ b/plugins/background/gtd-plugin-background.c
@@ -0,0 +1,507 @@
+/* gtd-plugin-background.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 "config.h"
+
+#include "gtd-plugin-background.h"
+
+#include <glib/gi18n.h>
+
+#define AUTOSTART_FILE                 "org.gnome.Todo.Autostart.desktop"
+#define AUTOSTART_NOTIFICATION_ID      "Gtd::BackgroundPlugin::autostart_notification"
+#define AUTOSTART_NOTIFICATION_TIMEOUT 3  /* seconds */
+#define MAX_BODY_LENGTH                50 /* chars */
+
+struct _GtdPluginBackground
+{
+  PeasExtensionBase   parent;
+
+  GtkWidget          *preferences_panel;
+
+  GSettings          *settings;
+  gboolean            startup_notification : 1;
+  gboolean            show_notifications : 1;
+
+  guint               startup_notification_timeout_id;
+};
+
+static void          on_tasklist_notified                        (GtdPluginBackground      *self);
+
+static void          gtd_activatable_iface_init                  (GtdActivatableInterface  *iface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GtdPluginBackground, gtd_plugin_background, PEAS_TYPE_EXTENSION_BASE,
+                                0,
+                                G_IMPLEMENT_INTERFACE_DYNAMIC (GTD_TYPE_ACTIVATABLE,
+                                                               gtd_activatable_iface_init))
+
+enum {
+  PROP_0,
+  PROP_PREFERENCES_PANEL,
+  N_PROPS
+};
+
+/*
+ * Auxiliary methods
+ */
+static inline GtdWindow*
+get_window (void)
+{
+  GtkApplication *app = GTK_APPLICATION (g_application_get_default ());
+
+  return GTD_WINDOW (gtk_application_get_active_window (app));
+}
+
+static void
+set_autostart_enabled (GtdPluginBackground *self,
+                       gboolean             enabled)
+{
+  g_autoptr (GFile) file;
+  g_autofree gchar *autostart_file_path;
+  g_autofree gchar *user_autostart_file;
+
+  autostart_file_path = g_build_filename (PACKAGE_DATA_DIR, AUTOSTART_FILE, NULL);
+  user_autostart_file = g_build_filename (g_get_user_config_dir (), "autostart", AUTOSTART_FILE, NULL);
+  file = g_file_new_for_path (user_autostart_file);
+
+  /*
+   * Create a symbolic link to the autostart file if enabled,
+   * otherwise remove the symbolic link.
+   */
+  if (enabled)
+    {
+      g_autoptr (GFile) parent = NULL;
+
+      /* Nothing to do if the file already exists */
+      if (g_file_query_exists (file, NULL))
+        return;
+
+      /* Ensure the autostart directory first */
+      parent = g_file_get_parent (file);
+      g_file_make_directory_with_parents (parent, NULL, NULL);
+
+      /* Symlink the Autostart.desktop file */
+      g_file_make_symbolic_link (file, autostart_file_path, NULL, NULL);
+    }
+  else
+    {
+      /* Remove the startup file */
+      g_file_delete (file, NULL, NULL);
+    }
+}
+
+static gchar*
+format_notification_body (GList *tasks,
+                          guint  n_tasks)
+{
+  GString *string, *aux;
+  GList *l;
+  guint current_task, length;
+
+  aux = g_string_new ("");
+  string = g_string_new ("");
+  current_task = length = 0;
+
+  for (l = tasks; l != NULL; l = l->next)
+    {
+      GtdTask *task = l->data;
+
+      length += g_utf8_strlen (gtd_task_get_title (task), -1);
+
+      if (length > MAX_BODY_LENGTH)
+        break;
+
+      if (current_task > 0)
+        g_string_append (aux, ", ");
+
+      g_string_append (aux, gtd_task_get_title (task));
+      current_task++;
+    }
+
+  if (current_task == 0)
+    {
+      /* The first task has a huge title. Let's ellipsize it */
+      g_string_append (string, gtd_task_get_title (tasks->data));
+      g_string_truncate (string, MAX_BODY_LENGTH - 1);
+      g_string_append (string, "…");
+    }
+  else if (current_task < n_tasks)
+    {
+      /* Some tasks fit, but we need to append a text explaining there are more */
+      g_string_append_printf (string,
+                              g_dngettext (GETTEXT_PACKAGE,
+                                           "%1$s and one more task",
+                                           "%1$s and %2$d other tasks",
+                                           n_tasks - current_task),
+                              aux->str,
+                              n_tasks - current_task);
+    }
+  else
+    {
+      /* Nothing to do, we were able to print all titles */
+    }
+
+  g_string_free (aux, TRUE);
+
+  return g_string_free (string, FALSE);
+}
+
+static inline gboolean
+is_today (GDateTime *now,
+          GDateTime *dt)
+{
+  return g_date_time_get_year (dt) == g_date_time_get_year (now) &&
+         g_date_time_get_month (dt) == g_date_time_get_month (now) &&
+         g_date_time_get_day_of_month (dt) == g_date_time_get_day_of_month (now);
+}
+
+static GList*
+get_tasks_for_today (guint *n_events)
+{
+  g_autoptr (GDateTime) now;
+  GtdManager *manager;
+  GList *task_lists, *l;
+  GList *result;
+  guint n_tasks;
+
+  now = g_date_time_new_now_local ();
+  result = NULL;
+  n_tasks = 0;
+  manager = gtd_manager_get_default ();
+  task_lists = gtd_manager_get_task_lists (manager);
+
+  for (l = task_lists; l != NULL; l = l->next)
+    {
+      GList *tasks, *t;
+
+      tasks = gtd_task_list_get_tasks (l->data);
+
+      for (t = tasks; t != NULL; t = t->next)
+        {
+          GDateTime *due_date;
+
+          due_date = gtd_task_get_due_date (t->data);
+
+          if (!due_date || !is_today (now, due_date))
+            continue;
+
+
+          n_tasks += 1;
+          result = g_list_prepend (result, t->data);
+        }
+    }
+
+  if (n_events)
+    *n_events = n_tasks;
+
+  return result;
+}
+
+/*
+ * Callbacks
+ */
+static void
+on_startup_changed (GSettings           *settings,
+                    const gchar         *key,
+                    GtdPluginBackground *self)
+{
+  set_autostart_enabled (self, g_settings_get_boolean (settings, key));
+}
+
+static gboolean
+on_startup_timeout_cb (GtdPluginBackground *self)
+{
+  GNotification *notification;
+  GApplication *app;
+  GtdWindow *window;
+  GList *tasks;
+  gchar *title;
+  gchar *body;
+  guint n_tasks;
+
+  window = get_window ();
+
+  /*
+   * If the user already focused To Do's window, we don't have to
+   * notify about the number of tasks.
+   */
+  if (gtk_window_is_active (GTK_WINDOW (window)))
+    goto out;
+
+  /* The user don't want to be bothered with notifications */
+  if (!g_settings_get_boolean (self->settings, "show-notifications"))
+    goto out;
+
+  app = g_application_get_default ();
+  tasks = get_tasks_for_today (&n_tasks);
+
+  if (n_tasks == 0)
+    goto out;
+
+  title = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE,
+                                        "You have %d task for today",
+                                        "You have %d tasks for today",
+                                        n_tasks),
+                           n_tasks);
+
+  body = format_notification_body (tasks, n_tasks);
+
+  /* Build up the notification */
+  notification = g_notification_new (title);
+  g_notification_set_body (notification, body);
+  g_notification_set_default_action (notification, "app.activate");
+
+  g_application_send_notification (app, AUTOSTART_NOTIFICATION_ID, notification);
+
+  g_clear_pointer (&tasks, g_list_free);
+  g_clear_object (&notification);
+
+out:
+  self->startup_notification_timeout_id = 0;
+
+  g_signal_handlers_disconnect_by_func (gtd_manager_get_default (),
+                                        on_tasklist_notified,
+                                        self);
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+on_tasklist_notified (GtdPluginBackground *self)
+{
+  /* Remove previously set timeout */
+  if (self->startup_notification_timeout_id > 0)
+    {
+      g_source_remove (self->startup_notification_timeout_id);
+      self->startup_notification_timeout_id = 0;
+    }
+
+  self->startup_notification_timeout_id = g_timeout_add_seconds (AUTOSTART_NOTIFICATION_TIMEOUT,
+                                                                 (GSourceFunc) on_startup_timeout_cb,
+                                                                 self);
+}
+
+static void
+watch_manager_for_new_lists (GtdPluginBackground *self)
+{
+  GtdManager *manager = gtd_manager_get_default ();
+
+  g_signal_connect_swapped (manager,
+                            "list-added",
+                            G_CALLBACK (on_tasklist_notified),
+                            self);
+
+  g_signal_connect_swapped (manager,
+                            "list-changed",
+                            G_CALLBACK (on_tasklist_notified),
+                            self);
+
+  g_signal_connect_swapped (manager,
+                            "list-removed",
+                            G_CALLBACK (on_tasklist_notified),
+                            self);
+}
+
+/*
+ * GtdActivatable interface implementation
+ */
+static void
+gtd_plugin_background_activate (GtdActivatable *activatable)
+{
+  GtdPluginBackground *self;
+  GtdWindow *window;
+
+  self = GTD_PLUGIN_BACKGROUND (activatable);
+  window = get_window ();
+
+  g_signal_connect (window,
+                    "delete-event",
+                    G_CALLBACK (gtk_widget_hide_on_delete),
+                    window);
+
+  on_startup_changed (self->settings, "run-on-startup", self);
+  g_signal_connect (self->settings,
+                    "changed::run-on-startup",
+                    G_CALLBACK (on_startup_changed),
+                    self);
+
+  /* Start watching the manager to notify the user about today's tasks */
+  watch_manager_for_new_lists (self);
+}
+
+static void
+gtd_plugin_background_deactivate (GtdActivatable *activatable)
+{
+  GtdPluginBackground *self;
+  GtdManager *manager;
+  GtdWindow *window;
+
+  self = GTD_PLUGIN_BACKGROUND (activatable);
+  manager = gtd_manager_get_default ();
+  window = get_window ();
+
+  g_signal_handlers_disconnect_by_func (window,
+                                        gtk_widget_hide_on_delete,
+                                        window);
+
+  g_signal_handlers_disconnect_by_func (self->settings,
+                                        on_startup_changed,
+                                        self);
+
+  g_signal_handlers_disconnect_by_func (manager,
+                                        on_tasklist_notified,
+                                        self);
+
+  /* Deactivate the timeout */
+  if (self->startup_notification_timeout_id > 0)
+    {
+      g_source_remove (self->startup_notification_timeout_id);
+      self->startup_notification_timeout_id = 0;
+    }
+
+  /* Deactivate auto startup */
+  set_autostart_enabled (self, FALSE);
+}
+
+static GList*
+gtd_plugin_background_get_header_widgets (GtdActivatable *activatable)
+{
+  return NULL;
+}
+
+static GtkWidget*
+gtd_plugin_background_get_preferences_panel (GtdActivatable *activatable)
+{
+  GtdPluginBackground *self = GTD_PLUGIN_BACKGROUND (activatable);
+
+  return self->preferences_panel;
+}
+
+static GList*
+gtd_plugin_background_get_panels (GtdActivatable *activatable)
+{
+  return NULL;
+}
+
+static GList*
+gtd_plugin_background_get_providers (GtdActivatable *activatable)
+{
+  return NULL;
+}
+
+static void
+gtd_activatable_iface_init (GtdActivatableInterface *iface)
+{
+  iface->activate = gtd_plugin_background_activate;
+  iface->deactivate = gtd_plugin_background_deactivate;
+  iface->get_header_widgets = gtd_plugin_background_get_header_widgets;
+  iface->get_preferences_panel = gtd_plugin_background_get_preferences_panel;
+  iface->get_panels = gtd_plugin_background_get_panels;
+  iface->get_providers = gtd_plugin_background_get_providers;
+}
+
+static void
+gtd_plugin_background_finalize (GObject *object)
+{
+  GtdPluginBackground *self = (GtdPluginBackground *)object;
+
+  g_clear_object (&self->settings);
+
+  G_OBJECT_CLASS (gtd_plugin_background_parent_class)->finalize (object);
+}
+
+static void
+gtd_plugin_background_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GtdPluginBackground *self = GTD_PLUGIN_BACKGROUND (object);
+
+  switch (prop_id)
+    {
+    case PROP_PREFERENCES_PANEL:
+      g_value_set_object (value, self->preferences_panel);
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gtd_plugin_background_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_plugin_background_class_init (GtdPluginBackgroundClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gtd_plugin_background_finalize;
+  object_class->get_property = gtd_plugin_background_get_property;
+  object_class->set_property = gtd_plugin_background_set_property;
+
+  g_object_class_override_property (object_class,
+                                    PROP_PREFERENCES_PANEL,
+                                    "preferences-panel");
+}
+
+static void
+gtd_plugin_background_init (GtdPluginBackground *self)
+{
+  GtkBuilder *builder;
+
+  /* Load the settings */
+  self->settings = g_settings_new ("org.gnome.todo.plugins.background");
+
+  /* And the preferences panel */
+  builder = gtk_builder_new_from_resource ("/org/gnome/todo/ui/background/preferences.ui");
+
+  self->preferences_panel = GTK_WIDGET (gtk_builder_get_object (builder, "main_frame"));
+
+  g_settings_bind (self->settings,
+                   "run-on-startup",
+                   gtk_builder_get_object (builder, "startup_switch"),
+                   "active",
+                   G_SETTINGS_BIND_DEFAULT);
+
+  g_settings_bind (self->settings,
+                   "show-notifications",
+                   gtk_builder_get_object (builder, "notifications_switch"),
+                   "active",
+                   G_SETTINGS_BIND_DEFAULT);
+}
+
+static void
+gtd_plugin_background_class_finalize (GtdPluginBackgroundClass *klass)
+{
+}
+
+G_MODULE_EXPORT void
+gtd_plugin_background_register_types (PeasObjectModule *module)
+{
+  gtd_plugin_background_register_type (G_TYPE_MODULE (module));
+
+  peas_object_module_register_extension_type (module,
+                                              GTD_TYPE_ACTIVATABLE,
+                                              GTD_TYPE_PLUGIN_BACKGROUND);
+}
diff --git a/plugins/background/gtd-plugin-background.h b/plugins/background/gtd-plugin-background.h
new file mode 100644
index 0000000..30402af
--- /dev/null
+++ b/plugins/background/gtd-plugin-background.h
@@ -0,0 +1,36 @@
+/* gtd-plugin-background.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_PLUGIN_BACKGROUND_H
+#define GTD_PLUGIN_BACKGROUND_H
+
+#include <glib.h>
+#include <gnome-todo.h>
+
+G_BEGIN_DECLS
+
+#define GTD_TYPE_PLUGIN_BACKGROUND (gtd_plugin_background_get_type())
+
+G_DECLARE_FINAL_TYPE (GtdPluginBackground, gtd_plugin_background, GTD, PLUGIN_BACKGROUND, PeasExtensionBase)
+
+G_MODULE_EXPORT void gtd_plugin_background_register_types        (PeasObjectModule   *module);
+
+G_END_DECLS
+
+#endif /* GTD_PLUGIN_BACKGROUND_H */
+
diff --git a/plugins/background/org.gnome.todo.background.gschema.xml 
b/plugins/background/org.gnome.todo.background.gschema.xml
new file mode 100644
index 0000000..5adf4bd
--- /dev/null
+++ b/plugins/background/org.gnome.todo.background.gschema.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schemalist gettext-domain="gnome-todo">
+    <schema id="org.gnome.todo.plugins.background" path="/org/gnome/todo/plugins/background/">
+        <key name="run-on-startup" type="b">
+            <default>false</default>
+            <summary>Run To Do on startup</summary>
+            <description>Whether GNOME To Do should run on startup</description>
+        </key>
+        <key name="show-notifications" type="b">
+            <default>true</default>
+            <summary>Show notifications on startup</summary>
+            <description>Whether GNOME To Do should show notifications or not</description>
+        </key>
+    </schema>
+</schemalist>
diff --git a/plugins/background/ui/preferences.ui b/plugins/background/ui/preferences.ui
new file mode 100644
index 0000000..20652a8
--- /dev/null
+++ b/plugins/background/ui/preferences.ui
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkFrame" id="main_frame">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="label_xalign">0</property>
+    <property name="shadow_type">none</property>
+    <child>
+      <object class="GtkFrame">
+        <property name="width_request">400</property>
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="halign">center</property>
+        <property name="valign">center</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+        <property name="label_xalign">0</property>
+        <child>
+          <object class="GtkListBox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <property name="selection-mode">none</property>
+            <child>
+              <object class="GtkListBoxRow">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">12</property>
+                    <property name="column_spacing">18</property>
+                    <child>
+                      <object class="GtkSwitch" id="startup_switch">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="valign">center</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">0</property>
+                        <property name="height">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="label" translatable="yes">Run on startup</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="label" translatable="yes">Run To Do Automatically when you log 
in</property>
+                        <property name="xalign">0</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkListBoxRow">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="activatable">False</property>
+                <property name="selectable">False</property>
+                <child>
+                  <object class="GtkSeparator">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkListBoxRow">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="border_width">12</property>
+                    <property name="column_spacing">18</property>
+                    <child>
+                      <object class="GtkSwitch" id="notifications_switch">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="valign">center</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">0</property>
+                        <property name="height">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="label" translatable="yes">Show Notifications</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="label" translatable="yes">When To Do runs, show a startup 
notification</property>
+                        <property name="xalign">0</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child type="label_item">
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+    <child type="label_item">
+      <placeholder/>
+    </child>
+  </object>
+</interface>
diff --git a/src/Makefile.am b/src/Makefile.am
index 703597d..c7be054 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -98,20 +98,22 @@ gnome_todo_CFLAGS = \
 
 gnome_todo_LDFLAGS = \
        -Wl,--export-dynamic \
+       -Wl,--undefined=gtd_plugin_background_register_types \
        -Wl,--undefined=gtd_plugin_eds_register_types \
        -Wl,--undefined=gtd_plugin_dark_theme_register_types \
        -Wl,--undefined=gtd_plugin_scheduled_panel_register_types \
        -Wl,--undefined=gtd_plugin_today_panel_register_types \
-        -Wl,--undefined=gtd_plugin_todo_txt_register_types \
+       -Wl,--undefined=gtd_plugin_todo_txt_register_types \
        -lm \
        $(GNOME_TODO_WARN_LDFLAGS)
 
 gnome_todo_LDADD = \
+       $(top_builddir)/plugins/background/libbackground.la \
        $(top_builddir)/plugins/eds/libeds.la \
        $(top_builddir)/plugins/dark-theme/libdarktheme.la \
        $(top_builddir)/plugins/scheduled-panel/libscheduledpanel.la \
        $(top_builddir)/plugins/today-panel/libtodaypanel.la \
-        $(top_builddir)/plugins/todo-txt/libtodotxt.la \
+       $(top_builddir)/plugins/todo-txt/libtodotxt.la \
        $(GNOME_TODO_LIBS)
 
 gnome_todo_DEPENDENCIES = \


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