[gnome-shell/155-move-functionality-from-evolution-alarm-notify-to-gnome-shell-calendar-server: 1996/1997] calendar-server: Add a ReminderWatcher




commit ceadfd3a252f38514af17fd5eab2ee54a3bd3bb0
Author: Milan Crha <mcrha redhat com>
Date:   Mon Nov 29 15:55:56 2021 +0100

    calendar-server: Add a ReminderWatcher
    
    This is to show even reminders within the shell itself.
    
    Related to https://gitlab.gnome.org/GNOME/gnome-shell/issues/155

 po/POTFILES.in                                    |   1 +
 src/calendar-server/gnome-shell-calendar-server.c |   6 +
 src/calendar-server/meson.build                   |   4 +-
 src/calendar-server/reminder-watcher.c            | 706 ++++++++++++++++++++++
 src/calendar-server/reminder-watcher.h            |  65 ++
 5 files changed, 781 insertions(+), 1 deletion(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6340bff17a..d5ad4af2c7 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -76,6 +76,7 @@ js/ui/windowAttentionHandler.js
 js/ui/windowManager.js
 js/ui/windowMenu.js
 src/calendar-server/evolution-calendar.desktop.in
+src/calendar-server/reminder-watcher.c
 src/main.c
 src/shell-app.c
 src/shell-app-system.c
diff --git a/src/calendar-server/gnome-shell-calendar-server.c 
b/src/calendar-server/gnome-shell-calendar-server.c
index 71a08faae3..0b1d8240d1 100644
--- a/src/calendar-server/gnome-shell-calendar-server.c
+++ b/src/calendar-server/gnome-shell-calendar-server.c
@@ -40,6 +40,7 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
 G_GNUC_END_IGNORE_DEPRECATIONS
 
 #include "calendar-sources.h"
+#include "reminder-watcher.h"
 
 #define BUS_NAME "org.gnome.Shell.CalendarServer"
 
@@ -318,6 +319,8 @@ struct _App
   gulong client_appeared_signal_id;
   gulong client_disappeared_signal_id;
 
+  EReminderWatcher *reminder_watcher;
+
   gchar *timezone_location;
 
   GSList *notify_appointments; /* CalendarAppointment *, for EventsAdded */
@@ -341,6 +344,7 @@ app_update_timezone (App *app)
       g_free (app->timezone_location);
       app->timezone_location = g_steal_pointer (&location);
       print_debug ("Using timezone %s", app->timezone_location);
+      e_reminder_watcher_set_default_zone (app->reminder_watcher, app->zone);
     }
 }
 
@@ -791,6 +795,7 @@ app_new (GApplication *application,
   app = g_new0 (App, 1);
   app->connection = g_object_ref (connection);
   app->sources = calendar_sources_get ();
+  app->reminder_watcher = reminder_watcher_new (application, calendar_sources_get_registry (app->sources));
   app->client_appeared_signal_id = g_signal_connect (app->sources,
                                                      "client-appeared",
                                                      G_CALLBACK (on_client_appeared_cb),
@@ -829,6 +834,7 @@ app_free (App *app)
   g_slist_free_full (app->notify_ids, g_free);
 
   g_object_unref (app->connection);
+  g_object_unref (app->reminder_watcher);
   g_object_unref (app->sources);
 
   g_free (app);
diff --git a/src/calendar-server/meson.build b/src/calendar-server/meson.build
index 7363282a59..ff3bb75352 100644
--- a/src/calendar-server/meson.build
+++ b/src/calendar-server/meson.build
@@ -2,7 +2,9 @@ calendar_sources = [
   'gnome-shell-calendar-server.c',
   'calendar-debug.h',
   'calendar-sources.c',
-  'calendar-sources.h'
+  'calendar-sources.h',
+  'reminder-watcher.c',
+  'reminder-watcher.h'
 ]
 
 calendar_server = executable('gnome-shell-calendar-server', calendar_sources,
diff --git a/src/calendar-server/reminder-watcher.c b/src/calendar-server/reminder-watcher.c
new file mode 100644
index 0000000000..9e20617205
--- /dev/null
+++ b/src/calendar-server/reminder-watcher.c
@@ -0,0 +1,706 @@
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.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 2 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 <glib/gi18n-lib.h>
+
+#define HANDLE_LIBICAL_MEMORY
+#define EDS_DISABLE_DEPRECATED
+#include <libecal/libecal.h>
+
+#include "calendar-sources.h"
+#include "reminder-watcher.h"
+
+struct _ReminderWatcherPrivate {
+  GApplication *application; /* not referenced */
+  CalendarSources *sources;
+  GSettings *settings;
+
+  GMutex dismiss_lock;
+  GSList *dismiss; /* EReminderData * */
+  GThread *dismiss_thread; /* not referenced, only to know whether it's scheduled */
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (ReminderWatcher, reminder_watcher, E_TYPE_REMINDER_WATCHER)
+
+static const gchar *
+reminder_watcher_get_rd_summary (const EReminderData *rd)
+{
+  if (!rd)
+    return NULL;
+
+  return i_cal_component_get_summary (e_cal_component_get_icalcomponent (e_reminder_data_get_component 
(rd)));
+}
+
+static gboolean
+reminder_watcher_notify_audio (ReminderWatcher *rw,
+                               const EReminderData *rd,
+                               ECalComponentAlarm *alarm)
+{
+#if 0
+  ICalAttach *attach = NULL;
+  GSList *attachments;
+  gboolean did_play = FALSE;
+
+  g_return_val_if_fail (rw != NULL, FALSE);
+  g_return_val_if_fail (rd != NULL, FALSE);
+  g_return_val_if_fail (alarm != NULL, FALSE);
+
+  attachments = e_cal_component_alarm_get_attachments (alarm);
+  if (attachments && !attachments->next)
+    attach = attachments->data;
+
+  if (attach && i_cal_attach_get_is_url (attach))
+    {
+      const gchar *url;
+
+      url = i_cal_attach_get_url (attach);
+      if (url && *url)
+        {
+          gchar *filename;
+          GError *error = NULL;
+
+          filename = g_filename_from_uri (url, NULL, &error);
+
+          if (!filename)
+            ean_debug_print ("Audio notify: Failed to convert URI '%s' to filename: %s\n", url, error ? 
error->message : "Unknown error");
+           else if (g_file_test (filename, G_FILE_TEST_EXISTS))
+            {
+#ifdef HAVE_CANBERRA
+              gint err = ca_context_play (ca_gtk_context_get (), 0,
+                                          CA_PROP_MEDIA_FILENAME, filename,
+                                          NULL);
+
+              did_play = !err;
+
+              if (err)
+                ean_debug_print ("Audio notify: Cannot play file '%s': %s\n", filename, ca_strerror (err));
+#else
+                ean_debug_print ("Audio notify: Cannot play file '%s': Not compiled with libcanberra\n", 
filename);
+#endif
+            }
+           else
+            ean_debug_print ("Audio notify: File '%s' does not exist\n", filename);
+
+          g_clear_error (&error);
+          g_free (filename);
+        }
+       else
+        ean_debug_print ("Audio notify: Alarm has stored empty URL, fallback to default sound\n");
+    }
+   else if (!attach)
+    ean_debug_print ("Audio notify: Alarm has no attachment, fallback to default sound\n");
+   else
+    ean_debug_print ("Audio notify: Alarm attachment is not a URL to sound file, fallback to default 
sound\n");
+
+#ifdef HAVE_CANBERRA
+  if (!did_play)
+    {
+      gint err = ca_context_play (ca_gtk_context_get (), 0,
+                                  CA_PROP_EVENT_ID, "alarm-clock-elapsed",
+                                  NULL);
+
+      did_play = !err;
+
+      if (err)
+        ean_debug_print ("Audio notify: Cannot play event sound: %s\n", ca_strerror (err));
+    }
+#endif
+
+  if (!did_play)
+    {
+      GdkDisplay *display;
+
+      display = rw->priv->window ? gtk_widget_get_display (rw->priv->window) : NULL;
+
+      if (!display)
+        display = gdk_display_get_default ();
+
+      if (display)
+        gdk_display_beep (display);
+      else
+        ean_debug_print ("Audio notify: Cannot beep, no display found\n");
+    }
+#endif
+
+  print_debug ("ReminderWatcher::Notify Audio for '%s'", reminder_watcher_get_rd_summary (rd));
+
+  return FALSE;
+}
+
+static gchar *
+reminder_watcher_build_notif_id (const EReminderData *rd)
+{
+  GString *string;
+  ECalComponentId *id;
+  ECalComponentAlarmInstance *instance;
+
+  g_return_val_if_fail (rd != NULL, NULL);
+
+  string = g_string_sized_new (32);
+
+  if (e_reminder_data_get_source_uid (rd))
+    {
+      g_string_append (string, e_reminder_data_get_source_uid (rd));
+      g_string_append_c (string, '\n');
+    }
+
+  id = e_cal_component_get_id (e_reminder_data_get_component (rd));
+  if (id)
+    {
+      if (e_cal_component_id_get_uid (id))
+        {
+          g_string_append (string, e_cal_component_id_get_uid (id));
+          g_string_append_c (string, '\n');
+        }
+
+      if (e_cal_component_id_get_rid (id))
+        {
+          g_string_append (string, e_cal_component_id_get_rid (id));
+          g_string_append_c (string, '\n');
+        }
+
+      e_cal_component_id_free (id);
+    }
+
+  instance = e_reminder_data_get_instance (rd);
+
+  g_string_append_printf (string, "%" G_GINT64_FORMAT, (gint64) (instance ? 
e_cal_component_alarm_instance_get_time (instance) : -1));
+
+  return g_string_free (string, FALSE);
+}
+
+static gboolean
+reminder_watcher_notify_display (ReminderWatcher *rw,
+                                 const EReminderData *rd,
+                                 ECalComponentAlarm *alarm)
+{
+  GNotification *notification;
+#if 0
+  GtkIconInfo *icon_info;
+#endif
+  gchar *description, *notif_id;
+
+  g_return_val_if_fail (rw != NULL, FALSE);
+  g_return_val_if_fail (rd != NULL, FALSE);
+  g_return_val_if_fail (alarm != NULL, FALSE);
+
+  notif_id = reminder_watcher_build_notif_id (rd);
+  description = e_reminder_watcher_describe_data (E_REMINDER_WATCHER (rw), rd, 
E_REMINDER_WATCHER_DESCRIBE_FLAG_NONE);
+
+  notification = g_notification_new (_("Reminders"));
+  g_notification_set_body (notification, description);
+
+#if 0
+  icon_info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_default (), "appointment-soon", 
GTK_ICON_SIZE_DIALOG, 0);
+  if (icon_info)
+    {
+      const gchar *filename;
+
+      filename = gtk_icon_info_get_filename (icon_info);
+      if (filename && *filename)
+        {
+          GFile *file;
+          GIcon *icon;
+
+          file = g_file_new_for_path (filename);
+          icon = g_file_icon_new (file);
+
+          if (icon)
+            {
+              g_notification_set_icon (notification, icon);
+              g_object_unref (icon);
+            }
+
+          g_object_unref (file);
+        }
+
+      gtk_icon_info_free (icon_info);
+    }
+#endif
+
+  g_application_send_notification (rw->priv->application, notif_id, notification);
+
+  g_object_unref (notification);
+  g_free (description);
+  g_free (notif_id);
+
+  print_debug ("ReminderWatcher::Notify Display for '%s'", reminder_watcher_get_rd_summary (rd));
+
+  return TRUE;
+}
+
+static gboolean
+reminder_watcher_notify_email (ReminderWatcher *rw,
+                               const EReminderData *rd,
+                               ECalComponentAlarm *alarm)
+{
+  print_debug ("ReminderWatcher::Notify Email for '%s'", reminder_watcher_get_rd_summary (rd));
+
+  /* Nothing to do here */
+  return FALSE;
+}
+
+static gboolean
+reminder_watcher_is_blessed_program (GSettings *settings,
+                                     const gchar *url)
+{
+  gchar **list;
+  gint ii;
+  gboolean found = FALSE;
+
+  g_return_val_if_fail (G_IS_SETTINGS (settings), FALSE);
+  g_return_val_if_fail (url != NULL, FALSE);
+
+  list = g_settings_get_strv (settings, "notify-programs");
+
+  for (ii = 0; list && list[ii] && !found; ii++)
+    {
+      found = g_strcmp0 (list[ii], url) == 0;
+    }
+
+  g_strfreev (list);
+
+  return found;
+}
+
+#if 0
+static void
+reminder_watcher_save_blessed_program (GSettings *settings,
+                                       const gchar *url)
+{
+  gchar **list;
+  gint ii;
+  GPtrArray *array;
+
+  g_return_if_fail (G_IS_SETTINGS (settings));
+  g_return_if_fail (url != NULL);
+
+  array = g_ptr_array_new ();
+
+  list = g_settings_get_strv (settings, "notify-programs");
+
+  for (ii = 0; list && list[ii]; ii++)
+    {
+      if (g_strcmp0 (url, list[ii]) != 0)
+        g_ptr_array_add (array, list[ii]);
+    }
+
+  g_ptr_array_add (array, (gpointer) url);
+  g_ptr_array_add (array, NULL);
+
+  g_settings_set_strv (settings, "notify-programs", (const gchar * const *) array->pdata);
+
+  g_ptr_array_free (array, TRUE);
+  g_strfreev (list);
+}
+#endif
+
+static gboolean
+reminder_watcher_can_procedure (ReminderWatcher *rw,
+                                const gchar *cmd,
+                                const gchar *url)
+{
+#if 0
+  GtkWidget *container;
+  GtkWidget *dialog;
+  GtkWidget *label;
+  GtkWidget *checkbox;
+  gchar *str;
+  gint response;
+#endif
+
+  if (reminder_watcher_is_blessed_program (rw->priv->settings, url))
+    return TRUE;
+
+#if 0
+  dialog = gtk_dialog_new_with_buttons (
+    _("Warning"), GTK_WINDOW (rw->priv->window), 0,
+    _("_No"), GTK_RESPONSE_CANCEL,
+    _("_Yes"), GTK_RESPONSE_OK,
+    NULL);
+
+  str = g_strdup_printf (
+    _("A calendar reminder is about to trigger. "
+      "This reminder is configured to run the following program:\n\n"
+      "        %s\n\n"
+      "Are you sure you want to run this program?"),
+    cmd);
+  label = gtk_label_new (str);
+  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+  gtk_widget_show (label);
+
+  container = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+  gtk_box_pack_start (GTK_BOX (container), label, TRUE, TRUE, 4);
+  g_free (str);
+
+  checkbox = gtk_check_button_new_with_label (_("Do not ask me about this program again"));
+  gtk_widget_show (checkbox);
+  gtk_box_pack_start (GTK_BOX (container), checkbox, TRUE, TRUE, 4);
+
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+  if (response == GTK_RESPONSE_OK &&
+      gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox)))
+    {
+      reminder_watcher_save_blessed_program (rw->priv->settings, url);
+    }
+
+  gtk_widget_destroy (dialog);
+
+  return response == GTK_RESPONSE_OK;
+#endif
+
+  return FALSE;
+}
+
+static gboolean
+reminder_watcher_notify_procedure (ReminderWatcher *rw,
+                                   const EReminderData *rd,
+                                   ECalComponentAlarm *alarm)
+{
+  ECalComponentText *description;
+  ICalAttach *attach = NULL;
+  GSList *attachments;
+  const gchar *url;
+  gchar *cmd;
+  gboolean result = FALSE;
+
+  g_return_val_if_fail (rw != NULL, FALSE);
+  g_return_val_if_fail (rd != NULL, FALSE);
+  g_return_val_if_fail (alarm != NULL, FALSE);
+
+  print_debug ("ReminderWatcher::Notify Procedure for '%s'", reminder_watcher_get_rd_summary (rd));
+
+  attachments = e_cal_component_alarm_get_attachments (alarm);
+
+  if (attachments && !attachments->next)
+    attach = attachments->data;
+
+  description = e_cal_component_alarm_get_description (alarm);
+
+  /* If the alarm has no attachment, simply display a notification dialog. */
+  if (!attach)
+    goto fallback;
+
+  if (!i_cal_attach_get_is_url (attach))
+    goto fallback;
+
+  url = i_cal_attach_get_url (attach);
+  g_return_val_if_fail (url != NULL, FALSE);
+
+  /* Ask for confirmation before executing the stuff */
+  if (description && e_cal_component_text_get_value (description))
+    cmd = g_strconcat (url, " ", e_cal_component_text_get_value (description), NULL);
+  else
+    cmd = (gchar *) url;
+
+  if (reminder_watcher_can_procedure (rw, cmd, url))
+    result = g_spawn_command_line_async (cmd, NULL);
+
+  if (cmd != (gchar *) url)
+    g_free (cmd);
+
+  /* Fall back to display notification if we got an error */
+  if (!result)
+    goto fallback;
+
+  return FALSE;
+
+ fallback:
+
+  return reminder_watcher_notify_display (rw, rd, alarm);
+}
+
+/* Returns %TRUE to keep it, %FALSE to dismiss it */
+static gboolean
+reminders_process_one (ReminderWatcher *rw,
+                       const EReminderData *rd,
+                       gboolean snoozed)
+{
+  ECalComponentAlarm *alarm;
+  ECalComponentAlarmInstance *instance;
+  ECalComponentAlarmAction action;
+  gboolean keep_in_reminders = FALSE;
+
+  g_return_val_if_fail (rw != NULL, FALSE);
+  g_return_val_if_fail (rd != NULL, FALSE);
+
+  if (e_cal_component_get_vtype (e_reminder_data_get_component (rd)) == E_CAL_COMPONENT_TODO)
+    {
+      ICalPropertyStatus status;
+
+      status = e_cal_component_get_status (e_reminder_data_get_component (rd));
+
+      if (status == I_CAL_STATUS_COMPLETED &&
+          !g_settings_get_boolean (rw->priv->settings, "notify-completed-tasks"))
+        return FALSE;
+    }
+
+  instance = e_reminder_data_get_instance (rd);
+
+  alarm = instance ? e_cal_component_get_alarm (e_reminder_data_get_component (rd), 
e_cal_component_alarm_instance_get_uid (instance)) : NULL;
+  if (!alarm)
+    return FALSE;
+
+  if (!snoozed && !g_settings_get_boolean (rw->priv->settings, "notify-past-events"))
+    {
+      ECalComponentAlarmTrigger *trigger;
+      time_t offset = 0, event_relative, orig_trigger_day, today;
+
+      trigger = e_cal_component_alarm_get_trigger (alarm);
+
+      switch (trigger ? e_cal_component_alarm_trigger_get_kind (trigger) : 
E_CAL_COMPONENT_ALARM_TRIGGER_NONE)
+        {
+          case E_CAL_COMPONENT_ALARM_TRIGGER_NONE:
+          case E_CAL_COMPONENT_ALARM_TRIGGER_ABSOLUTE:
+            break;
+
+          case E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START:
+          case E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_END:
+            offset = i_cal_duration_as_int (e_cal_component_alarm_trigger_get_duration (trigger));
+            break;
+
+          default:
+            break;
+        }
+
+        today = time (NULL);
+        event_relative = e_cal_component_alarm_instance_get_occur_start (instance) - offset;
+
+        #define CLAMP_TO_DAY(x) ((x) - ((x) % (60 * 60 * 24)))
+
+        event_relative = CLAMP_TO_DAY (event_relative);
+        orig_trigger_day = CLAMP_TO_DAY (e_cal_component_alarm_instance_get_time (instance));
+        today = CLAMP_TO_DAY (today);
+
+        #undef CLAMP_TO_DAY
+
+        if (event_relative < today && orig_trigger_day < today)
+          {
+            e_cal_component_alarm_free (alarm);
+            return FALSE;
+          }
+    }
+
+  action = e_cal_component_alarm_get_action (alarm);
+
+  switch (action)
+    {
+      case E_CAL_COMPONENT_ALARM_AUDIO:
+        keep_in_reminders = reminder_watcher_notify_audio (rw, rd, alarm);
+        break;
+
+      case E_CAL_COMPONENT_ALARM_DISPLAY:
+        keep_in_reminders = reminder_watcher_notify_display (rw, rd, alarm);
+        break;
+
+      case E_CAL_COMPONENT_ALARM_EMAIL:
+        keep_in_reminders = reminder_watcher_notify_email (rw, rd, alarm);
+        break;
+
+      case E_CAL_COMPONENT_ALARM_PROCEDURE:
+        keep_in_reminders = reminder_watcher_notify_procedure (rw, rd, alarm);
+        break;
+
+      case E_CAL_COMPONENT_ALARM_NONE:
+      case E_CAL_COMPONENT_ALARM_UNKNOWN:
+        break;
+    }
+
+  e_cal_component_alarm_free (alarm);
+
+  return keep_in_reminders;
+}
+
+static gpointer
+reminders_dismiss_thread (gpointer user_data)
+{
+  ReminderWatcher *rw = user_data;
+  EReminderWatcher *watcher;
+  GSList *dismiss, *link;
+
+  g_return_val_if_fail (IS_REMINDER_WATCHER (rw), NULL);
+
+  g_mutex_lock (&rw->priv->dismiss_lock);
+  dismiss = rw->priv->dismiss;
+  rw->priv->dismiss = NULL;
+  rw->priv->dismiss_thread = NULL;
+  g_mutex_unlock (&rw->priv->dismiss_lock);
+
+  watcher = E_REMINDER_WATCHER (rw);
+  if (watcher)
+    {
+      for (link = dismiss; link; link = g_slist_next (link))
+        {
+          EReminderData *rd = link->data;
+
+          if (rd)
+            {
+              /* Silently ignore any errors here */
+              e_reminder_watcher_dismiss_sync (watcher, rd, NULL, NULL);
+            }
+        }
+    }
+
+  g_slist_free_full (dismiss, e_reminder_data_free);
+  g_clear_object (&rw);
+
+  return NULL;
+}
+
+static void
+reminders_triggered_cb (EReminderWatcher *watcher,
+                        const GSList *reminders, /* EReminderData * */
+                        gboolean snoozed,
+                        gpointer user_data)
+{
+  ReminderWatcher *rw = REMINDER_WATCHER (watcher);
+  GSList *link;
+
+  g_return_if_fail (IS_REMINDER_WATCHER (rw));
+
+  g_mutex_lock (&rw->priv->dismiss_lock);
+
+  for (link = (GSList *) reminders; link; link = g_slist_next (link))
+    {
+      const EReminderData *rd = link->data;
+
+      if (rd && !reminders_process_one (rw, rd, snoozed))
+        {
+         rw->priv->dismiss = g_slist_prepend (rw->priv->dismiss, e_reminder_data_copy (rd));
+        }
+    }
+
+  if (rw->priv->dismiss && !rw->priv->dismiss_thread)
+    {
+       rw->priv->dismiss_thread = g_thread_new (NULL, reminders_dismiss_thread, g_object_ref (rw));
+       g_warn_if_fail (rw->priv->dismiss_thread != NULL);
+       if (rw->priv->dismiss_thread)
+          g_thread_unref (rw->priv->dismiss_thread);
+    }
+
+  g_mutex_unlock (&rw->priv->dismiss_lock);
+}
+
+static EClient *
+reminder_watcher_cal_client_connect_sync (EReminderWatcher *watcher,
+                                          ESource *source,
+                                          ECalClientSourceType source_type,
+                                          guint32 wait_for_connected_seconds,
+                                          GCancellable *cancellable,
+                                          GError **error)
+{
+  ReminderWatcher *reminder_watcher = REMINDER_WATCHER (watcher);
+
+  return calendar_sources_connect_client_sync (reminder_watcher->priv->sources, FALSE, source, source_type,
+                                               wait_for_connected_seconds, cancellable, error);
+}
+
+static void
+reminder_watcher_cal_client_connect (EReminderWatcher *watcher,
+                                     ESource *source,
+                                     ECalClientSourceType source_type,
+                                     guint32 wait_for_connected_seconds,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
+{
+  ReminderWatcher *reminder_watcher = REMINDER_WATCHER (watcher);
+
+  calendar_sources_connect_client (reminder_watcher->priv->sources, FALSE, source, source_type,
+                                   wait_for_connected_seconds, cancellable, callback, user_data);
+}
+
+static EClient *
+reminder_watcher_cal_client_connect_finish (EReminderWatcher *watcher,
+                                            GAsyncResult *result,
+                                            GError **error)
+{
+  ReminderWatcher *reminder_watcher = REMINDER_WATCHER (watcher);
+
+  return calendar_sources_connect_client_finish (reminder_watcher->priv->sources, result, error);
+}
+
+static void
+reminder_watcher_constructed (GObject *object)
+{
+  ReminderWatcher *rw = REMINDER_WATCHER (object);
+
+  G_OBJECT_CLASS (reminder_watcher_parent_class)->constructed (object);
+
+  rw->priv->sources = calendar_sources_get ();
+
+  g_signal_connect (rw, "triggered",
+                    G_CALLBACK (reminders_triggered_cb), NULL);
+}
+
+static void
+reminder_watcher_finalize (GObject *object)
+{
+  ReminderWatcher *rw = REMINDER_WATCHER (object);
+
+  g_clear_object (&rw->priv->sources);
+  g_clear_object (&rw->priv->settings);
+  g_mutex_clear (&rw->priv->dismiss_lock);
+
+  G_OBJECT_CLASS (reminder_watcher_parent_class)->finalize (object);
+}
+
+static void
+reminder_watcher_class_init (ReminderWatcherClass *klass)
+{
+  GObjectClass *object_class;
+  EReminderWatcherClass *watcher_class;
+
+  object_class = G_OBJECT_CLASS (klass);
+  object_class->constructed = reminder_watcher_constructed;
+  object_class->finalize = reminder_watcher_finalize;
+
+  watcher_class = E_REMINDER_WATCHER_CLASS (klass);
+  watcher_class->cal_client_connect_sync = reminder_watcher_cal_client_connect_sync;
+  watcher_class->cal_client_connect = reminder_watcher_cal_client_connect;
+  watcher_class->cal_client_connect_finish = reminder_watcher_cal_client_connect_finish;
+}
+
+static void
+reminder_watcher_init (ReminderWatcher *rw)
+{
+  rw->priv = reminder_watcher_get_instance_private (rw);
+  rw->priv->settings = g_settings_new ("org.gnome.evolution-data-server.calendar");
+
+  g_mutex_init (&rw->priv->dismiss_lock);
+}
+
+EReminderWatcher *
+reminder_watcher_new (GApplication *application,
+                      ESourceRegistry *registry)
+{
+  ReminderWatcher *rw;
+
+  g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+  rw = g_object_new (TYPE_REMINDER_WATCHER,
+                     "registry", registry,
+                     NULL);
+
+  rw->priv->application = application;
+
+  return E_REMINDER_WATCHER (rw);
+}
diff --git a/src/calendar-server/reminder-watcher.h b/src/calendar-server/reminder-watcher.h
new file mode 100644
index 0000000000..f98fadf779
--- /dev/null
+++ b/src/calendar-server/reminder-watcher.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 Red Hat (www.redhat.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 2 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 REMINDER_WATCHER_H
+#define REMINDER_WATCHER_H
+
+#define HANDLE_LIBICAL_MEMORY
+#define EDS_DISABLE_DEPRECATED
+#include <libecal/libecal.h>
+
+/* Standard GObject macros */
+#define TYPE_REMINDER_WATCHER \
+        (reminder_watcher_get_type ())
+#define REMINDER_WATCHER(obj) \
+        (G_TYPE_CHECK_INSTANCE_CAST \
+        ((obj), TYPE_REMINDER_WATCHER, ReminderWatcher))
+#define REMINDER_WATCHER_CLASS(cls) \
+        (G_TYPE_CHECK_CLASS_CAST \
+        ((cls), TYPE_REMINDER_WATCHER, ReminderWatcherClass))
+#define IS_REMINDER_WATCHER(obj) \
+        (G_TYPE_CHECK_INSTANCE_TYPE \
+        ((obj), TYPE_REMINDER_WATCHER))
+#define IS_REMINDER_WATCHER_CLASS(cls) \
+        (G_TYPE_CHECK_CLASS_TYPE \
+        ((cls), TYPE_REMINDER_WATCHER))
+#define REMINDER_WATCHER_GET_CLASS(obj) \
+        (G_TYPE_INSTANCE_GET_CLASS \
+        ((obj), TYPE_REMINDER_WATCHER, ReminderWatcherClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ReminderWatcher ReminderWatcher;
+typedef struct _ReminderWatcherClass ReminderWatcherClass;
+typedef struct _ReminderWatcherPrivate ReminderWatcherPrivate;
+
+struct _ReminderWatcher {
+  EReminderWatcher parent;
+  ReminderWatcherPrivate *priv;
+};
+
+struct _ReminderWatcherClass {
+  EReminderWatcherClass parent_class;
+};
+
+GType             reminder_watcher_get_type     (void) G_GNUC_CONST;
+EReminderWatcher *reminder_watcher_new          (GApplication *application,
+                                                 ESourceRegistry *registry);
+
+G_END_DECLS
+
+#endif /* REMINDER_WATCHER_H */


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