From 70487ccce4dbcf04f9dfb02ba50f7e88e428f14a Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 21:02:17 -0500 Subject: move planner instantiation to main.c so that we can prepare to pass in a mock planner for testing --- src/main.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index c75b2d7..710db66 100644 --- a/src/main.c +++ b/src/main.c @@ -25,6 +25,7 @@ #include #include +#include "planner-eds.h" #include "service.h" /*** @@ -41,23 +42,28 @@ on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop) int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) { - GMainLoop * loop; + IndicatorDatetimePlanner * planner; IndicatorDatetimeService * service; + GMainLoop * loop; /* boilerplate i18n */ setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain (GETTEXT_PACKAGE); + /* get the planner */ + planner = indicator_datetime_planner_eds_new (); + /* run */ - service = indicator_datetime_service_new (); + service = indicator_datetime_service_new (planner); loop = g_main_loop_new (NULL, FALSE); g_signal_connect (service, INDICATOR_DATETIME_SERVICE_SIGNAL_NAME_LOST, G_CALLBACK(on_name_lost), loop); g_main_loop_run (loop); /* cleanup */ - g_clear_object (&service); g_main_loop_unref (loop); + g_object_unref (service); + g_object_unref (planner); return 0; } -- cgit v1.2.3 From b6b0c140f922385d947fa12dfff179a5491a1722 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 21:31:13 -0500 Subject: add a preliminary mock planner for testing alarms/appointments isolated apart from the EDS backend --- src/Makefile.am | 2 + src/main.c | 11 +++- src/planner-mock.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/planner-mock.h | 58 +++++++++++++++++ 4 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 src/planner-mock.c create mode 100644 src/planner-mock.h (limited to 'src/main.c') diff --git a/src/Makefile.am b/src/Makefile.am index 093a258..640650a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,6 +20,8 @@ libindicator_datetime_service_a_CFLAGS = \ libindicator_datetime_service_a_SOURCES = \ planner.c \ planner.h \ + planner-mock.c \ + planner-mock.h \ planner-eds.c \ planner-eds.h \ service.c \ diff --git a/src/main.c b/src/main.c index 710db66..073c876 100644 --- a/src/main.c +++ b/src/main.c @@ -26,6 +26,7 @@ #include #include "planner-eds.h" +#include "planner-mock.h" #include "service.h" /*** @@ -52,7 +53,15 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) textdomain (GETTEXT_PACKAGE); /* get the planner */ - planner = indicator_datetime_planner_eds_new (); + if (g_getenv ("INDICATOR_DATETIME_USE_FAKE_PLANNER") != NULL) + { + g_message ("Using fake appointment book for testing"); + planner = indicator_datetime_planner_mock_new (); + } + else + { + planner = indicator_datetime_planner_eds_new (); + } /* run */ service = indicator_datetime_service_new (planner); diff --git a/src/planner-mock.c b/src/planner-mock.c new file mode 100644 index 0000000..e67ad7e --- /dev/null +++ b/src/planner-mock.c @@ -0,0 +1,178 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . + */ + +#include "config.h" + +#include "planner-mock.h" + +struct _IndicatorDatetimePlannerMockPriv +{ + gboolean is_configured; +}; + +typedef IndicatorDatetimePlannerMockPriv priv_t; + +G_DEFINE_TYPE (IndicatorDatetimePlannerMock, + indicator_datetime_planner_mock, + INDICATOR_TYPE_DATETIME_PLANNER) + +/*** +**** IndicatorDatetimePlanner virtual funcs +***/ + +static void +my_get_appointments (IndicatorDatetimePlanner * planner, + GDateTime * begin_datetime, + GDateTime * end_datetime G_GNUC_UNUSED, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask * task; + GSList * appointments; + struct IndicatorDatetimeAppt * appt; + struct IndicatorDatetimeAppt * prev; + + task = g_task_new (planner, NULL, callback, user_data); + + /** + *** Build the appointments list + **/ + + appointments = NULL; + + /* add a daily appointment that occurs at the beginning of the next minute */ + appt = g_slice_new0 (struct IndicatorDatetimeAppt); + appt->is_daily = TRUE; + appt->begin = g_date_time_add_seconds (begin_datetime, 60-g_date_time_get_seconds(begin_datetime)); + appt->end = g_date_time_add_minutes (appt->begin, 1); + appt->color = g_strdup ("#00FF00"); + appt->is_event = TRUE; + appt->summary = g_strdup ("Daily alarm"); + appt->uid = g_strdup ("this uid isn't very random."); + appt->has_alarms = TRUE; + appt->url = g_strdup ("alarm:///some-alarm-info-goes-here"); + appointments = g_slist_prepend (appointments, appt); + prev = appt; + + /* and add one for a minute later that has an alarm uri */ + appt = g_slice_new0 (struct IndicatorDatetimeAppt); + appt->is_daily = TRUE; + appt->begin = g_date_time_add_minutes (prev->end, 1); + appt->end = g_date_time_add_minutes (appt->begin, 1); + appt->color = g_strdup ("#0000FF"); + appt->is_event = TRUE; + appt->summary = g_strdup ("Second Daily alarm"); + appt->uid = g_strdup ("this uid isn't very random either."); + appt->has_alarms = FALSE; + appointments = g_slist_prepend (appointments, appt); + + /* done */ + g_task_return_pointer (task, appointments, NULL); + g_object_unref (task); +} + +static GSList * +my_get_appointments_finish (IndicatorDatetimePlanner * self G_GNUC_UNUSED, + GAsyncResult * res, + GError ** error) +{ + return g_task_propagate_pointer (G_TASK(res), error); +} + +static gboolean +my_is_configured (IndicatorDatetimePlanner * planner) +{ + IndicatorDatetimePlannerMock * self; + self = INDICATOR_DATETIME_PLANNER_MOCK (planner); + return self->priv->is_configured; +} + +static void +my_activate (IndicatorDatetimePlanner * self G_GNUC_UNUSED) +{ + g_message ("%s %s", G_STRLOC, G_STRFUNC); +} + +static void +my_activate_time (IndicatorDatetimePlanner * self G_GNUC_UNUSED, + GDateTime * activate_time) +{ + gchar * str = g_date_time_format (activate_time, "%F %T"); + g_message ("%s %s: %s", G_STRLOC, G_STRFUNC, str); + g_free (str); +} + +/*** +**** GObject virtual funcs +***/ + +static void +my_dispose (GObject * o) +{ + G_OBJECT_CLASS (indicator_datetime_planner_mock_parent_class)->dispose (o); +} + +/*** +**** Instantiation +***/ + +static void +indicator_datetime_planner_mock_class_init (IndicatorDatetimePlannerMockClass * klass) +{ + GObjectClass * object_class; + IndicatorDatetimePlannerClass * planner_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + + planner_class = INDICATOR_DATETIME_PLANNER_CLASS (klass); + planner_class->is_configured = my_is_configured; + planner_class->activate = my_activate; + planner_class->activate_time = my_activate_time; + planner_class->get_appointments = my_get_appointments; + planner_class->get_appointments_finish = my_get_appointments_finish; + + g_type_class_add_private (klass, sizeof (IndicatorDatetimePlannerMockPriv)); +} + +static void +indicator_datetime_planner_mock_init (IndicatorDatetimePlannerMock * self) +{ + priv_t * p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_DATETIME_PLANNER_MOCK, + IndicatorDatetimePlannerMockPriv); + + p->is_configured = TRUE; + + self->priv = p; +} + +/*** +**** Public +***/ + +IndicatorDatetimePlanner * +indicator_datetime_planner_mock_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_PLANNER_MOCK, NULL); + + return INDICATOR_DATETIME_PLANNER (o); +} diff --git a/src/planner-mock.h b/src/planner-mock.h new file mode 100644 index 0000000..8d7d7c2 --- /dev/null +++ b/src/planner-mock.h @@ -0,0 +1,58 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . + */ + +#ifndef __INDICATOR_DATETIME_PLANNER_MOCK__H__ +#define __INDICATOR_DATETIME_PLANNER_MOCK__H__ + +#include "planner.h" /* parent class */ + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_DATETIME_PLANNER_MOCK (indicator_datetime_planner_mock_get_type()) +#define INDICATOR_DATETIME_PLANNER_MOCK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK, IndicatorDatetimePlannerMock)) +#define INDICATOR_DATETIME_PLANNER_MOCK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK, IndicatorDatetimePlannerMockClass)) +#define INDICATOR_IS_DATETIME_PLANNER_MOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK)) + +typedef struct _IndicatorDatetimePlannerMock IndicatorDatetimePlannerMock; +typedef struct _IndicatorDatetimePlannerMockPriv IndicatorDatetimePlannerMockPriv; +typedef struct _IndicatorDatetimePlannerMockClass IndicatorDatetimePlannerMockClass; + +GType indicator_datetime_planner_mock_get_type (void); + +/** + * An IndicatorDatetimePlanner which uses Evolution Data Server + * to get its list of appointments. + */ +struct _IndicatorDatetimePlannerMock +{ + /*< private >*/ + IndicatorDatetimePlanner parent; + IndicatorDatetimePlannerMockPriv * priv; +}; + +struct _IndicatorDatetimePlannerMockClass +{ + IndicatorDatetimePlannerClass parent_class; +}; + +IndicatorDatetimePlanner * indicator_datetime_planner_mock_new (void); + +G_END_DECLS + +#endif /* __INDICATOR_DATETIME_PLANNER_MOCK__H__ */ -- cgit v1.2.3 From a52e3b86ee0dbce56221d1327c6c62a6d8e163e3 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 21:33:15 -0500 Subject: preliminary implementation of snap decision --- configure.ac | 2 ++ debian/control | 1 + src/main.c | 6 +++++ src/service.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 73 insertions(+), 14 deletions(-) (limited to 'src/main.c') diff --git a/configure.ac b/configure.ac index 8b95695..5b9dda6 100644 --- a/configure.ac +++ b/configure.ac @@ -51,6 +51,7 @@ GEOCLUE_REQUIRED_VERSION=0.12.0 ICAL_REQUIRED_VERSION=0.48 ECAL_REQUIRED_VERSION=3.5 EDS_REQUIRED_VERSION=3.5 +LIBNOTIFY_REQUIRED_VERSION=0.7.6 URL_DISPATCHER_1_REQUIRED_VERSION=1 GTK3_REQUIRED_VERSION=3.1.4 @@ -61,6 +62,7 @@ PKG_CHECK_MODULES(SERVICE, [glib-2.0 >= $GLIB_REQUIRED_VERSION libical >= $ICAL_REQUIRED_VERSION libecal-1.2 >= $ECAL_REQUIRED_VERSION libedataserver-1.2 >= EDS_REQUIRED_VERSION + libnotify >= $LIBNOTIFY_REQUIRED_VERSION url-dispatcher-1 >= URL_DISPATCHER_1_REQUIRED_VERSION]) ########################### diff --git a/debian/control b/debian/control index 67938bf..0815e1b 100644 --- a/debian/control +++ b/debian/control @@ -10,6 +10,7 @@ Build-Depends: debhelper (>= 9), libxorg-gtest-dev, libgtest-dev, libglib2.0-dev (>= 2.35.4), + libnotify-dev (>= 0.7.6), libido3-0.1-dev (>= 0.2.90), libgeoclue-dev (>= 0.12.0), libecal1.2-dev (>= 3.5), diff --git a/src/main.c b/src/main.c index 073c876..34e9b98 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,7 @@ #include #include +#include #include "planner-eds.h" #include "planner-mock.h" @@ -52,6 +53,11 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain (GETTEXT_PACKAGE); + /* init libnotify */ + if (!notify_init ("indicator-datetime-service")) + g_critical ("libnotify initialization failed"); + + /* get the planner */ if (g_getenv ("INDICATOR_DATETIME_USE_FAKE_PLANNER") != NULL) { diff --git a/src/service.c b/src/service.c index 57d0a7e..c76b07e 100644 --- a/src/service.c +++ b/src/service.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "dbus-shared.h" @@ -431,31 +432,80 @@ dispatch_alarm_url (const struct IndicatorDatetimeAppt * appt) url_dispatch_send (appt->url, NULL, NULL); } -/* Check for alarms that start at the current time. - If we find any, we dispatch the URL associated with them. */ +#if 0 static void -dispatch_alarm_urls (IndicatorDatetimeService * self) +on_notification_closed (NotifyNotification * nn, gpointer gself) { - GDateTime * now = indicator_datetime_service_get_localtime (self); - GSList * l; + //IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself); - for (l=self->priv->upcoming_appointments; l!=NULL; l=l->next) - { - const struct IndicatorDatetimeAppt * appt = l->data; + g_message ("hello world"); - if (appointment_has_alarm_url (appt) && datetimes_have_the_same_minute (now, appt->begin)) - dispatch_alarm_url (appt); - } + /* cleanup */ + g_signal_handlers_disconnect_by_data (nn, gself); + g_object_unref (nn); +} +#endif - g_date_time_unref (now); +static void +on_alarm_popup_ok_clicked (NotifyNotification * nn G_GNUC_UNUSED, char * action G_GNUC_UNUSED, gpointer gurl) +{ + const char * url = gurl; + url_dispatch_send (url, NULL, NULL); } +#define ALARM_ICON_NAME "alarm-symbolic" + static void update_appointment_lists (IndicatorDatetimeService * self); static gboolean -on_alarm_timer (gpointer self) +on_alarm_timer (gpointer gself) { - dispatch_alarm_urls (self); + GDateTime * now; + GSList * l; + IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself); + + /* Check for alarms that start at the current time. + * If we find one, trigger a snap decision displaying + * the appointment text and a single button to dismiss */ + now = indicator_datetime_service_get_localtime (self); + for (l=self->priv->upcoming_appointments; l!=NULL; l=l->next) + { + gchar * title; + const gchar * body; + const struct IndicatorDatetimeAppt * appt = l->data; + NotifyNotification * nn; + GError * error; + + if (!appointment_has_alarm_url (appt)) + continue; + + if (!datetimes_have_the_same_minute (now, appt->begin)) + continue; + + title = g_date_time_format (now, get_terse_time_format_string (now)); + body = appt->summary; + nn = notify_notification_new (title, body, ALARM_ICON_NAME); + + notify_notification_set_hint (nn, "x-canonical-snap-decisions", + g_variant_new_boolean(TRUE)); + notify_notification_set_hint (nn, "x-canonical-private-button-tint", + g_variant_new_boolean(TRUE)); + notify_notification_add_action (nn, "ok", _("OK"), + on_alarm_popup_ok_clicked, + g_strdup (appt->url), g_free); + //g_signal_connect (nn, "closed", G_CALLBACK(on_notification_closed), self); + + error = NULL; + notify_notification_show (nn, &error); + if (error != NULL) + { + g_warning ("Unable to show alarm '%s' popup: %s", body, error->message); + g_error_free (error); + dispatch_alarm_url (appt); + } + g_free (title); + } + g_date_time_unref (now); /* rebuild the alarm list asynchronously. when it's done, set_upcoming_appointments() will update the alarm timer */ -- cgit v1.2.3 From dae4fdd39e5381083345e87759dbaffddabe14e4 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 9 Oct 2013 22:55:26 -0500 Subject: more wiring in of mock objects --- src/main.c | 38 +++++++++++++++++++++++++++----------- src/service.c | 7 +++++-- 2 files changed, 32 insertions(+), 13 deletions(-) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index 34e9b98..45ee180 100644 --- a/src/main.c +++ b/src/main.c @@ -21,6 +21,7 @@ #include #include /* exit() */ +#include #include #include @@ -30,6 +31,8 @@ #include "planner-mock.h" #include "service.h" +#define TEST_MODE + /*** **** ***/ @@ -41,6 +44,18 @@ on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop) g_main_loop_quit ((GMainLoop*)loop); } +#ifdef TEST_MODE +static void +log_handler (const gchar * log_domain, + GLogLevelFlags log_level, + const gchar * message, + gpointer fp) +{ + fprintf (fp, "%s %d %s\n", log_domain, (int)log_level, message); + fflush (fp); +} +#endif + int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) { @@ -57,17 +72,15 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) if (!notify_init ("indicator-datetime-service")) g_critical ("libnotify initialization failed"); - - /* get the planner */ - if (g_getenv ("INDICATOR_DATETIME_USE_FAKE_PLANNER") != NULL) - { - g_message ("Using fake appointment book for testing"); - planner = indicator_datetime_planner_mock_new (); - } - else - { - planner = indicator_datetime_planner_eds_new (); - } + /* set up the planner */ +#ifdef TEST_MODE + g_warning ("Using fake appointment book for testing! Probably shouldn't merge this to trunk."); + FILE * fp = fopen ("/tmp/indicator-datetime-log.txt", "w+"); + g_log_set_handler ("Indicator-Datetime", G_LOG_LEVEL_MASK, log_handler, fp); + planner = indicator_datetime_planner_mock_new (); +#else + planner = indicator_datetime_planner_eds_new (); +#endif /* run */ service = indicator_datetime_service_new (planner); @@ -80,5 +93,8 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) g_main_loop_unref (loop); g_object_unref (service); g_object_unref (planner); +#ifdef TEST_MODE + fclose (fp); +#endif return 0; } diff --git a/src/service.c b/src/service.c index c76b07e..61d50aa 100644 --- a/src/service.c +++ b/src/service.c @@ -472,6 +472,7 @@ on_alarm_timer (gpointer gself) { gchar * title; const gchar * body; + const gchar * icon_name; const struct IndicatorDatetimeAppt * appt = l->data; NotifyNotification * nn; GError * error; @@ -484,8 +485,10 @@ on_alarm_timer (gpointer gself) title = g_date_time_format (now, get_terse_time_format_string (now)); body = appt->summary; - nn = notify_notification_new (title, body, ALARM_ICON_NAME); - + icon_name = ALARM_ICON_NAME; + g_debug ("creating a snap decision with title '%s', body '%s', icon '%s'", + title, body, icon_name); + nn = notify_notification_new (title, body, icon_name); notify_notification_set_hint (nn, "x-canonical-snap-decisions", g_variant_new_boolean(TRUE)); notify_notification_set_hint (nn, "x-canonical-private-button-tint", -- cgit v1.2.3 From 8dadf00b78312867f33a2f6dcd39118a1beb150c Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 16 Oct 2013 14:52:54 -0500 Subject: for testing purposes, fire off a snap decision as soon as the datetime indicator is started. this way one can test on phablet by running as user phablet --- src/main.c | 57 ++++++++++++++++++++++++++++++++++++++++----------------- src/service.c | 33 ++++++++++----------------------- 2 files changed, 50 insertions(+), 40 deletions(-) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index 45ee180..c7ad34a 100644 --- a/src/main.c +++ b/src/main.c @@ -31,30 +31,55 @@ #include "planner-mock.h" #include "service.h" -#define TEST_MODE - /*** **** ***/ static void -on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop) +on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop G_GNUC_UNUSED) { g_message ("exiting: service couldn't acquire or lost ownership of busname"); g_main_loop_quit ((GMainLoop*)loop); } -#ifdef TEST_MODE static void -log_handler (const gchar * log_domain, - GLogLevelFlags log_level, - const gchar * message, - gpointer fp) +action_ok (NotifyNotification *notification G_GNUC_UNUSED, + char *action, + gpointer gurl) { - fprintf (fp, "%s %d %s\n", log_domain, (int)log_level, message); - fflush (fp); + const char * url = gurl; + g_message ("'%s' clicked for snap decision; url is '%s'", action, url); +} + +static void +show_snap_decision (void) +{ + const gchar * title = "Title"; + const gchar * body = "Body"; + const gchar * icon_name = "alarm-clock"; + NotifyNotification * nn; + GError * error; + + g_debug ("creating a snap decision with title '%s', body '%s', icon '%s'", + title, body, icon_name); + + nn = notify_notification_new (title, body, icon_name); + notify_notification_set_hint (nn, "x-canonical-snap-decisions", + g_variant_new_boolean(TRUE)); + notify_notification_set_hint (nn, "x-canonical-private-button-tint", + g_variant_new_boolean(TRUE)); + notify_notification_add_action (nn, "action_accept", _("OK"), + action_ok, g_strdup("hello world"), g_free); + + g_message ("showing notification %p", nn); + error = NULL; + notify_notification_show (nn, &error); + if (error != NULL) + { + g_warning ("Unable to show alarm '%s' popup: %s", body, error->message); + g_error_free (error); + } } -#endif int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) @@ -74,14 +99,15 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) /* set up the planner */ #ifdef TEST_MODE - g_warning ("Using fake appointment book for testing! Probably shouldn't merge this to trunk."); - FILE * fp = fopen ("/tmp/indicator-datetime-log.txt", "w+"); - g_log_set_handler ("Indicator-Datetime", G_LOG_LEVEL_MASK, log_handler, fp); + g_warning ("Using fake appointment book for testing! " + "Probably shouldn't merge this to trunk."); planner = indicator_datetime_planner_mock_new (); #else planner = indicator_datetime_planner_eds_new (); #endif + show_snap_decision (); + /* run */ service = indicator_datetime_service_new (planner); loop = g_main_loop_new (NULL, FALSE); @@ -93,8 +119,5 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) g_main_loop_unref (loop); g_object_unref (service); g_object_unref (planner); -#ifdef TEST_MODE - fclose (fp); -#endif return 0; } diff --git a/src/service.c b/src/service.c index 270f214..fd3d937 100644 --- a/src/service.c +++ b/src/service.c @@ -432,24 +432,13 @@ dispatch_alarm_url (const struct IndicatorDatetimeAppt * appt) url_dispatch_send (appt->url, NULL, NULL); } -#if 0 static void -on_notification_closed (NotifyNotification * nn, gpointer gself) -{ - //IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself); - - g_message ("hello world"); - - /* cleanup */ - g_signal_handlers_disconnect_by_data (nn, gself); - g_object_unref (nn); -} -#endif - -static void -on_alarm_popup_ok_clicked (NotifyNotification * nn G_GNUC_UNUSED, char * action G_GNUC_UNUSED, gpointer gurl) +action_ok (NotifyNotification *notification G_GNUC_UNUSED, + char *action, + gpointer gurl) { const char * url = gurl; + g_debug ("'%s' clicked for snap decision %s", action, url); url_dispatch_send (url, NULL, NULL); } @@ -465,17 +454,18 @@ show_snap_decision_for_alarm (const struct IndicatorDatetimeAppt * appt) title = g_date_time_format (appt->begin, get_terse_time_format_string (appt->begin)); body = appt->summary; - icon_name = "alarm-symbolic"; + icon_name = "alarm-clock"; g_debug ("creating a snap decision with title '%s', body '%s', icon '%s'", title, body, icon_name); + nn = notify_notification_new (title, body, icon_name); notify_notification_set_hint (nn, "x-canonical-snap-decisions", g_variant_new_boolean(TRUE)); notify_notification_set_hint (nn, "x-canonical-private-button-tint", g_variant_new_boolean(TRUE)); - notify_notification_add_action (nn, "ok", _("OK"), - on_alarm_popup_ok_clicked, - g_strdup (appt->url), g_free); + notify_notification_add_action (nn, "action_accept", _("OK"), + action_ok, g_strdup(appt->url), g_free); + error = NULL; notify_notification_show (nn, &error); if (error != NULL) @@ -1981,14 +1971,11 @@ on_name_lost (GDBusConnection * connection G_GNUC_UNUSED, { IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself); - if (connection == NULL) - g_error ("Unable to get bus connection to own name '%s'", name); - g_debug ("%s %s name lost %s", G_STRLOC, G_STRFUNC, name); unexport (self); - g_signal_emit (self, signals[SIGNAL_NAME_LOST], 0, NULL); + //g_signal_emit (self, signals[SIGNAL_NAME_LOST], 0, NULL); } -- cgit v1.2.3 From a96e714329ea80e676af5dc5db69ba5b62a25b6e Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Wed, 16 Oct 2013 16:48:01 -0500 Subject: add a test mode for alarms. --- src/main.c | 78 ++++++++++++++++++++++++-------------------------------------- 1 file changed, 30 insertions(+), 48 deletions(-) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index c7ad34a..3be51eb 100644 --- a/src/main.c +++ b/src/main.c @@ -35,55 +35,28 @@ **** ***/ +/* When enabled, new alarms will show up every minute to test snap decisions */ +static gboolean test_alarms = FALSE; + +static GOptionEntry entries[] = { + { "test-alarms", '\0', 0, G_OPTION_ARG_NONE, &test_alarms, "Test Alarms", NULL }, + { NULL } +}; + static void on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop G_GNUC_UNUSED) { g_message ("exiting: service couldn't acquire or lost ownership of busname"); - g_main_loop_quit ((GMainLoop*)loop); -} -static void -action_ok (NotifyNotification *notification G_GNUC_UNUSED, - char *action, - gpointer gurl) -{ - const char * url = gurl; - g_message ("'%s' clicked for snap decision; url is '%s'", action, url); -} - -static void -show_snap_decision (void) -{ - const gchar * title = "Title"; - const gchar * body = "Body"; - const gchar * icon_name = "alarm-clock"; - NotifyNotification * nn; - GError * error; - - g_debug ("creating a snap decision with title '%s', body '%s', icon '%s'", - title, body, icon_name); - - nn = notify_notification_new (title, body, icon_name); - notify_notification_set_hint (nn, "x-canonical-snap-decisions", - g_variant_new_boolean(TRUE)); - notify_notification_set_hint (nn, "x-canonical-private-button-tint", - g_variant_new_boolean(TRUE)); - notify_notification_add_action (nn, "action_accept", _("OK"), - action_ok, g_strdup("hello world"), g_free); - - g_message ("showing notification %p", nn); - error = NULL; - notify_notification_show (nn, &error); - if (error != NULL) - { - g_warning ("Unable to show alarm '%s' popup: %s", body, error->message); - g_error_free (error); - } + if (!test_alarms) + g_main_loop_quit ((GMainLoop*)loop); } int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) { + GOptionContext * context; + GError * error; IndicatorDatetimePlanner * planner; IndicatorDatetimeService * service; GMainLoop * loop; @@ -97,16 +70,25 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) if (!notify_init ("indicator-datetime-service")) g_critical ("libnotify initialization failed"); + /* parse command-line options */ + context = g_option_context_new (NULL); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_print("option parsing failed: %s\n", error->message); + return EXIT_FAILURE; + } + /* set up the planner */ -#ifdef TEST_MODE - g_warning ("Using fake appointment book for testing! " - "Probably shouldn't merge this to trunk."); - planner = indicator_datetime_planner_mock_new (); -#else - planner = indicator_datetime_planner_eds_new (); -#endif - - show_snap_decision (); + if (test_alarms) + { + g_message ("Using fake appointment book for testing alarms."); + planner = indicator_datetime_planner_mock_new (); + } + else + { + planner = indicator_datetime_planner_eds_new (); + } /* run */ service = indicator_datetime_service_new (planner); -- cgit v1.2.3 From f1fe817863e7f167fdb4f98ebd9e5fed33d659b3 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 17 Oct 2013 08:23:13 -0400 Subject: Work around glib's type initialization deadlock --- src/main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index f791683..cd7a6a5 100644 --- a/src/main.c +++ b/src/main.c @@ -60,6 +60,12 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) IndicatorDatetimeService * service; GMainLoop * loop; + /* Work around a deadlock in glib's type initialization. It can be + * removed when https://bugzilla.gnome.org/show_bug.cgi?id=674885 is + * fixed. + */ + g_type_ensure (G_TYPE_DBUS_CONNECTION); + /* boilerplate i18n */ setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); -- cgit v1.2.3 From bcc04892148c7396e638f45e96fcba42d0034ec7 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 17 Oct 2013 16:32:44 -0500 Subject: refactor the timezone and current time provider into a gobject Interface 'IndicatorDatetimeClock' --- src/Makefile.am | 6 +- src/clock-live.c | 306 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/clock-live.h | 73 ++++++++++++ src/clock.c | 110 ++++++++++++++++++ src/clock.h | 76 +++++++++++++ src/main.c | 41 ++----- src/planner-mock.c | 178 ------------------------------ src/planner-mock.h | 58 ---------- src/service.c | 230 ++++++++++++++++---------------------- src/service.h | 10 +- tests/planner-mock.c | 178 ++++++++++++++++++++++++++++++ tests/planner-mock.h | 58 ++++++++++ 12 files changed, 916 insertions(+), 408 deletions(-) create mode 100644 src/clock-live.c create mode 100644 src/clock-live.h create mode 100644 src/clock.c create mode 100644 src/clock.h delete mode 100644 src/planner-mock.c delete mode 100644 src/planner-mock.h create mode 100644 tests/planner-mock.c create mode 100644 tests/planner-mock.h (limited to 'src/main.c') diff --git a/src/Makefile.am b/src/Makefile.am index 640650a..be7eb4d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,10 +18,12 @@ libindicator_datetime_service_a_CFLAGS = \ $(SHARED_CFLAGS) libindicator_datetime_service_a_SOURCES = \ + clock.c \ + clock.h \ + clock-live.c \ + clock-live.h \ planner.c \ planner.h \ - planner-mock.c \ - planner-mock.h \ planner-eds.c \ planner-eds.h \ service.c \ diff --git a/src/clock-live.c b/src/clock-live.c new file mode 100644 index 0000000..6e694ed --- /dev/null +++ b/src/clock-live.c @@ -0,0 +1,306 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . + */ + +#include +#include + +#include "config.h" + +#include "clock-live.h" +#include "settings-shared.h" +#include "timezone-file.h" +#include "timezone-geoclue.h" + +/*** +**** private struct +***/ + +struct _IndicatorDatetimeClockLivePriv +{ + GSettings * settings; + + /* cached GTimeZone for use by indicator_datetime_service_get_localtime() */ + GTimeZone * internal_timezone; + + IndicatorDatetimeTimezone * tz_file; + IndicatorDatetimeTimezone * tz_geoclue; +}; + +typedef IndicatorDatetimeClockLivePriv priv_t; + +/*** +**** GObject boilerplate +***/ + +static void indicator_datetime_clock_interface_init ( + IndicatorDatetimeClockInterface * iface); + +G_DEFINE_TYPE_WITH_CODE ( + IndicatorDatetimeClockLive, + indicator_datetime_clock_live, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (INDICATOR_TYPE_DATETIME_CLOCK, + indicator_datetime_clock_interface_init)); + +/*** +**** Convenience func +***/ + +#if 0 +static void +emit_changed (IndicatorDatetimeClockLive * self) +{ + indicator_datetime_clock_emit_changed (INDICATOR_DATETIME_CLOCK (self)); +} +#endif + +/*** +**** Timezones +***/ + +static void +update_internal_timezone (IndicatorDatetimeClockLive * self) +{ + priv_t * p = self->priv; + const char * id; + + /* find the id from tz_file or tz_geoclue if possible; NULL otherwise */ + id = NULL; + if (p->tz_file != NULL ) + id = indicator_datetime_timezone_get_timezone (p->tz_file); + if (!id && p->tz_geoclue) + id = indicator_datetime_timezone_get_timezone (p->tz_geoclue); + + g_clear_pointer (&p->internal_timezone, g_time_zone_unref); + p->internal_timezone = g_time_zone_new (id); +} + +static void +on_current_timezone_changed (IndicatorDatetimeClockLive * self) +{ + indicator_datetime_clock_emit_changed (INDICATOR_DATETIME_CLOCK (self)); +} + +static void +set_detect_location_enabled (IndicatorDatetimeClockLive * self, gboolean enabled) +{ + priv_t * p = self->priv; + gboolean changed = FALSE; + + /* geoclue */ + + if (!p->tz_geoclue && enabled) + { + p->tz_geoclue = indicator_datetime_timezone_geoclue_new (); + g_signal_connect_swapped (p->tz_geoclue, "notify::timezone", + G_CALLBACK(on_current_timezone_changed), + self); + changed = TRUE; + } + else if (p->tz_geoclue && !enabled) + { + g_signal_handlers_disconnect_by_func (p->tz_geoclue, + on_current_timezone_changed, + self); + g_clear_object (&p->tz_geoclue); + changed = TRUE; + } + + /* timezone file */ + + if (!p->tz_file && enabled) + { + p->tz_file = indicator_datetime_timezone_file_new (TIMEZONE_FILE); + g_signal_connect_swapped (p->tz_file, "notify::timezone", + G_CALLBACK(on_current_timezone_changed), + self); + changed = TRUE; + } + else if (p->tz_file && !enabled) + { + g_signal_handlers_disconnect_by_func (p->tz_file, + on_current_timezone_changed, + self); + g_clear_object (&p->tz_file); + changed = TRUE; + } + + if (changed) + on_current_timezone_changed (self); +} + +/* When the 'auto-detect timezone' boolean setting changes, + start or stop watching geoclue and /etc/timezone */ +static void +on_detect_location_changed (IndicatorDatetimeClockLive * self) +{ + const gboolean enabled = g_settings_get_boolean (self->priv->settings, SETTINGS_SHOW_DETECTED_S); + set_detect_location_enabled (self, enabled); +} + +/*** +**** IndicatorDatetimeClock virtual functions +***/ + +static gchar ** +my_get_timezones (IndicatorDatetimeClock * clock G_GNUC_UNUSED) +{ + IndicatorDatetimeClockLive * self; + priv_t * p; + GHashTable * hash; + gchar ** timezones; + int i; + GHashTableIter iter; + gpointer key; + + self = INDICATOR_DATETIME_CLOCK_LIVE (clock); + p = self->priv; + + hash = g_hash_table_new (g_str_hash, g_str_equal); + + if (p->tz_file != NULL) + { + const gchar * tz = indicator_datetime_timezone_get_timezone (p->tz_file); + if (tz && *tz) + g_hash_table_add (hash, (gpointer) tz); + } + + if (p->tz_geoclue != NULL) + { + const gchar * tz = indicator_datetime_timezone_get_timezone (p->tz_geoclue); + if (tz && *tz) + g_hash_table_add (hash, (gpointer) tz); + } + + timezones = g_new0 (gchar*, g_hash_table_size(hash) + 1); + i = 0; + g_hash_table_iter_init (&iter, hash); + while (g_hash_table_iter_next (&iter, &key, NULL)) + timezones[i++] = g_strdup (key); + g_hash_table_unref (hash); + return timezones; +} + +static GDateTime * +my_get_current_time (IndicatorDatetimeClock * clock) +{ + IndicatorDatetimeClockLive * self; + priv_t * p; + + self = INDICATOR_DATETIME_CLOCK_LIVE (clock); + p = self->priv; + + if (G_UNLIKELY (p->internal_timezone == NULL)) + update_internal_timezone (self); + + return g_date_time_new_now (p->internal_timezone); +} + +/*** +**** GObject virtual functions +***/ + +static void +my_dispose (GObject * o) +{ + IndicatorDatetimeClockLive * self; + priv_t * p; + + self = INDICATOR_DATETIME_CLOCK_LIVE(o); + p = self->priv; + + g_clear_pointer (&p->internal_timezone, g_time_zone_unref); + + if (p->settings != NULL) + { + g_signal_handlers_disconnect_by_data (p->settings, self); + g_clear_object (&p->settings); + } + + set_detect_location_enabled (self, FALSE); + + G_OBJECT_CLASS (indicator_datetime_clock_live_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ +#if 0 + IndicatorDatetimeClockLive * self; + priv_t * p; + + self = INDICATOR_DATETIME_CLOCK_LIVE(o); + p = self->priv; +#endif + + G_OBJECT_CLASS (indicator_datetime_clock_live_parent_class)->dispose (o); +} + +/*** +**** Instantiation +***/ + +static void +indicator_datetime_clock_live_class_init (IndicatorDatetimeClockLiveClass * klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + + g_type_class_add_private (klass, + sizeof (IndicatorDatetimeClockLivePriv)); +} + +static void +indicator_datetime_clock_interface_init (IndicatorDatetimeClockInterface * iface) +{ + iface->get_timezones = my_get_timezones; + iface->get_current_time = my_get_current_time; +} + +static void +indicator_datetime_clock_live_init (IndicatorDatetimeClockLive * self) +{ + IndicatorDatetimeClockLivePriv * p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_DATETIME_CLOCK_LIVE, + IndicatorDatetimeClockLivePriv); + self->priv = p; + + p->settings = g_settings_new (SETTINGS_INTERFACE); + g_signal_connect (p->settings, "changed::" SETTINGS_SHOW_DETECTED_S, + G_CALLBACK(on_detect_location_changed), self); + + + on_detect_location_changed (self); +} + +/*** +**** Public API +***/ + +IndicatorDatetimeClock * +indicator_datetime_clock_live_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_CLOCK_LIVE, NULL); + + return INDICATOR_DATETIME_CLOCK (o); +} diff --git a/src/clock-live.h b/src/clock-live.h new file mode 100644 index 0000000..4425f5b --- /dev/null +++ b/src/clock-live.h @@ -0,0 +1,73 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . + */ + +#ifndef __INDICATOR_DATETIME_CLOCK_LIVE__H__ +#define __INDICATOR_DATETIME_CLOCK_LIVE__H__ + +#include /* parent class */ + +#include "clock.h" + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_DATETIME_CLOCK_LIVE \ + (indicator_datetime_clock_live_get_type()) + +#define INDICATOR_DATETIME_CLOCK_LIVE(o) \ + (G_TYPE_CHECK_INSTANCE_CAST ((o), \ + INDICATOR_TYPE_DATETIME_CLOCK_LIVE, \ + IndicatorDatetimeClockLive)) + +#define INDICATOR_DATETIME_CLOCK_LIVE_GET_CLASS(o) \ + (G_TYPE_INSTANCE_GET_CLASS ((o), \ + INDICATOR_TYPE_DATETIME_CLOCK_LIVE, \ + IndicatorDatetimeClockLiveClass)) + +#define INDICATOR_IS_DATETIME_CLOCK_LIVE(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((o), \ + INDICATOR_TYPE_DATETIME_CLOCK_LIVE)) + +typedef struct _IndicatorDatetimeClockLive + IndicatorDatetimeClockLive; +typedef struct _IndicatorDatetimeClockLivePriv + IndicatorDatetimeClockLivePriv; +typedef struct _IndicatorDatetimeClockLiveClass + IndicatorDatetimeClockLiveClass; + +/** + * An IndicatorDatetimeClock which gives live clock times + * from timezones determined by geoclue and /etc/timezone + */ +struct _IndicatorDatetimeClockLive +{ + GObject parent_instance; + + IndicatorDatetimeClockLivePriv * priv; +}; + +struct _IndicatorDatetimeClockLiveClass +{ + GObjectClass parent_class; +}; + +IndicatorDatetimeClock * indicator_datetime_clock_live_new (void); + +G_END_DECLS + +#endif /* __INDICATOR_DATETIME_CLOCK_LIVE__H__ */ diff --git a/src/clock.c b/src/clock.c new file mode 100644 index 0000000..1abdd21 --- /dev/null +++ b/src/clock.c @@ -0,0 +1,110 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . + */ + +#include "clock.h" + +enum +{ + SIGNAL_CHANGED, + SIGNAL_LAST +}; + +static guint signals[SIGNAL_LAST] = { 0 }; + +G_DEFINE_INTERFACE (IndicatorDatetimeClock, + indicator_datetime_clock, + 0); + +static void +indicator_datetime_clock_default_init (IndicatorDatetimeClockInterface * klass) +{ + signals[SIGNAL_CHANGED] = g_signal_new ( + "changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (IndicatorDatetimeClockInterface, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +/*** +**** PUBLIC API +***/ + +/** + * Get a strv of timezones. + * + * Return value: (element-type char*) + * (transfer full): + * array of timezone strings + */ +gchar ** +indicator_datetime_clock_get_timezones (IndicatorDatetimeClock * self) +{ + gchar ** timezones; + IndicatorDatetimeClockInterface * iface; + + g_return_val_if_fail (INDICATOR_IS_DATETIME_CLOCK(self), NULL); + iface = INDICATOR_DATETIME_CLOCK_GET_INTERFACE(self); + + if (iface->get_timezones != NULL) + timezones = iface->get_timezones (self); + else + timezones = NULL; + + return timezones; +} + +/** + * Get the current time. + * + * Return value: (element-type GDateTime*) + * (transfer full): + * the current time. + */ +GDateTime * +indicator_datetime_clock_get_current_time (IndicatorDatetimeClock * self) +{ + GDateTime * now; + IndicatorDatetimeClockInterface * iface; + + g_return_val_if_fail (INDICATOR_IS_DATETIME_CLOCK(self), NULL); + iface = INDICATOR_DATETIME_CLOCK_GET_INTERFACE(self); + + if (iface->get_current_time != NULL) + now = iface->get_current_time (self); + else + now = NULL; + + return now; +} + +/** + * Emits the "changed" signal. + * + * This should only be called by subclasses. + */ +void +indicator_datetime_clock_emit_changed (IndicatorDatetimeClock * self) +{ + g_return_if_fail (INDICATOR_IS_DATETIME_CLOCK (self)); + + g_signal_emit (self, signals[SIGNAL_CHANGED], 0, NULL); +} diff --git a/src/clock.h b/src/clock.h new file mode 100644 index 0000000..8932895 --- /dev/null +++ b/src/clock.h @@ -0,0 +1,76 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . + */ + +#ifndef __INDICATOR_DATETIME_CLOCK__H__ +#define __INDICATOR_DATETIME_CLOCK__H__ + +#include + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_DATETIME_CLOCK \ + (indicator_datetime_clock_get_type ()) + +#define INDICATOR_DATETIME_CLOCK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + INDICATOR_TYPE_DATETIME_CLOCK, \ + IndicatorDatetimeClock)) + +#define INDICATOR_IS_DATETIME_CLOCK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_TYPE_DATETIME_CLOCK)) + +#define INDICATOR_DATETIME_CLOCK_GET_INTERFACE(inst) \ + (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \ + INDICATOR_TYPE_DATETIME_CLOCK, \ + IndicatorDatetimeClockInterface)) + +typedef struct _IndicatorDatetimeClock + IndicatorDatetimeClock; + +typedef struct _IndicatorDatetimeClockInterface + IndicatorDatetimeClockInterface; + +struct _IndicatorDatetimeClockInterface +{ + GTypeInterface parent_iface; + + /* signals */ + void (*changed) (IndicatorDatetimeClock * self); + + /* virtual functions */ + gchar** (*get_timezones) (IndicatorDatetimeClock * self); + GDateTime* (*get_current_time) (IndicatorDatetimeClock * self); +}; + +GType indicator_datetime_clock_get_type (void); + +/*** +**** +***/ + +gchar ** indicator_datetime_clock_get_timezones (IndicatorDatetimeClock * clock); + +GDateTime * indicator_datetime_clock_get_current_time (IndicatorDatetimeClock * clock); + +void indicator_datetime_clock_emit_changed (IndicatorDatetimeClock * clock); + + +G_END_DECLS + +#endif /* __INDICATOR_DATETIME_CLOCK__H__ */ diff --git a/src/main.c b/src/main.c index f791683..9305794 100644 --- a/src/main.c +++ b/src/main.c @@ -26,36 +26,26 @@ #include #include +#include "clock-live.h" #include "planner-eds.h" -#include "planner-mock.h" #include "service.h" /*** **** ***/ -/* When enabled, new alarms will show up every minute to test snap decisions */ -static gboolean test_alarms = FALSE; - -static GOptionEntry entries[] = { - { "test-alarms", '\0', 0, G_OPTION_ARG_NONE, &test_alarms, "Test Alarms", NULL }, - { NULL } -}; - static void on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop) { g_message ("exiting: service couldn't acquire or lost ownership of busname"); - if (!test_alarms) - g_main_loop_quit ((GMainLoop*)loop); + g_main_loop_quit ((GMainLoop*)loop); } int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) { - GOptionContext * context; - GError * error; + IndicatorDatetimeClock * clock; IndicatorDatetimePlanner * planner; IndicatorDatetimeService * service; GMainLoop * loop; @@ -69,28 +59,10 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) if (!notify_init ("indicator-datetime-service")) g_critical ("libnotify initialization failed"); - /* parse command-line options */ - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); - if (!g_option_context_parse (context, &argc, &argv, &error)) - { - g_print("option parsing failed: %s\n", error->message); - return EXIT_FAILURE; - } - - /* set up the planner */ - if (test_alarms) - { - g_message ("Using fake appointment book for testing alarms."); - planner = indicator_datetime_planner_mock_new (); - } - else - { - planner = indicator_datetime_planner_eds_new (); - } - /* run */ - service = indicator_datetime_service_new (planner); + clock = indicator_datetime_clock_live_new (); + planner = indicator_datetime_planner_eds_new (); + service = indicator_datetime_service_new (clock, planner); loop = g_main_loop_new (NULL, FALSE); g_signal_connect (service, INDICATOR_DATETIME_SERVICE_SIGNAL_NAME_LOST, G_CALLBACK(on_name_lost), loop); @@ -100,5 +72,6 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) g_main_loop_unref (loop); g_object_unref (service); g_object_unref (planner); + g_object_unref (clock); return 0; } diff --git a/src/planner-mock.c b/src/planner-mock.c deleted file mode 100644 index e67ad7e..0000000 --- a/src/planner-mock.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2013 Canonical Ltd. - * - * Authors: - * Charles Kerr - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . - */ - -#include "config.h" - -#include "planner-mock.h" - -struct _IndicatorDatetimePlannerMockPriv -{ - gboolean is_configured; -}; - -typedef IndicatorDatetimePlannerMockPriv priv_t; - -G_DEFINE_TYPE (IndicatorDatetimePlannerMock, - indicator_datetime_planner_mock, - INDICATOR_TYPE_DATETIME_PLANNER) - -/*** -**** IndicatorDatetimePlanner virtual funcs -***/ - -static void -my_get_appointments (IndicatorDatetimePlanner * planner, - GDateTime * begin_datetime, - GDateTime * end_datetime G_GNUC_UNUSED, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask * task; - GSList * appointments; - struct IndicatorDatetimeAppt * appt; - struct IndicatorDatetimeAppt * prev; - - task = g_task_new (planner, NULL, callback, user_data); - - /** - *** Build the appointments list - **/ - - appointments = NULL; - - /* add a daily appointment that occurs at the beginning of the next minute */ - appt = g_slice_new0 (struct IndicatorDatetimeAppt); - appt->is_daily = TRUE; - appt->begin = g_date_time_add_seconds (begin_datetime, 60-g_date_time_get_seconds(begin_datetime)); - appt->end = g_date_time_add_minutes (appt->begin, 1); - appt->color = g_strdup ("#00FF00"); - appt->is_event = TRUE; - appt->summary = g_strdup ("Daily alarm"); - appt->uid = g_strdup ("this uid isn't very random."); - appt->has_alarms = TRUE; - appt->url = g_strdup ("alarm:///some-alarm-info-goes-here"); - appointments = g_slist_prepend (appointments, appt); - prev = appt; - - /* and add one for a minute later that has an alarm uri */ - appt = g_slice_new0 (struct IndicatorDatetimeAppt); - appt->is_daily = TRUE; - appt->begin = g_date_time_add_minutes (prev->end, 1); - appt->end = g_date_time_add_minutes (appt->begin, 1); - appt->color = g_strdup ("#0000FF"); - appt->is_event = TRUE; - appt->summary = g_strdup ("Second Daily alarm"); - appt->uid = g_strdup ("this uid isn't very random either."); - appt->has_alarms = FALSE; - appointments = g_slist_prepend (appointments, appt); - - /* done */ - g_task_return_pointer (task, appointments, NULL); - g_object_unref (task); -} - -static GSList * -my_get_appointments_finish (IndicatorDatetimePlanner * self G_GNUC_UNUSED, - GAsyncResult * res, - GError ** error) -{ - return g_task_propagate_pointer (G_TASK(res), error); -} - -static gboolean -my_is_configured (IndicatorDatetimePlanner * planner) -{ - IndicatorDatetimePlannerMock * self; - self = INDICATOR_DATETIME_PLANNER_MOCK (planner); - return self->priv->is_configured; -} - -static void -my_activate (IndicatorDatetimePlanner * self G_GNUC_UNUSED) -{ - g_message ("%s %s", G_STRLOC, G_STRFUNC); -} - -static void -my_activate_time (IndicatorDatetimePlanner * self G_GNUC_UNUSED, - GDateTime * activate_time) -{ - gchar * str = g_date_time_format (activate_time, "%F %T"); - g_message ("%s %s: %s", G_STRLOC, G_STRFUNC, str); - g_free (str); -} - -/*** -**** GObject virtual funcs -***/ - -static void -my_dispose (GObject * o) -{ - G_OBJECT_CLASS (indicator_datetime_planner_mock_parent_class)->dispose (o); -} - -/*** -**** Instantiation -***/ - -static void -indicator_datetime_planner_mock_class_init (IndicatorDatetimePlannerMockClass * klass) -{ - GObjectClass * object_class; - IndicatorDatetimePlannerClass * planner_class; - - object_class = G_OBJECT_CLASS (klass); - object_class->dispose = my_dispose; - - planner_class = INDICATOR_DATETIME_PLANNER_CLASS (klass); - planner_class->is_configured = my_is_configured; - planner_class->activate = my_activate; - planner_class->activate_time = my_activate_time; - planner_class->get_appointments = my_get_appointments; - planner_class->get_appointments_finish = my_get_appointments_finish; - - g_type_class_add_private (klass, sizeof (IndicatorDatetimePlannerMockPriv)); -} - -static void -indicator_datetime_planner_mock_init (IndicatorDatetimePlannerMock * self) -{ - priv_t * p; - - p = G_TYPE_INSTANCE_GET_PRIVATE (self, - INDICATOR_TYPE_DATETIME_PLANNER_MOCK, - IndicatorDatetimePlannerMockPriv); - - p->is_configured = TRUE; - - self->priv = p; -} - -/*** -**** Public -***/ - -IndicatorDatetimePlanner * -indicator_datetime_planner_mock_new (void) -{ - gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_PLANNER_MOCK, NULL); - - return INDICATOR_DATETIME_PLANNER (o); -} diff --git a/src/planner-mock.h b/src/planner-mock.h deleted file mode 100644 index 8d7d7c2..0000000 --- a/src/planner-mock.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2013 Canonical Ltd. - * - * Authors: - * Charles Kerr - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . - */ - -#ifndef __INDICATOR_DATETIME_PLANNER_MOCK__H__ -#define __INDICATOR_DATETIME_PLANNER_MOCK__H__ - -#include "planner.h" /* parent class */ - -G_BEGIN_DECLS - -#define INDICATOR_TYPE_DATETIME_PLANNER_MOCK (indicator_datetime_planner_mock_get_type()) -#define INDICATOR_DATETIME_PLANNER_MOCK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK, IndicatorDatetimePlannerMock)) -#define INDICATOR_DATETIME_PLANNER_MOCK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK, IndicatorDatetimePlannerMockClass)) -#define INDICATOR_IS_DATETIME_PLANNER_MOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK)) - -typedef struct _IndicatorDatetimePlannerMock IndicatorDatetimePlannerMock; -typedef struct _IndicatorDatetimePlannerMockPriv IndicatorDatetimePlannerMockPriv; -typedef struct _IndicatorDatetimePlannerMockClass IndicatorDatetimePlannerMockClass; - -GType indicator_datetime_planner_mock_get_type (void); - -/** - * An IndicatorDatetimePlanner which uses Evolution Data Server - * to get its list of appointments. - */ -struct _IndicatorDatetimePlannerMock -{ - /*< private >*/ - IndicatorDatetimePlanner parent; - IndicatorDatetimePlannerMockPriv * priv; -}; - -struct _IndicatorDatetimePlannerMockClass -{ - IndicatorDatetimePlannerClass parent_class; -}; - -IndicatorDatetimePlanner * indicator_datetime_planner_mock_new (void); - -G_END_DECLS - -#endif /* __INDICATOR_DATETIME_PLANNER_MOCK__H__ */ diff --git a/src/service.c b/src/service.c index 08945bc..b777b8c 100644 --- a/src/service.c +++ b/src/service.c @@ -29,8 +29,6 @@ #include #include "dbus-shared.h" -#include "timezone-file.h" -#include "timezone-geoclue.h" #include "service.h" #include "settings-shared.h" #include "utils.h" @@ -54,6 +52,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, + PROP_CLOCK, PROP_PLANNER, PROP_LAST }; @@ -101,13 +100,9 @@ struct _IndicatorDatetimeServicePrivate GSettings * settings; - IndicatorDatetimeTimezone * tz_file; - IndicatorDatetimeTimezone * tz_geoclue; + IndicatorDatetimeClock * clock; IndicatorDatetimePlanner * planner; - /* cached GTimeZone for use by indicator_datetime_service_get_localtime() */ - GTimeZone * internal_timezone; - /* the clock app's icon filename */ gchar * clock_app_icon_filename; @@ -168,6 +163,12 @@ indicator_clear_timer (guint * tag) } } +static inline GDateTime * +indicator_datetime_service_get_localtime (IndicatorDatetimeService * self) +{ + return indicator_datetime_clock_get_current_time (self->priv->clock); +} + /*** **** ***/ @@ -589,23 +590,6 @@ set_alarm_timer (IndicatorDatetimeService * self) **** ***/ -static void -update_internal_timezone (IndicatorDatetimeService * self) -{ - priv_t * p = self->priv; - const char * id; - - /* find the id from tz_file or tz_geoclue if possible; NULL otherwise */ - id = NULL; - if (!id && p->tz_file) - id = indicator_datetime_timezone_get_timezone (p->tz_file); - if (!id && p->tz_geoclue) - id = indicator_datetime_timezone_get_timezone (p->tz_geoclue); - - g_clear_pointer (&p->internal_timezone, g_time_zone_unref); - p->internal_timezone = g_time_zone_new (id); -} - /** * General purpose handler for rebuilding sections and restarting their timers * when time jumps for whatever reason: @@ -624,7 +608,6 @@ on_local_time_jumped (IndicatorDatetimeService * self) 1. rebuild the necessary states / menuitems when time jumps 2. restart the timers so their new wait interval is correct */ - update_internal_timezone (self); on_header_timer (self); on_timezone_timer (self); } @@ -1100,61 +1083,6 @@ create_desktop_appointments_section (IndicatorDatetimeService * self) **** ***/ -static void -on_current_timezone_changed (IndicatorDatetimeService * self) -{ - on_local_time_jumped (self); -} - -/* When the 'auto-detect timezone' boolean setting changes, - start or stop watching geoclue and /etc/timezone */ -static void -set_detect_location_enabled (IndicatorDatetimeService * self, gboolean enabled) -{ - gboolean changed = FALSE; - priv_t * p = self->priv; - - /* geoclue */ - - if (!p->tz_geoclue && enabled) - { - p->tz_geoclue = indicator_datetime_timezone_geoclue_new (); - g_signal_connect_swapped (p->tz_geoclue, "notify::timezone", - G_CALLBACK(on_current_timezone_changed), - self); - changed = TRUE; - } - else if (p->tz_geoclue && !enabled) - { - g_signal_handlers_disconnect_by_func (p->tz_geoclue, - on_current_timezone_changed, - self); - g_clear_object (&p->tz_geoclue); - changed = TRUE; - } - - /* timezone file */ - - if (!p->tz_file && enabled) - { - p->tz_file = indicator_datetime_timezone_file_new (TIMEZONE_FILE); - g_signal_connect_swapped (p->tz_file, "notify::timezone", - G_CALLBACK(on_current_timezone_changed), - self); - changed = TRUE; - } - else if (p->tz_file && !enabled) - { - g_signal_handlers_disconnect_by_func (p->tz_file, - on_current_timezone_changed, - self); - g_clear_object (&p->tz_file); - changed = TRUE; - } - - if (changed) - on_current_timezone_changed (self); -} /* A temp struct used by create_locations_section() for pruning duplicates and sorting. */ @@ -1240,44 +1168,30 @@ create_locations_section (IndicatorDatetimeService * self) GSList * l; GSList * locations = NULL; gchar ** user_locations; - gboolean visible; - IndicatorDatetimeTimezone * detected_timezones[2]; + gchar ** detected_timezones; priv_t * p = self->priv; GDateTime * now = indicator_datetime_service_get_localtime (self); - set_detect_location_enabled (self, - g_settings_get_boolean (p->settings, SETTINGS_SHOW_DETECTED_S)); - menu = g_menu_new (); /*** - **** Build a list of locations to add: use geo_timezone, - **** current_timezone, and SETTINGS_LOCATIONS_S, but omit duplicates. + **** Build a list of locations to add, omitting duplicates ***/ - /* maybe add the auto-detected timezones */ - detected_timezones[0] = p->tz_geoclue; - detected_timezones[1] = p->tz_file; - visible = g_settings_get_boolean (p->settings, SETTINGS_SHOW_DETECTED_S); - for (i=0; iclock); + for (i=0; detected_timezones && detected_timezones[i]; i++) { - if (detected_timezones[i] != NULL) - { - const char * tz = indicator_datetime_timezone_get_timezone (detected_timezones[i]); - if (tz && *tz) - { - gchar * name = get_current_zone_name (tz, p->settings); - locations = locations_add (locations, tz, name, visible); - g_free (name); - } - } + const char * tz = detected_timezones[i]; + gchar * name = get_current_zone_name (tz, p->settings); + locations = locations_add (locations, tz, name, TRUE); } + g_strfreev (detected_timezones); /* maybe add the user-specified locations */ user_locations = g_settings_get_strv (p->settings, SETTINGS_LOCATIONS_S); if (user_locations != NULL) { - visible = g_settings_get_boolean (p->settings, SETTINGS_SHOW_LOCATIONS_S); + const gboolean visible = g_settings_get_boolean (p->settings, SETTINGS_SHOW_LOCATIONS_S); for (i=0; user_locations[i] != NULL; i++) { @@ -1735,6 +1649,9 @@ rebuild_now (IndicatorDatetimeService * self, int sections) struct ProfileMenuInfo * desktop = &p->menus[PROFILE_DESKTOP]; struct ProfileMenuInfo * greeter = &p->menus[PROFILE_GREETER]; + if (p->actions == NULL) + return; + if (sections & SECTION_HEADER) { g_simple_action_set_state (p->desktop_header_action, @@ -2088,6 +2005,10 @@ my_get_property (GObject * o, switch (property_id) { + case PROP_CLOCK: + g_value_set_object (value, self->priv->clock); + break; + case PROP_PLANNER: g_value_set_object (value, self->priv->planner); break; @@ -2107,6 +2028,10 @@ my_set_property (GObject * o, switch (property_id) { + case PROP_CLOCK: + indicator_datetime_service_set_clock (self, g_value_get_object (value)); + break; + case PROP_PLANNER: indicator_datetime_service_set_planner (self, g_value_get_object (value)); break; @@ -2138,8 +2063,7 @@ my_dispose (GObject * o) g_clear_object (&p->cancellable); } - set_detect_location_enabled (self, FALSE); - + indicator_datetime_service_set_clock (self, NULL); indicator_datetime_service_set_planner (self, NULL); if (p->login1_manager != NULL) @@ -2165,7 +2089,6 @@ my_dispose (GObject * o) for (i=0; imenus[i].menu); - g_clear_pointer (&p->internal_timezone, g_time_zone_unref); g_clear_object (&p->calendar_action); g_clear_object (&p->desktop_header_action); g_clear_object (&p->phone_header_action); @@ -2194,9 +2117,27 @@ my_finalize (GObject * o) static void indicator_datetime_service_init (IndicatorDatetimeService * self) { - guint i, n; priv_t * p; + + /* init the priv pointer */ + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_DATETIME_SERVICE, + IndicatorDatetimeServicePrivate); + self->priv = p; + + p->cancellable = g_cancellable_new (); + + p->settings = g_settings_new (SETTINGS_INTERFACE); +} + +static void +my_constructed (GObject * gself) +{ + IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself); + priv_t * p = self->priv; GString * gstr = g_string_new (NULL); + guint i, n; /* these are the settings that affect the contents of the respective sections */ @@ -2233,20 +2174,10 @@ indicator_datetime_service_init (IndicatorDatetimeService * self) }; - /* init the priv pointer */ - - p = G_TYPE_INSTANCE_GET_PRIVATE (self, - INDICATOR_TYPE_DATETIME_SERVICE, - IndicatorDatetimeServicePrivate); - self->priv = p; - - p->cancellable = g_cancellable_new (); - /*** - **** Create the settings object and listen for changes + **** Listen for settings changes ***/ - p->settings = g_settings_new (SETTINGS_INTERFACE); for (i=0, n=G_N_ELEMENTS(header_settings); idispose = my_dispose; object_class->finalize = my_finalize; + object_class->constructed = my_constructed; object_class->get_property = my_get_property; object_class->set_property = my_set_property; @@ -2345,6 +2277,12 @@ indicator_datetime_service_class_init (IndicatorDatetimeServiceClass * klass) properties[PROP_0] = NULL; + properties[PROP_CLOCK] = g_param_spec_object ("clock", + "Clock", + "The clock", + G_TYPE_OBJECT, + flags); + properties[PROP_PLANNER] = g_param_spec_object ("planner", "Planner", "The appointment provider", @@ -2359,28 +2297,17 @@ indicator_datetime_service_class_init (IndicatorDatetimeServiceClass * klass) ***/ IndicatorDatetimeService * -indicator_datetime_service_new (IndicatorDatetimePlanner * planner) +indicator_datetime_service_new (IndicatorDatetimeClock * clock, + IndicatorDatetimePlanner * planner) { GObject * o = g_object_new (INDICATOR_TYPE_DATETIME_SERVICE, + "clock", clock, "planner", planner, NULL); return INDICATOR_DATETIME_SERVICE (o); } -/* This currently just returns the system time, - As we add test coverage, we'll need this to bypass the system time. */ -GDateTime * -indicator_datetime_service_get_localtime (IndicatorDatetimeService * self) -{ - priv_t * p = self->priv; - - if (G_UNLIKELY (p->internal_timezone == NULL)) - update_internal_timezone (self); - - return g_date_time_new_now (p->internal_timezone); -} - void indicator_datetime_service_set_calendar_date (IndicatorDatetimeService * self, GDateTime * date) @@ -2400,6 +2327,43 @@ indicator_datetime_service_set_calendar_date (IndicatorDatetimeService * self, update_appointment_lists (self); } +static void +on_clock_changed (IndicatorDatetimeService * self) +{ + on_local_time_jumped (self); +} + +void +indicator_datetime_service_set_clock (IndicatorDatetimeService * self, + IndicatorDatetimeClock * clock) +{ + priv_t * p; + + g_return_if_fail (INDICATOR_IS_DATETIME_SERVICE (self)); + g_return_if_fail ((clock == NULL) || INDICATOR_IS_DATETIME_CLOCK (clock)); + + p = self->priv; + + /* clear the old clock */ + + if (p->clock != NULL) + { + g_signal_handlers_disconnect_by_data (p->clock, self); + g_clear_object (&p->clock); + } + + /* set the new clock */ + + if (clock != NULL) + { + p->clock = g_object_ref (clock); + + g_signal_connect_swapped (p->clock, "changed", + G_CALLBACK(on_clock_changed), self); + on_clock_changed (self); + } +} + void indicator_datetime_service_set_planner (IndicatorDatetimeService * self, IndicatorDatetimePlanner * planner) @@ -2407,7 +2371,7 @@ indicator_datetime_service_set_planner (IndicatorDatetimeService * self, priv_t * p; g_return_if_fail (INDICATOR_IS_DATETIME_SERVICE (self)); - g_return_if_fail (INDICATOR_IS_DATETIME_PLANNER (planner)); + g_return_if_fail ((planner == NULL) || INDICATOR_IS_DATETIME_PLANNER (planner)); p = self->priv; diff --git a/src/service.h b/src/service.h index 25bb59a..d38db72 100644 --- a/src/service.h +++ b/src/service.h @@ -22,6 +22,8 @@ #include #include + +#include "clock.h" #include "planner.h" G_BEGIN_DECLS @@ -63,9 +65,8 @@ struct _IndicatorDatetimeServiceClass GType indicator_datetime_service_get_type (void); -IndicatorDatetimeService * indicator_datetime_service_new (IndicatorDatetimePlanner * planner); - -GDateTime * indicator_datetime_service_get_localtime (IndicatorDatetimeService * service); +IndicatorDatetimeService * indicator_datetime_service_new (IndicatorDatetimeClock * clock, + IndicatorDatetimePlanner * planner); void indicator_datetime_service_set_calendar_date (IndicatorDatetimeService * self, GDateTime * date); @@ -74,6 +75,9 @@ void indicator_datetime_service_set_planner (IndicatorDatetimeService * self, IndicatorDatetimePlanner * planner); +void indicator_datetime_service_set_clock (IndicatorDatetimeService * self, + IndicatorDatetimeClock * clock); + G_END_DECLS diff --git a/tests/planner-mock.c b/tests/planner-mock.c new file mode 100644 index 0000000..e67ad7e --- /dev/null +++ b/tests/planner-mock.c @@ -0,0 +1,178 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . + */ + +#include "config.h" + +#include "planner-mock.h" + +struct _IndicatorDatetimePlannerMockPriv +{ + gboolean is_configured; +}; + +typedef IndicatorDatetimePlannerMockPriv priv_t; + +G_DEFINE_TYPE (IndicatorDatetimePlannerMock, + indicator_datetime_planner_mock, + INDICATOR_TYPE_DATETIME_PLANNER) + +/*** +**** IndicatorDatetimePlanner virtual funcs +***/ + +static void +my_get_appointments (IndicatorDatetimePlanner * planner, + GDateTime * begin_datetime, + GDateTime * end_datetime G_GNUC_UNUSED, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask * task; + GSList * appointments; + struct IndicatorDatetimeAppt * appt; + struct IndicatorDatetimeAppt * prev; + + task = g_task_new (planner, NULL, callback, user_data); + + /** + *** Build the appointments list + **/ + + appointments = NULL; + + /* add a daily appointment that occurs at the beginning of the next minute */ + appt = g_slice_new0 (struct IndicatorDatetimeAppt); + appt->is_daily = TRUE; + appt->begin = g_date_time_add_seconds (begin_datetime, 60-g_date_time_get_seconds(begin_datetime)); + appt->end = g_date_time_add_minutes (appt->begin, 1); + appt->color = g_strdup ("#00FF00"); + appt->is_event = TRUE; + appt->summary = g_strdup ("Daily alarm"); + appt->uid = g_strdup ("this uid isn't very random."); + appt->has_alarms = TRUE; + appt->url = g_strdup ("alarm:///some-alarm-info-goes-here"); + appointments = g_slist_prepend (appointments, appt); + prev = appt; + + /* and add one for a minute later that has an alarm uri */ + appt = g_slice_new0 (struct IndicatorDatetimeAppt); + appt->is_daily = TRUE; + appt->begin = g_date_time_add_minutes (prev->end, 1); + appt->end = g_date_time_add_minutes (appt->begin, 1); + appt->color = g_strdup ("#0000FF"); + appt->is_event = TRUE; + appt->summary = g_strdup ("Second Daily alarm"); + appt->uid = g_strdup ("this uid isn't very random either."); + appt->has_alarms = FALSE; + appointments = g_slist_prepend (appointments, appt); + + /* done */ + g_task_return_pointer (task, appointments, NULL); + g_object_unref (task); +} + +static GSList * +my_get_appointments_finish (IndicatorDatetimePlanner * self G_GNUC_UNUSED, + GAsyncResult * res, + GError ** error) +{ + return g_task_propagate_pointer (G_TASK(res), error); +} + +static gboolean +my_is_configured (IndicatorDatetimePlanner * planner) +{ + IndicatorDatetimePlannerMock * self; + self = INDICATOR_DATETIME_PLANNER_MOCK (planner); + return self->priv->is_configured; +} + +static void +my_activate (IndicatorDatetimePlanner * self G_GNUC_UNUSED) +{ + g_message ("%s %s", G_STRLOC, G_STRFUNC); +} + +static void +my_activate_time (IndicatorDatetimePlanner * self G_GNUC_UNUSED, + GDateTime * activate_time) +{ + gchar * str = g_date_time_format (activate_time, "%F %T"); + g_message ("%s %s: %s", G_STRLOC, G_STRFUNC, str); + g_free (str); +} + +/*** +**** GObject virtual funcs +***/ + +static void +my_dispose (GObject * o) +{ + G_OBJECT_CLASS (indicator_datetime_planner_mock_parent_class)->dispose (o); +} + +/*** +**** Instantiation +***/ + +static void +indicator_datetime_planner_mock_class_init (IndicatorDatetimePlannerMockClass * klass) +{ + GObjectClass * object_class; + IndicatorDatetimePlannerClass * planner_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + + planner_class = INDICATOR_DATETIME_PLANNER_CLASS (klass); + planner_class->is_configured = my_is_configured; + planner_class->activate = my_activate; + planner_class->activate_time = my_activate_time; + planner_class->get_appointments = my_get_appointments; + planner_class->get_appointments_finish = my_get_appointments_finish; + + g_type_class_add_private (klass, sizeof (IndicatorDatetimePlannerMockPriv)); +} + +static void +indicator_datetime_planner_mock_init (IndicatorDatetimePlannerMock * self) +{ + priv_t * p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_DATETIME_PLANNER_MOCK, + IndicatorDatetimePlannerMockPriv); + + p->is_configured = TRUE; + + self->priv = p; +} + +/*** +**** Public +***/ + +IndicatorDatetimePlanner * +indicator_datetime_planner_mock_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_PLANNER_MOCK, NULL); + + return INDICATOR_DATETIME_PLANNER (o); +} diff --git a/tests/planner-mock.h b/tests/planner-mock.h new file mode 100644 index 0000000..8d7d7c2 --- /dev/null +++ b/tests/planner-mock.h @@ -0,0 +1,58 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . + */ + +#ifndef __INDICATOR_DATETIME_PLANNER_MOCK__H__ +#define __INDICATOR_DATETIME_PLANNER_MOCK__H__ + +#include "planner.h" /* parent class */ + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_DATETIME_PLANNER_MOCK (indicator_datetime_planner_mock_get_type()) +#define INDICATOR_DATETIME_PLANNER_MOCK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK, IndicatorDatetimePlannerMock)) +#define INDICATOR_DATETIME_PLANNER_MOCK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK, IndicatorDatetimePlannerMockClass)) +#define INDICATOR_IS_DATETIME_PLANNER_MOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_PLANNER_MOCK)) + +typedef struct _IndicatorDatetimePlannerMock IndicatorDatetimePlannerMock; +typedef struct _IndicatorDatetimePlannerMockPriv IndicatorDatetimePlannerMockPriv; +typedef struct _IndicatorDatetimePlannerMockClass IndicatorDatetimePlannerMockClass; + +GType indicator_datetime_planner_mock_get_type (void); + +/** + * An IndicatorDatetimePlanner which uses Evolution Data Server + * to get its list of appointments. + */ +struct _IndicatorDatetimePlannerMock +{ + /*< private >*/ + IndicatorDatetimePlanner parent; + IndicatorDatetimePlannerMockPriv * priv; +}; + +struct _IndicatorDatetimePlannerMockClass +{ + IndicatorDatetimePlannerClass parent_class; +}; + +IndicatorDatetimePlanner * indicator_datetime_planner_mock_new (void); + +G_END_DECLS + +#endif /* __INDICATOR_DATETIME_PLANNER_MOCK__H__ */ -- cgit v1.2.3 From 758a4880f645242f1c7753990dc46f880a7e9de8 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 17 Oct 2013 17:48:06 -0500 Subject: cleanup: dead code removal, fix comments, smaller implementation of update_internal_localtime() --- src/clock-live.c | 47 ++++++++++++++--------------------------------- src/clock.c | 6 +++--- src/clock.h | 4 ++-- src/main.c | 6 ++++-- src/service.c | 2 +- 5 files changed, 24 insertions(+), 41 deletions(-) (limited to 'src/main.c') diff --git a/src/clock-live.c b/src/clock-live.c index 6e694ed..564d990 100644 --- a/src/clock-live.c +++ b/src/clock-live.c @@ -35,7 +35,7 @@ struct _IndicatorDatetimeClockLivePriv { GSettings * settings; - /* cached GTimeZone for use by indicator_datetime_service_get_localtime() */ + /* cached GTimeZone for use by get_localtime() */ GTimeZone * internal_timezone; IndicatorDatetimeTimezone * tz_file; @@ -58,39 +58,10 @@ G_DEFINE_TYPE_WITH_CODE ( G_IMPLEMENT_INTERFACE (INDICATOR_TYPE_DATETIME_CLOCK, indicator_datetime_clock_interface_init)); -/*** -**** Convenience func -***/ - -#if 0 -static void -emit_changed (IndicatorDatetimeClockLive * self) -{ - indicator_datetime_clock_emit_changed (INDICATOR_DATETIME_CLOCK (self)); -} -#endif - /*** **** Timezones ***/ -static void -update_internal_timezone (IndicatorDatetimeClockLive * self) -{ - priv_t * p = self->priv; - const char * id; - - /* find the id from tz_file or tz_geoclue if possible; NULL otherwise */ - id = NULL; - if (p->tz_file != NULL ) - id = indicator_datetime_timezone_get_timezone (p->tz_file); - if (!id && p->tz_geoclue) - id = indicator_datetime_timezone_get_timezone (p->tz_geoclue); - - g_clear_pointer (&p->internal_timezone, g_time_zone_unref); - p->internal_timezone = g_time_zone_new (id); -} - static void on_current_timezone_changed (IndicatorDatetimeClockLive * self) { @@ -159,7 +130,7 @@ on_detect_location_changed (IndicatorDatetimeClockLive * self) ***/ static gchar ** -my_get_timezones (IndicatorDatetimeClock * clock G_GNUC_UNUSED) +my_get_timezones (IndicatorDatetimeClock * clock) { IndicatorDatetimeClockLive * self; priv_t * p; @@ -197,8 +168,18 @@ my_get_timezones (IndicatorDatetimeClock * clock G_GNUC_UNUSED) return timezones; } +static void +update_internal_timezone (IndicatorDatetimeClockLive * self) +{ + priv_t * p = self->priv; + gchar ** timezones = my_get_timezones (INDICATOR_DATETIME_CLOCK (self)); + g_clear_pointer (&p->internal_timezone, g_time_zone_unref); + p->internal_timezone = g_time_zone_new (timezones ? timezones[0] : NULL); + g_strfreev (timezones); +} + static GDateTime * -my_get_current_time (IndicatorDatetimeClock * clock) +my_get_localtime (IndicatorDatetimeClock * clock) { IndicatorDatetimeClockLive * self; priv_t * p; @@ -271,8 +252,8 @@ indicator_datetime_clock_live_class_init (IndicatorDatetimeClockLiveClass * klas static void indicator_datetime_clock_interface_init (IndicatorDatetimeClockInterface * iface) { + iface->get_localtime = my_get_localtime; iface->get_timezones = my_get_timezones; - iface->get_current_time = my_get_current_time; } static void diff --git a/src/clock.c b/src/clock.c index 1abdd21..a5cefee 100644 --- a/src/clock.c +++ b/src/clock.c @@ -80,7 +80,7 @@ indicator_datetime_clock_get_timezones (IndicatorDatetimeClock * self) * the current time. */ GDateTime * -indicator_datetime_clock_get_current_time (IndicatorDatetimeClock * self) +indicator_datetime_clock_get_localtime (IndicatorDatetimeClock * self) { GDateTime * now; IndicatorDatetimeClockInterface * iface; @@ -88,8 +88,8 @@ indicator_datetime_clock_get_current_time (IndicatorDatetimeClock * self) g_return_val_if_fail (INDICATOR_IS_DATETIME_CLOCK(self), NULL); iface = INDICATOR_DATETIME_CLOCK_GET_INTERFACE(self); - if (iface->get_current_time != NULL) - now = iface->get_current_time (self); + if (iface->get_localtime != NULL) + now = iface->get_localtime (self); else now = NULL; diff --git a/src/clock.h b/src/clock.h index 8932895..0c10dab 100644 --- a/src/clock.h +++ b/src/clock.h @@ -55,7 +55,7 @@ struct _IndicatorDatetimeClockInterface /* virtual functions */ gchar** (*get_timezones) (IndicatorDatetimeClock * self); - GDateTime* (*get_current_time) (IndicatorDatetimeClock * self); + GDateTime* (*get_localtime) (IndicatorDatetimeClock * self); }; GType indicator_datetime_clock_get_type (void); @@ -66,7 +66,7 @@ GType indicator_datetime_clock_get_type (void); gchar ** indicator_datetime_clock_get_timezones (IndicatorDatetimeClock * clock); -GDateTime * indicator_datetime_clock_get_current_time (IndicatorDatetimeClock * clock); +GDateTime * indicator_datetime_clock_get_localtime (IndicatorDatetimeClock * clock); void indicator_datetime_clock_emit_changed (IndicatorDatetimeClock * clock); diff --git a/src/main.c b/src/main.c index 9305794..dc08419 100644 --- a/src/main.c +++ b/src/main.c @@ -59,17 +59,19 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) if (!notify_init ("indicator-datetime-service")) g_critical ("libnotify initialization failed"); - /* run */ + /* create the service */ clock = indicator_datetime_clock_live_new (); planner = indicator_datetime_planner_eds_new (); service = indicator_datetime_service_new (clock, planner); + + /* run */ loop = g_main_loop_new (NULL, FALSE); g_signal_connect (service, INDICATOR_DATETIME_SERVICE_SIGNAL_NAME_LOST, G_CALLBACK(on_name_lost), loop); g_main_loop_run (loop); + g_main_loop_unref (loop); /* cleanup */ - g_main_loop_unref (loop); g_object_unref (service); g_object_unref (planner); g_object_unref (clock); diff --git a/src/service.c b/src/service.c index b777b8c..f2b0b34 100644 --- a/src/service.c +++ b/src/service.c @@ -166,7 +166,7 @@ indicator_clear_timer (guint * tag) static inline GDateTime * indicator_datetime_service_get_localtime (IndicatorDatetimeService * self) { - return indicator_datetime_clock_get_current_time (self->priv->clock); + return indicator_datetime_clock_get_localtime (self->priv->clock); } /*** -- cgit v1.2.3