aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/service.c2432
1 files changed, 0 insertions, 2432 deletions
diff --git a/src/service.c b/src/service.c
deleted file mode 100644
index 7176ef1..0000000
--- a/src/service.c
+++ /dev/null
@@ -1,2432 +0,0 @@
-/*
- * Copyright 2013 Canonical Ltd.
- *
- * Authors:
- * Charles Kerr <charles.kerr@canonical.com>
- * Ted Gould <ted@canonical.com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <string.h> /* strstr() */
-
-#include <glib/gi18n.h>
-#include <gio/gio.h>
-#include <libnotify/notify.h>
-#include <json-glib/json-glib.h>
-#include <url-dispatcher.h>
-
-#include "dbus-shared.h"
-#include "service.h"
-#include "settings-shared.h"
-#include "utils.h"
-
-#define SKEW_CHECK_INTERVAL_SEC 10
-#define SKEW_DIFF_THRESHOLD_USEC ((SKEW_CHECK_INTERVAL_SEC+5) * G_USEC_PER_SEC)
-#define ALARM_CLOCK_ICON_NAME "alarm-clock"
-
-G_DEFINE_TYPE (IndicatorDatetimeService,
- indicator_datetime_service,
- G_TYPE_OBJECT)
-
-enum
-{
- SIGNAL_NAME_LOST,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-enum
-{
- PROP_0,
- PROP_CLOCK,
- PROP_PLANNER,
- PROP_LAST
-};
-
-static GParamSpec * properties[PROP_LAST] = { 0 };
-
-enum
-{
- SECTION_HEADER = (1<<0),
- SECTION_CALENDAR = (1<<1),
- SECTION_APPOINTMENTS = (1<<2),
- SECTION_LOCATIONS = (1<<3),
- SECTION_SETTINGS = (1<<4),
-};
-
-enum
-{
- PROFILE_PHONE,
- PROFILE_DESKTOP,
- PROFILE_GREETER,
- N_PROFILES
-};
-
-static const char * const menu_names[N_PROFILES] =
-{
- "phone",
- "desktop",
- "desktop_greeter"
-};
-
-struct ProfileMenuInfo
-{
- /* the root level -- the header is the only child of this */
- GMenu * menu;
-
- /* parent of the sections. This is the header's submenu */
- GMenu * submenu;
-
- guint export_id;
-};
-
-struct _IndicatorDatetimeServicePrivate
-{
- GCancellable * cancellable;
-
- GSettings * settings;
-
- IndicatorDatetimeClock * clock;
- IndicatorDatetimePlanner * planner;
-
- gchar * header_label_format_string;
-
- guint own_id;
- guint actions_export_id;
- GDBusConnection * conn;
-
- guint rebuild_id;
- int rebuild_flags;
- struct ProfileMenuInfo menus[N_PROFILES];
-
- GDateTime * skew_time;
- guint skew_timer;
-
- guint header_timer;
- guint timezone_timer;
- guint alarm_timer;
-
- /* Which year/month to show in the calendar,
- and which day should get the cursor.
- This value is reflected in the calendar action's state */
- GDateTime * calendar_date;
-
- GSimpleActionGroup * actions;
- GSimpleAction * phone_header_action;
- GSimpleAction * desktop_header_action;
- GSimpleAction * calendar_action;
-
- GDBusProxy * login1_manager;
-
- /* all the appointments in the selected calendar_date's month.
- Used when populating the 'appointment-days' entry in
- create_calendar_state() */
- GSList * calendar_appointments;
-
- /* appointments over the next few weeks.
- Used when building SECTION_APPOINTMENTS */
- GSList * upcoming_appointments;
-
- /* serialized icon cache */
- GVariant * alarm_icon_serialized;
- GVariant * calendar_icon_serialized;
- GVariant * clock_app_icon_serialized;
-};
-
-typedef IndicatorDatetimeServicePrivate priv_t;
-
-/***
-****
-***/
-
-static void
-indicator_clear_timer (guint * tag)
-{
- if (*tag)
- {
- g_source_remove (*tag);
- *tag = 0;
- }
-}
-
-static inline GDateTime *
-indicator_datetime_service_get_localtime (IndicatorDatetimeService * self)
-{
- return indicator_datetime_clock_get_localtime (self->priv->clock);
-}
-
-/***
-****
-***/
-
-static void rebuild_now (IndicatorDatetimeService * self, int section);
-static void rebuild_soon (IndicatorDatetimeService * self, int section);
-
-static inline void
-rebuild_header_soon (IndicatorDatetimeService * self)
-{
- g_clear_pointer (&self->priv->header_label_format_string, g_free);
-
- rebuild_soon (self, SECTION_HEADER);
-}
-
-static inline void
-rebuild_calendar_section_soon (IndicatorDatetimeService * self)
-{
- rebuild_soon (self, SECTION_CALENDAR);
-}
-
-static inline void
-rebuild_appointments_section_soon (IndicatorDatetimeService * self)
-{
- rebuild_soon (self, SECTION_APPOINTMENTS);
-}
-
-static inline void
-rebuild_locations_section_soon (IndicatorDatetimeService * self)
-{
- rebuild_soon (self, SECTION_LOCATIONS);
-}
-
-static inline void
-rebuild_settings_section_soon (IndicatorDatetimeService * self)
-{
- rebuild_soon (self, SECTION_SETTINGS);
-}
-
-/***
-**** TIMEZONE TIMER
-***/
-
-/*
- * Periodically rebuild the sections that have time format strings
- * that are dependent on the current time:
- *
- * 1. appointment menuitems' time format strings depend on the
- * current time; for example, they don't show the day of week
- * if the appointment is today.
- *
- * 2. location menuitems' time format strings depend on the
- * current time; for example, they don't show the day of the week
- * if the local date and location date are the same.
- *
- * 3. the "local date" menuitem in the calendar section is,
- * obviously, dependent on the local time.
- *
- * In short, we want to update whenever the number of days between two zone
- * might have changed. We do that by updating when either zone's day changes.
- *
- * Since not all UTC offsets are evenly divisible by hours
- * (examples: Newfoundland UTC-03:30, Nepal UTC+05:45), refreshing on the hour
- * is not enough. We need to refresh at HH:00, HH:15, HH:30, and HH:45.
- */
-
-static guint
-calculate_seconds_until_next_fifteen_minutes (GDateTime * now)
-{
- char * str;
- gint minute;
- guint seconds;
- GTimeSpan diff;
- GDateTime * next;
- GDateTime * start_of_next;
-
- minute = g_date_time_get_minute (now);
- minute = 15 - (minute % 15);
- next = g_date_time_add_minutes (now, minute);
- start_of_next = g_date_time_new_local (g_date_time_get_year (next),
- g_date_time_get_month (next),
- g_date_time_get_day_of_month (next),
- g_date_time_get_hour (next),
- g_date_time_get_minute (next),
- 0.1);
-
- str = g_date_time_format (start_of_next, "%F %T");
- g_debug ("%s %s the next timestamp rebuild will be at %s", G_STRLOC, G_STRFUNC, str);
- g_free (str);
-
- diff = g_date_time_difference (start_of_next, now);
- seconds = (diff + (G_TIME_SPAN_SECOND-1)) / G_TIME_SPAN_SECOND;
-
- g_date_time_unref (start_of_next);
- g_date_time_unref (next);
-
- return seconds;
-}
-
-static void start_timezone_timer (IndicatorDatetimeService * self);
-
-static gboolean
-on_timezone_timer (gpointer gself)
-{
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself);
-
- rebuild_soon (self, SECTION_CALENDAR |
- SECTION_APPOINTMENTS |
- SECTION_LOCATIONS);
-
- /* Restarting the timer to recalculate the interval. This helps us to hit
- our marks despite clock skew, suspend+resume, leap seconds, etc */
- start_timezone_timer (self);
- return G_SOURCE_REMOVE;
-}
-
-static void
-start_timezone_timer (IndicatorDatetimeService * self)
-{
- GDateTime * now;
- guint seconds;
- priv_t * p = self->priv;
-
- indicator_clear_timer (&p->timezone_timer);
-
- now = indicator_datetime_service_get_localtime (self);
- seconds = calculate_seconds_until_next_fifteen_minutes (now);
- p->timezone_timer = g_timeout_add_seconds (seconds, on_timezone_timer, self);
- g_date_time_unref (now);
-}
-
-/***
-**** HEADER TIMER
-***/
-
-/*
- * This is to periodically rebuild the header's action's state.
- *
- * If the label shows seconds, update when we reach the next second.
- * Otherwise, update when we reach the next minute.
- */
-
-static guint
-calculate_milliseconds_until_next_minute (GDateTime * now)
-{
- GDateTime * next;
- GDateTime * start_of_next;
- GTimeSpan interval_usec;
- guint interval_msec;
-
- next = g_date_time_add_minutes (now, 1);
- start_of_next = g_date_time_new_local (g_date_time_get_year (next),
- g_date_time_get_month (next),
- g_date_time_get_day_of_month (next),
- g_date_time_get_hour (next),
- g_date_time_get_minute (next),
- 0.1);
-
- interval_usec = g_date_time_difference (start_of_next, now);
- interval_msec = (interval_usec + 999) / 1000;
-
- g_date_time_unref (start_of_next);
- g_date_time_unref (next);
-
- return interval_msec;
-}
-
-static gint
-calculate_milliseconds_until_next_second (GDateTime * now)
-{
- gint interval_usec;
- guint interval_msec;
-
- interval_usec = G_USEC_PER_SEC - g_date_time_get_microsecond (now);
- interval_msec = (interval_usec + 999) / 1000;
-
- return interval_msec;
-}
-
-static void start_header_timer (IndicatorDatetimeService * self);
-
-static gboolean
-on_header_timer (gpointer gself)
-{
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself);
-
- rebuild_now (self, SECTION_HEADER);
-
- /* Restarting the timer to recalculate the interval. This helps us to hit
- our marks despite clock skew, suspend+resume, leap seconds, etc */
- start_header_timer (self);
- return G_SOURCE_REMOVE;
-}
-
-static const char * get_header_label_format_string (IndicatorDatetimeService *);
-
-static void
-start_header_timer (IndicatorDatetimeService * self)
-{
- guint interval_msec;
- gboolean header_shows_seconds = FALSE;
- priv_t * p = self->priv;
- GDateTime * now = indicator_datetime_service_get_localtime (self);
-
- indicator_clear_timer (&p->header_timer);
-
- if (g_settings_get_boolean (self->priv->settings, SETTINGS_SHOW_CLOCK_S))
- {
- const char * fmt = get_header_label_format_string (self);
- header_shows_seconds = fmt && (strstr(fmt,"%s") || strstr(fmt,"%S") ||
- strstr(fmt,"%T") || strstr(fmt,"%X") ||
- strstr(fmt,"%c"));
- }
-
- if (header_shows_seconds)
- interval_msec = calculate_milliseconds_until_next_second (now);
- else
- interval_msec = calculate_milliseconds_until_next_minute (now);
-
- interval_msec += 50; /* add a small margin to ensure the callback
- fires /after/ next is reached */
-
- p->header_timer = g_timeout_add_full (G_PRIORITY_HIGH,
- interval_msec,
- on_header_timer,
- self,
- NULL);
-
- g_date_time_unref (now);
-}
-
-/***
-**** ALARMS
-***/
-
-static void set_alarm_timer (IndicatorDatetimeService * self);
-
-static gboolean
-appointment_has_alarm_url (const struct IndicatorDatetimeAppt * appt)
-{
- return (appt->has_alarms) &&
- (appt->url != NULL) &&
- (g_str_has_prefix (appt->url, "alarm:///"));
-}
-
-static gboolean
-datetimes_have_the_same_minute (GDateTime * a G_GNUC_UNUSED, GDateTime * b G_GNUC_UNUSED)
-{
- int ay, am, ad;
- int by, bm, bd;
-
- g_date_time_get_ymd (a, &ay, &am, &ad);
- g_date_time_get_ymd (b, &by, &bm, &bd);
-
- return (ay == by) &&
- (am == bm) &&
- (ad == bd) &&
- (g_date_time_get_hour (a) == g_date_time_get_hour (b)) &&
- (g_date_time_get_minute (a) == g_date_time_get_minute (b));
-}
-
-static void
-dispatch_alarm_url (const struct IndicatorDatetimeAppt * appt)
-{
- gchar * str;
-
- g_return_if_fail (appt != NULL);
- g_return_if_fail (appointment_has_alarm_url (appt));
-
- str = g_date_time_format (appt->begin, "%F %T");
- g_debug ("dispatching url \"%s\" for appointment \"%s\", which begins at %s",
- appt->url, appt->summary, str);
- g_free (str);
-
- url_dispatch_send (appt->url, NULL, NULL);
-}
-
-static void
-on_snap_decided (NotifyNotification * notification G_GNUC_UNUSED,
- char * action,
- gpointer gurl)
-{
- g_debug ("%s: %s", G_STRFUNC, action);
-
- if (!g_strcmp0 (action, "show"))
- {
- const gchar * url = gurl;
- g_debug ("dispatching url '%s'", url);
- url_dispatch_send (url, NULL, NULL);
- }
-}
-
-static void
-show_snap_decision_for_alarm (const struct IndicatorDatetimeAppt * appt)
-{
- gchar * title;
- const gchar * body;
- const gchar * icon_name;
- NotifyNotification * nn;
- GError * error;
-
- title = g_date_time_format (appt->begin,
- get_terse_time_format_string (appt->begin));
- body = appt->summary;
- icon_name = ALARM_CLOCK_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_string (nn,
- "x-canonical-snap-decisions",
- "true");
- notify_notification_set_hint_string (nn,
- "x-canonical-private-button-tint",
- "true");
- notify_notification_add_action (nn, "show", _("Show"),
- on_snap_decided, g_strdup(appt->url), g_free);
- notify_notification_add_action (nn, "dismiss", _("Dismiss"),
- on_snap_decided, NULL, NULL);
-
- 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);
-}
-
-static void update_appointment_lists (IndicatorDatetimeService * self);
-
-static gboolean
-on_alarm_timer (gpointer gself)
-{
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself);
- GDateTime * now;
- GSList * l;
-
- /* If there are any alarms at the current time, show a snap decision */
- now = indicator_datetime_service_get_localtime (self);
- for (l=self->priv->upcoming_appointments; l!=NULL; l=l->next)
- {
- const struct IndicatorDatetimeAppt * appt = l->data;
-
- if (appointment_has_alarm_url (appt))
- if (datetimes_have_the_same_minute (now, appt->begin))
- show_snap_decision_for_alarm (appt);
- }
- g_date_time_unref (now);
-
- /* rebuild the alarm list asynchronously.
- set_upcoming_appointments() will update the alarm timer when this
- async call is done, so no need to restart the timer here... */
- update_appointment_lists (self);
-
- return G_SOURCE_REMOVE;
-}
-
-/* if there are upcoming alarms, set the alarm timer to the nearest one.
- otherwise, unset the alarm timer. */
-static void
-set_alarm_timer (IndicatorDatetimeService * self)
-{
- priv_t * p;
- GDateTime * now;
- GDateTime * alarm_time;
- GSList * l;
-
- p = self->priv;
- indicator_clear_timer (&p->alarm_timer);
-
- now = indicator_datetime_service_get_localtime (self);
-
- /* find the time of the next alarm on our calendar */
- alarm_time = NULL;
- for (l=p->upcoming_appointments; l!=NULL; l=l->next)
- {
- const struct IndicatorDatetimeAppt * appt = l->data;
-
- if (appointment_has_alarm_url (appt))
- if (g_date_time_compare (appt->begin, now) > 0)
- if (!alarm_time || g_date_time_compare (alarm_time, appt->begin) > 0)
- alarm_time = appt->begin;
- }
-
- /* if there's an upcoming alarm, set a timer to wake up at that time */
- if (alarm_time != NULL)
- {
- GTimeSpan interval_msec;
- gchar * str;
- GDateTime * then;
-
- interval_msec = g_date_time_difference (alarm_time, now);
- interval_msec += G_USEC_PER_SEC; /* fire a moment after alarm_time */
- interval_msec /= 1000; /* convert from usec to msec */
-
- str = g_date_time_format (alarm_time, "%F %T");
- g_debug ("%s is the next alarm time", str);
- g_free (str);
- then = g_date_time_add_seconds (now, interval_msec/1000);
- str = g_date_time_format (then, "%F %T");
- g_debug ("%s is when we'll wake up for it", str);
- g_free (str);
- g_date_time_unref (then);
-
- p->alarm_timer = g_timeout_add_full (G_PRIORITY_HIGH,
- (guint) interval_msec,
- on_alarm_timer,
- self,
- NULL);
- }
-
- g_date_time_unref (now);
-}
-
-/***
-****
-***/
-
-/**
- * General purpose handler for rebuilding sections and restarting their timers
- * when time jumps for whatever reason:
- *
- * - clock skew
- * - laptop suspend + resume
- * - geoclue detects that we've changed timezones
- * - Unity is running inside a TARDIS
- */
-static void
-on_local_time_jumped (IndicatorDatetimeService * self)
-{
- g_debug ("%s %s", G_STRLOC, G_STRFUNC);
-
- /* these calls accomplish two things:
- 1. rebuild the necessary states / menuitems when time jumps
- 2. restart the timers so their new wait interval is correct */
-
- on_header_timer (self);
- on_timezone_timer (self);
-}
-
-static gboolean
-skew_timer_func (gpointer gself)
-{
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself);
- GDateTime * now = indicator_datetime_service_get_localtime (self);
- priv_t * p = self->priv;
-
- /* check for clock skew: has too much time passed since the last check? */
- if (p->skew_time != NULL)
- {
- const GTimeSpan diff = g_date_time_difference (now, p->skew_time);
-
- if (diff > SKEW_DIFF_THRESHOLD_USEC)
- on_local_time_jumped (self);
- }
-
- g_clear_pointer (&p->skew_time, g_date_time_unref);
- p->skew_time = now;
- return G_SOURCE_CONTINUE;
-}
-
-/***
-****
-**** HEADER SECTION
-****
-***/
-
-static const gchar *
-get_header_label_format_string (IndicatorDatetimeService * self)
-{
- priv_t * p = self->priv;
-
- if (p->header_label_format_string == NULL)
- {
- char * fmt;
- GSettings * s = p->settings;
- const TimeFormatMode mode = g_settings_get_enum (s, SETTINGS_TIME_FORMAT_S);
-
- if (mode == TIME_FORMAT_MODE_CUSTOM)
- {
- fmt = g_settings_get_string (s, SETTINGS_CUSTOM_TIME_FORMAT_S);
- }
- else
- {
- gboolean show_day = g_settings_get_boolean (s, SETTINGS_SHOW_DAY_S);
- gboolean show_date = g_settings_get_boolean (s, SETTINGS_SHOW_DATE_S);
- gboolean show_year = show_date && g_settings_get_boolean (s, SETTINGS_SHOW_YEAR_S);
- fmt = generate_full_format_string (show_day, show_date, show_year, s);
- }
-
- p->header_label_format_string = fmt;
- }
-
- return p->header_label_format_string;
-}
-
-static GVariant *
-create_desktop_header_state (IndicatorDatetimeService * self)
-{
- priv_t * p = self->priv;
- GVariantBuilder b;
- const gchar * fmt;
- gchar * str;
- gboolean visible;
- GDateTime * now;
- GVariant * label_variant;
-
- visible = g_settings_get_boolean (p->settings, SETTINGS_SHOW_CLOCK_S);
-
- /* build the time string for the label & a11y */
- fmt = get_header_label_format_string (self);
- now = indicator_datetime_service_get_localtime (self);
- str = g_date_time_format (now, fmt);
- if (str == NULL)
- {
- str = g_strdup_printf (_("Unsupported date format “%s”"), fmt);
- g_warning ("%s", str);
- }
-
- label_variant = g_variant_new_take_string (str);
- g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add (&b, "{sv}", "accessible-desc", label_variant);
- g_variant_builder_add (&b, "{sv}", "label", label_variant);
- g_variant_builder_add (&b, "{sv}", "title", g_variant_new_string (_("Date and Time")));
- g_variant_builder_add (&b, "{sv}", "visible", g_variant_new_boolean (visible));
-
- /* cleanup */
- g_date_time_unref (now);
- return g_variant_builder_end (&b);
-}
-
-static gboolean
-service_has_alarms (IndicatorDatetimeService * self);
-
-static GVariant *
-create_phone_header_state (IndicatorDatetimeService * self)
-{
- priv_t * p = self->priv;
- const gboolean has_alarms = service_has_alarms (self);
- GVariantBuilder b;
- GDateTime * now;
- const gchar * fmt;
-
- g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add (&b, "{sv}", "title", g_variant_new_string (_("Upcoming")));
- g_variant_builder_add (&b, "{sv}", "visible", g_variant_new_boolean (TRUE));
-
- if (has_alarms)
- g_variant_builder_add (&b, "{sv}", "icon", p->alarm_icon_serialized);
-
- /* label, a11y */
- now = indicator_datetime_service_get_localtime (self);
- fmt = get_terse_header_time_format_string ();
- if (has_alarms)
- {
- gchar * label = g_date_time_format (now, fmt);
- gchar * a11y = g_strdup_printf (_("%s (has alarms)"), label);
- g_variant_builder_add (&b, "{sv}", "label", g_variant_new_take_string (label));
- g_variant_builder_add (&b, "{sv}", "accessible-desc", g_variant_new_take_string (a11y));
- }
- else
- {
- GVariant * v = g_variant_new_take_string (g_date_time_format (now, fmt));
- g_variant_builder_add (&b, "{sv}", "label", v);
- g_variant_builder_add (&b, "{sv}", "accessible-desc", v);
- }
-
- g_date_time_unref (now);
- return g_variant_builder_end (&b);
-}
-
-
-/***
-****
-**** CALENDAR SECTION
-****
-***/
-
-static GDateTime *
-get_calendar_date (IndicatorDatetimeService * self)
-{
- GDateTime * date;
- priv_t * p = self->priv;
-
- if (p->calendar_date)
- date = g_date_time_ref (p->calendar_date);
- else
- date = indicator_datetime_service_get_localtime (self);
-
- return date;
-}
-
-static GVariant *
-create_calendar_state (IndicatorDatetimeService * self)
-{
- guint i;
- const char * key;
- gboolean days[32] = { 0 };
- GVariantBuilder dict_builder;
- GVariantBuilder day_builder;
- GDateTime * date;
- GSList * l;
- gboolean b;
- priv_t * p = self->priv;
-
- g_variant_builder_init (&dict_builder, G_VARIANT_TYPE_DICTIONARY);
-
- key = "appointment-days";
- for (l=p->calendar_appointments; l!=NULL; l=l->next)
- {
- const struct IndicatorDatetimeAppt * appt = l->data;
- days[g_date_time_get_day_of_month (appt->begin)] = TRUE;
- }
- g_variant_builder_init (&day_builder, G_VARIANT_TYPE("ai"));
- for (i=0; i<G_N_ELEMENTS(days); i++)
- if (days[i])
- g_variant_builder_add (&day_builder, "i", i);
- g_variant_builder_add (&dict_builder, "{sv}", key,
- g_variant_builder_end (&day_builder));
-
- key = "calendar-day";
- date = get_calendar_date (self);
- g_variant_builder_add (&dict_builder, "{sv}", key,
- g_variant_new_int64 (g_date_time_to_unix (date)));
- g_date_time_unref (date);
-
- key = "show-week-numbers";
- b = g_settings_get_boolean (p->settings, SETTINGS_SHOW_WEEK_NUMBERS_S);
- g_variant_builder_add (&dict_builder, "{sv}", key, g_variant_new_boolean (b));
-
- return g_variant_builder_end (&dict_builder);
-}
-
-static void
-update_calendar_action_state (IndicatorDatetimeService * self)
-{
- g_simple_action_set_state (self->priv->calendar_action,
- create_calendar_state (self));
-}
-
-static GMenuModel *
-create_calendar_section (IndicatorDatetimeService * self, int profile)
-{
- const gboolean allow_activation = (profile == PROFILE_PHONE) || (profile == PROFILE_DESKTOP);
- GMenu * menu;
- GDateTime * now;
- char * label;
- GMenuItem * item;
-
- menu = g_menu_new ();
-
- /* add a menuitem that shows the current date & time */
- now = indicator_datetime_service_get_localtime (self);
- label = g_date_time_format (now, _("%A, %e %B %Y"));
- item = g_menu_item_new (label, NULL);
- g_menu_item_set_attribute_value (item, G_MENU_ATTRIBUTE_ICON, self->priv->calendar_icon_serialized);
- if (allow_activation)
- g_menu_item_set_action_and_target_value (item, "indicator.activate-planner", g_variant_new_int64(0));
- g_menu_append_item (menu, item);
- g_object_unref (item);
- g_free (label);
- g_date_time_unref (now);
-
- /* add a menuitem that shows the current date & time */
- if ((profile == PROFILE_DESKTOP) || (profile == PROFILE_GREETER))
- {
- item = g_menu_item_new ("[calendar]", NULL);
- g_menu_item_set_action_and_target_value (item, "indicator.calendar", g_variant_new_int64(0));
- g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.calendar");
- if (allow_activation)
- g_menu_item_set_attribute (item, "activation-action", "s", "indicator.activate-planner");
- g_menu_append_item (menu, item);
- g_object_unref (item);
- }
-
- return G_MENU_MODEL (menu);
-}
-
-/***
-****
-**** APPOINTMENTS SECTION
-****
-***/
-
-static gboolean
-service_has_alarms (IndicatorDatetimeService * self)
-{
- gboolean has_alarms = FALSE;
- GSList * appts;
- GSList * l;
-
- appts = self->priv->upcoming_appointments;
- for (l=appts; l!=NULL; l=l->next)
- {
- struct IndicatorDatetimeAppt * appt = l->data;
- if ((has_alarms = appt->has_alarms))
- break;
- }
-
- return has_alarms;
-}
-
-static char *
-get_appointment_time_format (struct IndicatorDatetimeAppt * appt,
- GDateTime * now,
- GSettings * settings,
- gboolean terse)
-{
- char * fmt;
- gboolean full_day = g_date_time_difference (appt->end, appt->begin) == G_TIME_SPAN_DAY;
-
- if (appt->is_daily)
- {
- const char * time_fmt = terse ? get_terse_time_format_string (appt->begin)
- : get_full_time_format_string (settings);
- fmt = join_date_and_time_format_strings (_("Daily"), time_fmt);
- }
- else if (full_day)
- {
- /* TRANSLATORS: a strftime(3) format showing full day events.
- * "%A" means a full text day (Wednesday), "%a" means abbreviated (Wed). */
- fmt = g_strdup (_("%A"));
- }
- else
- {
- fmt = terse ? generate_terse_format_string_at_time (now, appt->begin)
- : generate_full_format_string_at_time (now, appt->begin, settings);
- }
-
- return fmt;
-}
-
-static void
-add_appointments (IndicatorDatetimeService * self, GMenu * menu, gboolean phone)
-{
- const int MAX_APPTS = 5;
- GDateTime * now;
- GHashTable * added;
- GSList * appts;
- GSList * l;
- int i;
-
- now = indicator_datetime_service_get_localtime (self);
-
- added = g_hash_table_new (g_str_hash, g_str_equal);
-
- /* build appointment menuitems */
- appts = self->priv->upcoming_appointments;
- for (l=appts, i=0; l!=NULL && i<MAX_APPTS; l=l->next, i++)
- {
- struct IndicatorDatetimeAppt * appt = l->data;
- char * fmt;
- gint64 unix_time;
- GMenuItem * menu_item;
-
- if (g_hash_table_contains (added, appt->uid))
- continue;
-
- g_hash_table_add (added, appt->uid);
-
- fmt = get_appointment_time_format (appt, now, self->priv->settings, phone);
- unix_time = g_date_time_to_unix (appt->begin);
-
- menu_item = g_menu_item_new (appt->summary, NULL);
-
- if (appt->has_alarms)
- g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_ICON,
- self->priv->alarm_icon_serialized);
- else if (appt->color != NULL)
- g_menu_item_set_attribute (menu_item, "x-canonical-color",
- "s", appt->color);
-
- g_menu_item_set_attribute (menu_item, "x-canonical-time",
- "x", unix_time);
- g_menu_item_set_attribute (menu_item, "x-canonical-time-format",
- "s", fmt);
- g_menu_item_set_attribute (menu_item, "x-canonical-type",
- "s", appt->has_alarms ? "com.canonical.indicator.alarm"
- : "com.canonical.indicator.appointment");
-
- if (phone)
- g_menu_item_set_action_and_target_value (menu_item,
- "indicator.activate-appointment",
- g_variant_new_string (appt->uid));
- else
- g_menu_item_set_action_and_target_value (menu_item,
- "indicator.activate-planner",
- g_variant_new_int64 (unix_time));
- g_menu_append_item (menu, menu_item);
- g_object_unref (menu_item);
- g_free (fmt);
- }
-
- /* cleanup */
- g_hash_table_unref (added);
- g_date_time_unref (now);
-}
-
-
-/* try to extract the clock app's filename from click. (/$pkgdir/$icon) */
-static GVariant *
-get_clock_app_icon (void)
-{
- GVariant * serialized = NULL;
- gchar * icon_filename = NULL;
- gchar * pkgdir;
-
- pkgdir = NULL;
- g_spawn_command_line_sync ("click pkgdir com.ubuntu.clock", &pkgdir, NULL, NULL, NULL);
- if (pkgdir != NULL)
- {
- gchar * manifest = NULL;
- g_strstrip (pkgdir);
- g_spawn_command_line_sync ("click info com.ubuntu.clock", &manifest, NULL, NULL, NULL);
- if (manifest != NULL)
- {
- JsonParser * parser = json_parser_new ();
- if (json_parser_load_from_data (parser, manifest, -1, NULL))
- {
- JsonNode * root = json_parser_get_root (parser); /* transfer-none */
- if ((root != NULL) && (JSON_NODE_TYPE(root) == JSON_NODE_OBJECT))
- {
- JsonObject * o = json_node_get_object (root); /* transfer-none */
- const gchar * icon_name = json_object_get_string_member (o, "icon");
- if (icon_name != NULL)
- icon_filename = g_build_filename (pkgdir, icon_name, NULL);
- }
- }
- g_object_unref (parser);
- g_free (manifest);
- }
- g_free (pkgdir);
- }
-
- if (icon_filename != NULL)
- {
- GFile * file = g_file_new_for_path (icon_filename);
- GIcon * icon = g_file_icon_new (file);
-
- serialized = g_icon_serialize (icon);
-
- g_object_unref (icon);
- g_object_unref (file);
- g_free (icon_filename);
- }
-
- return serialized;
-}
-
-static GMenuModel *
-create_phone_appointments_section (IndicatorDatetimeService * self)
-{
- priv_t * p = self->priv;
- GMenu * menu = g_menu_new ();
- GMenuItem * menu_item;
-
- menu_item = g_menu_item_new (_("Clock"), "indicator.activate-phone-clock-app");
- if (p->clock_app_icon_serialized != NULL)
- g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_ICON, p->clock_app_icon_serialized);
- g_menu_append_item (menu, menu_item);
- g_object_unref (menu_item);
-
- add_appointments (self, menu, TRUE);
-
- return G_MENU_MODEL (menu);
-}
-
-static GMenuModel *
-create_desktop_appointments_section (IndicatorDatetimeService * self)
-{
- GMenu * menu = g_menu_new ();
-
- if (g_settings_get_boolean (self->priv->settings, SETTINGS_SHOW_EVENTS_S))
- {
- GMenuItem * menu_item;
-
- add_appointments (self, menu, FALSE);
-
- /* add the 'Add Event…' menuitem */
- menu_item = g_menu_item_new (_("Add Event…"), NULL);
- g_menu_item_set_action_and_target_value (menu_item,
- "indicator.activate-planner",
- g_variant_new_int64 (0));
- g_menu_append_item (menu, menu_item);
- g_object_unref (menu_item);
- }
-
- return G_MENU_MODEL (menu);
-}
-
-/***
-****
-**** LOCATIONS SECTION
-****
-***/
-
-
-/* A temp struct used by create_locations_section()
- for pruning duplicates and sorting. */
-struct TimeLocation
-{
- GTimeSpan offset;
- gchar * zone;
- gchar * name;
- gboolean visible;
- GDateTime * local_time;
-};
-
-static void
-time_location_free (struct TimeLocation * loc)
-{
- g_date_time_unref (loc->local_time);
- g_free (loc->name);
- g_free (loc->zone);
- g_slice_free (struct TimeLocation, loc);
-}
-
-static struct TimeLocation*
-time_location_new (const char * zone,
- const char * name,
- gboolean visible)
-{
- struct TimeLocation * loc = g_slice_new (struct TimeLocation);
- GTimeZone * tz = g_time_zone_new (zone);
- loc->zone = g_strdup (zone);
- loc->name = g_strdup (name);
- loc->visible = visible;
- loc->local_time = g_date_time_new_now (tz);
- loc->offset = g_date_time_get_utc_offset (loc->local_time);
- g_time_zone_unref (tz);
- return loc;
-}
-
-static int
-time_location_compare (const struct TimeLocation * a,
- const struct TimeLocation * b)
-{
- int ret = 0;
-
- if (!ret && (a->offset != b->offset)) /* primary key */
- ret = (a->offset < b->offset) ? -1 : 1;
-
- if (!ret)
- ret = g_strcmp0 (a->name, b->name); /* secondary key */
-
- if (!ret)
- ret = a->visible - b->visible; /* tertiary key */
-
- return ret;
-}
-
-static GSList*
-locations_add (GSList * locations,
- const char * zone,
- const char * name,
- gboolean visible)
-{
- struct TimeLocation * loc = time_location_new (zone, name, visible);
-
- if (g_slist_find_custom (locations, loc, (GCompareFunc)time_location_compare))
- {
- g_debug("%s Skipping duplicate zone '%s' name '%s'", G_STRLOC, zone, name);
- time_location_free (loc);
- }
- else
- {
- g_debug ("%s Adding zone '%s', name '%s'", G_STRLOC, zone, name);
- locations = g_slist_append (locations, loc);
- }
-
- return locations;
-}
-
-static GMenuModel *
-create_locations_section (IndicatorDatetimeService * self)
-{
- guint i;
- GMenu * menu;
- GSList * l;
- GSList * locations = NULL;
- gchar ** user_locations;
- const gchar ** detected_timezones;
- priv_t * p = self->priv;
- GDateTime * now = indicator_datetime_service_get_localtime (self);
-
- menu = g_menu_new ();
-
- /***
- **** Build a list of locations to add, omitting duplicates
- ***/
-
- detected_timezones = indicator_datetime_clock_get_timezones (p->clock);
- for (i=0; detected_timezones && detected_timezones[i]; i++)
- {
- const char * tz = detected_timezones[i];
- gchar * name = get_current_zone_name (tz, p->settings);
- locations = locations_add (locations, tz, name, TRUE);
- g_free (name);
- }
-
- /* maybe add the user-specified locations */
- user_locations = g_settings_get_strv (p->settings, SETTINGS_LOCATIONS_S);
- if (user_locations != NULL)
- {
- const gboolean visible = g_settings_get_boolean (p->settings, SETTINGS_SHOW_LOCATIONS_S);
-
- for (i=0; user_locations[i] != NULL; i++)
- {
- gchar * zone;
- gchar * name;
- split_settings_location (user_locations[i], &zone, &name);
- locations = locations_add (locations, zone, name, visible);
- g_free (name);
- g_free (zone);
- }
-
- g_strfreev (user_locations);
- user_locations = NULL;
- }
-
- /* now build menuitems for all the locations */
- for (l=locations; l!=NULL; l=l->next)
- {
- struct TimeLocation * loc = l->data;
- if (loc->visible)
- {
- char * detailed_action;
- char * fmt;
- GMenuItem * menu_item;
-
- detailed_action = g_strdup_printf ("indicator.set-location::%s %s",
- loc->zone,
- loc->name);
- fmt = generate_full_format_string_at_time (now, loc->local_time, p->settings);
-
- menu_item = g_menu_item_new (loc->name, detailed_action);
- g_menu_item_set_attribute (menu_item, "x-canonical-type",
- "s", "com.canonical.indicator.location");
- g_menu_item_set_attribute (menu_item, "x-canonical-timezone",
- "s", loc->zone);
- g_menu_item_set_attribute (menu_item, "x-canonical-time-format",
- "s", fmt);
- g_menu_append_item (menu, menu_item);
-
- g_object_unref (menu_item);
- g_free (fmt);
- g_free (detailed_action);
- }
- }
-
- g_date_time_unref (now);
- g_slist_free_full (locations, (GDestroyNotify)time_location_free);
- return G_MENU_MODEL (menu);
-}
-
-/***
-**** SET LOCATION
-***/
-
-struct setlocation_data
-{
- IndicatorDatetimeService * service;
- char * timezone_id;
- char * name;
-};
-
-static void
-setlocation_data_free (struct setlocation_data * data)
-{
- g_free (data->timezone_id);
- g_free (data->name);
- g_slice_free (struct setlocation_data, data);
-}
-
-static void
-on_datetime1_set_timezone_response (GObject * object,
- GAsyncResult * res,
- gpointer gdata)
-{
- GError * err;
- GVariant * answers;
- struct setlocation_data * data = gdata;
-
- err = NULL;
- answers = g_dbus_proxy_call_finish (G_DBUS_PROXY(object), res, &err);
- if (err != NULL)
- {
- if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("Could not set new timezone: %s", err->message);
-
- g_error_free (err);
- }
- else
- {
- char * timezone_name = g_strdup_printf ("%s %s",
- data->timezone_id,
- data->name);
-
- g_settings_set_string (data->service->priv->settings,
- SETTINGS_TIMEZONE_NAME_S,
- timezone_name);
-
- g_free (timezone_name);
- g_variant_unref (answers);
- }
-
- setlocation_data_free (data);
-}
-
-static void
-on_datetime1_proxy_ready (GObject * object G_GNUC_UNUSED,
- GAsyncResult * res,
- gpointer gdata)
-{
- GError * err;
- GDBusProxy * proxy;
- struct setlocation_data * data = gdata;
-
- err = NULL;
- proxy = g_dbus_proxy_new_for_bus_finish (res, &err);
- if (err != NULL)
- {
- if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("Could not grab DBus proxy for timedated: %s", err->message);
-
- g_error_free (err);
- setlocation_data_free (data);
- }
- else
- {
- g_dbus_proxy_call (proxy,
- "SetTimezone",
- g_variant_new ("(sb)", data->timezone_id, TRUE),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- data->service->priv->cancellable,
- on_datetime1_set_timezone_response,
- data);
-
- g_object_unref (proxy);
- }
-}
-
-static void
-indicator_datetime_service_set_location (IndicatorDatetimeService * self,
- const char * timezone_id,
- const char * name)
-{
- priv_t * p = self->priv;
- struct setlocation_data * data;
-
- g_return_if_fail (INDICATOR_IS_DATETIME_SERVICE (self));
- g_return_if_fail (name && *name);
- g_return_if_fail (timezone_id && *timezone_id);
-
- data = g_slice_new0 (struct setlocation_data);
- data->timezone_id = g_strdup (timezone_id);
- data->name = g_strdup (name);
- data->service = self;
-
- g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
- G_DBUS_PROXY_FLAGS_NONE,
- NULL,
- "org.freedesktop.timedate1",
- "/org/freedesktop/timedate1",
- "org.freedesktop.timedate1",
- p->cancellable,
- on_datetime1_proxy_ready,
- data);
-}
-
-static void
-on_set_location (GSimpleAction * a G_GNUC_UNUSED,
- GVariant * param,
- gpointer gself)
-{
- char * zone;
- char * name;
- IndicatorDatetimeService * self;
-
- self = INDICATOR_DATETIME_SERVICE (gself);
- split_settings_location (g_variant_get_string (param, NULL), &zone, &name);
- indicator_datetime_service_set_location (self, zone, name);
-
- g_free (name);
- g_free (zone);
-}
-
-static void
-on_calendar_active_changed (GSimpleAction *action G_GNUC_UNUSED,
- GVariant *state,
- gpointer user_data)
-{
- IndicatorDatetimeService *self = user_data;
-
- /* reset the date when the menu is shown */
- if (g_variant_get_boolean (state) && self->priv->calendar_date)
- {
- g_clear_pointer (&self->priv->calendar_date, g_date_time_unref);
- update_calendar_action_state (self);
- }
-}
-
-/***
-****
-***/
-
-static GMenuModel *
-create_desktop_settings_section (IndicatorDatetimeService * self G_GNUC_UNUSED)
-{
- GMenu * menu = g_menu_new ();
- g_menu_append (menu, _("Date & Time Settings…"), "indicator.activate-desktop-settings");
- return G_MENU_MODEL (menu);
-}
-
-static GMenuModel *
-create_phone_settings_section (IndicatorDatetimeService * self G_GNUC_UNUSED)
-{
- GMenu * menu = g_menu_new ();
- g_menu_append (menu, _("Time & Date settings…"), "indicator.activate-phone-settings");
- return G_MENU_MODEL (menu);
-}
-
-static void
-create_menu (IndicatorDatetimeService * self, int profile)
-{
- GMenu * menu;
- GMenu * submenu;
- GMenuItem * header;
- GMenuModel * sections[16];
- const gchar * header_action;
- int i;
- int n = 0;
-
- g_assert (0<=profile && profile<N_PROFILES);
- g_assert (self->priv->menus[profile].menu == NULL);
-
- switch (profile)
- {
- case PROFILE_PHONE:
- sections[n++] = create_calendar_section (self, profile);
- sections[n++] = create_phone_appointments_section (self);
- sections[n++] = create_phone_settings_section (self);
- header_action = "indicator.phone-header";
- break;
-
- case PROFILE_DESKTOP:
- sections[n++] = create_calendar_section (self, profile);
- sections[n++] = create_desktop_appointments_section (self);
- sections[n++] = create_locations_section (self);
- sections[n++] = create_desktop_settings_section (self);
- header_action = "indicator.desktop-header";
- break;
-
- case PROFILE_GREETER:
- sections[n++] = create_calendar_section (self, profile);
- header_action = "indicator.desktop-header";
- break;
- }
-
- /* add sections to the submenu */
-
- submenu = g_menu_new ();
-
- for (i=0; i<n; ++i)
- {
- g_menu_append_section (submenu, NULL, sections[i]);
- g_object_unref (sections[i]);
- }
-
- /* add submenu to the header */
- header = g_menu_item_new (NULL, header_action);
- g_menu_item_set_attribute (header, "x-canonical-type",
- "s", "com.canonical.indicator.root");
- g_menu_item_set_submenu (header, G_MENU_MODEL (submenu));
- g_menu_item_set_attribute (header, "submenu-action", "s", "indicator.calendar-active");
- g_object_unref (submenu);
-
- /* add header to the menu */
- menu = g_menu_new ();
- g_menu_append_item (menu, header);
- g_object_unref (header);
-
- self->priv->menus[profile].menu = menu;
- self->priv->menus[profile].submenu = submenu;
-}
-
-/***
-**** GActions
-***/
-
-/* Run a particular program based on an activation */
-static void
-execute_command (const gchar * cmd)
-{
- GError * err = NULL;
-
- g_debug ("Issuing command '%s'", cmd);
-
- if (!g_spawn_command_line_async (cmd, &err))
- {
- g_warning ("Unable to start \"%s\": %s", cmd, err->message);
- g_error_free (err);
- }
-}
-
-static void
-on_desktop_settings_activated (GSimpleAction * a G_GNUC_UNUSED,
- GVariant * param G_GNUC_UNUSED,
- gpointer gself G_GNUC_UNUSED)
-{
- gchar *path;
-
- path = g_find_program_in_path ("unity-control-center");
- if (path != NULL && g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") == 0)
- {
- execute_command ("unity-control-center datetime");
- }
- else
- {
-#ifdef HAVE_CCPANEL
- execute_command ("gnome-control-center indicator-datetime");
-#else
- execute_command ("gnome-control-center datetime");
-#endif
- }
-
- g_free (path);
-}
-
-static void
-on_phone_settings_activated (GSimpleAction * a G_GNUC_UNUSED,
- GVariant * param G_GNUC_UNUSED,
- gpointer gself G_GNUC_UNUSED)
-{
- url_dispatch_send ("settings:///system/time-date", NULL, NULL);
-}
-
-static void
-on_activate_appointment (GSimpleAction * a G_GNUC_UNUSED,
- GVariant * param,
- gpointer gself)
-{
- priv_t * p = INDICATOR_DATETIME_SERVICE(gself)->priv;
- const gchar * uid = g_variant_get_string (param, NULL);
-
- if (uid != NULL)
- {
- const struct IndicatorDatetimeAppt * appt;
- GSList * l;
-
- /* find the appointment that matches that uid */
- for (l=p->upcoming_appointments, appt=NULL; l && !appt; l=l->next)
- {
- const struct IndicatorDatetimeAppt * tmp = l->data;
- if (!g_strcmp0 (uid, tmp->uid))
- appt = tmp;
- }
-
- /* if that appointment's an alarm, dispatch its url */
- g_debug ("%s: uri '%s'; matching appt is %p", G_STRFUNC, uid, (void*)appt);
- if (appt && appointment_has_alarm_url (appt))
- dispatch_alarm_url (appt);
- }
-}
-
-static void
-on_phone_clock_activated (GSimpleAction * a G_GNUC_UNUSED,
- GVariant * param G_GNUC_UNUSED,
- gpointer gself G_GNUC_UNUSED)
-{
- const char * url = "appid://com.ubuntu.clock/clock/current-user-version";
- url_dispatch_send (url, NULL, NULL);
-}
-
-static void
-on_activate_planner (GSimpleAction * a G_GNUC_UNUSED,
- GVariant * param,
- gpointer gself)
-{
- priv_t * p = INDICATOR_DATETIME_SERVICE(gself)->priv;
-
- if (p->planner != NULL)
- {
- const gint64 t = g_variant_get_int64 (param);
- if (t)
- {
- GDateTime * date_time = g_date_time_new_from_unix_local (t);
- indicator_datetime_planner_activate_time (p->planner, date_time);
- g_date_time_unref (date_time);
- }
- else /* no time specified... */
- {
- indicator_datetime_planner_activate (p->planner);
- }
- }
-}
-
-static void
-on_calendar_action_activated (GSimpleAction * action G_GNUC_UNUSED,
- GVariant * state,
- gpointer gself)
-{
- gint64 unix_time;
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself);
-
- if ((unix_time = g_variant_get_int64 (state)))
- {
- GDateTime * date = g_date_time_new_from_unix_local (unix_time);
- indicator_datetime_service_set_calendar_date (self, date);
- g_date_time_unref (date);
- }
- else /* unset */
- {
- indicator_datetime_service_set_calendar_date (self, NULL);
- }
-}
-
-
-static void
-init_gactions (IndicatorDatetimeService * self)
-{
- GSimpleAction * a;
- priv_t * p = self->priv;
-
- GActionEntry entries[] = {
- { "activate-desktop-settings", on_desktop_settings_activated },
- { "activate-phone-settings", on_phone_settings_activated },
- { "activate-phone-clock-app", on_phone_clock_activated },
- { "activate-planner", on_activate_planner, "x", NULL },
- { "activate-appointment", on_activate_appointment, "s", NULL },
- { "set-location", on_set_location, "s" },
- { "calendar-active", NULL, NULL, "false", on_calendar_active_changed }
- };
-
- p->actions = g_simple_action_group_new ();
-
- g_action_map_add_action_entries (G_ACTION_MAP(p->actions),
- entries,
- G_N_ELEMENTS(entries),
- self);
-
- /* add the header actions */
-
- a = g_simple_action_new_stateful ("desktop-header", NULL,
- create_desktop_header_state (self));
- g_action_map_add_action (G_ACTION_MAP(p->actions), G_ACTION(a));
- p->desktop_header_action = a;
-
- a = g_simple_action_new_stateful ("phone-header", NULL,
- create_phone_header_state (self));
- g_action_map_add_action (G_ACTION_MAP(p->actions), G_ACTION(a));
- p->phone_header_action = a;
-
- /* add the calendar action */
- a = g_simple_action_new_stateful ("calendar",
- G_VARIANT_TYPE_INT64,
- create_calendar_state (self));
- g_action_map_add_action (G_ACTION_MAP(p->actions), G_ACTION(a));
- g_signal_connect (a, "activate",
- G_CALLBACK(on_calendar_action_activated), self);
- p->calendar_action = a;
-
- rebuild_now (self, SECTION_HEADER);
-}
-
-/***
-****
-***/
-
-/**
- * A small helper function for rebuild_now().
- * - removes the previous section
- * - adds and unrefs the new section
- */
-static void
-rebuild_section (GMenu * parent, int pos, GMenuModel * new_section)
-{
- g_menu_remove (parent, pos);
- g_menu_insert_section (parent, pos, NULL, new_section);
- g_object_unref (new_section);
-}
-
-static void
-rebuild_now (IndicatorDatetimeService * self, int sections)
-{
- priv_t * p = self->priv;
- struct ProfileMenuInfo * phone = &p->menus[PROFILE_PHONE];
- 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,
- create_desktop_header_state (self));
- g_simple_action_set_state (p->phone_header_action,
- create_phone_header_state (self));
- }
-
- if (sections & SECTION_CALENDAR)
- {
- rebuild_section (phone->submenu, 0, create_calendar_section(self, PROFILE_PHONE));
- rebuild_section (desktop->submenu, 0, create_calendar_section(self, PROFILE_DESKTOP));
- rebuild_section (greeter->submenu, 0, create_calendar_section(self, PROFILE_GREETER));
- }
-
- if (sections & SECTION_APPOINTMENTS)
- {
- rebuild_section (phone->submenu, 1, create_phone_appointments_section (self));
- rebuild_section (desktop->submenu, 1, create_desktop_appointments_section (self));
- }
-
- if (sections & SECTION_LOCATIONS)
- {
- rebuild_section (desktop->submenu, 2, create_locations_section (self));
- }
-
- if (sections & SECTION_SETTINGS)
- {
- rebuild_section (phone->submenu, 2, create_phone_settings_section (self));
- rebuild_section (desktop->submenu, 3, create_desktop_settings_section (self));
- }
-}
-
-static int
-rebuild_timeout_func (IndicatorDatetimeService * self)
-{
- priv_t * p = self->priv;
- rebuild_now (self, p->rebuild_flags);
- p->rebuild_flags = 0;
- p->rebuild_id = 0;
- return G_SOURCE_REMOVE;
-}
-
-static void
-rebuild_soon (IndicatorDatetimeService * self, int section)
-{
- priv_t * p = self->priv;
-
- p->rebuild_flags |= section;
-
- if (p->rebuild_id == 0)
- {
- /* Change events seem to come over the bus in small bursts. This msec
- value is an arbitrary number that tries to be large enough to fold
- multiple events into a single rebuild, but small enough that the
- user won't notice any lag. */
- static const int REBUILD_INTERVAL_MSEC = 500;
-
- p->rebuild_id = g_timeout_add (REBUILD_INTERVAL_MSEC,
- (GSourceFunc)rebuild_timeout_func,
- self);
- }
-}
-
-/***
-**** org.freedesktop.login1.Manager
-***/
-
-static void
-on_login1_manager_signal (GDBusProxy * proxy G_GNUC_UNUSED,
- gchar * sender_name G_GNUC_UNUSED,
- gchar * signal_name,
- GVariant * parameters,
- gpointer gself)
-{
- if (!g_strcmp0 (signal_name, "PrepareForSleep"))
- {
- gboolean sleeping = FALSE;
- g_variant_get (parameters, "(b)", &sleeping);
- if (!sleeping)
- on_local_time_jumped (INDICATOR_DATETIME_SERVICE (gself));
- }
-}
-
-static void
-on_login1_manager_proxy_ready (GObject * object G_GNUC_UNUSED,
- GAsyncResult * res,
- gpointer gself)
-{
- GError * err;
- GDBusProxy * proxy;
-
- err = NULL;
- proxy = g_dbus_proxy_new_for_bus_finish (res, &err);
-
- if (err != NULL)
- {
- if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("Could not grab DBus proxy for logind: %s", err->message);
-
- g_error_free (err);
- }
- else
- {
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself);
- self->priv->login1_manager = proxy;
- g_signal_connect (proxy, "g-signal",
- G_CALLBACK(on_login1_manager_signal), self);
- }
-}
-
-/***
-**** Appointments
-***/
-
-static void
-set_calendar_appointments (IndicatorDatetimeService * self,
- GSList * appointments)
-{
- priv_t * p = self->priv;
-
- /* repopulate the list */
- indicator_datetime_planner_free_appointments (p->calendar_appointments);
- p->calendar_appointments = appointments;
-
- /* sync the menus/actions */
- update_calendar_action_state (self);
- rebuild_calendar_section_soon (self);
-}
-
-static void
-on_calendar_appointments_ready (GObject * source,
- GAsyncResult * res,
- gpointer self)
-{
- IndicatorDatetimePlanner * planner;
- GError * error;
- GSList * appointments;
-
- planner = INDICATOR_DATETIME_PLANNER (source);
- error = NULL;
- appointments = indicator_datetime_planner_get_appointments_finish (planner,
- res,
- &error);
-
- if (error != NULL)
- {
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("can't get this month's appointments: %s", error->message);
-
- g_error_free (error);
- }
- else
- {
- set_calendar_appointments (INDICATOR_DATETIME_SERVICE (self),
- appointments);
- }
-}
-
-static void
-set_upcoming_appointments (IndicatorDatetimeService * self,
- GSList * appointments)
-{
- priv_t * p = self->priv;
-
- /* repopulate the list */
- indicator_datetime_planner_free_appointments (p->upcoming_appointments);
- p->upcoming_appointments = appointments;
-
- /* sync the menus/actions */
- rebuild_appointments_section_soon (self);
-
- /* alarm timer is keyed off of the next alarm time,
- so it needs to be rebuilt when the appointment list changes */
- set_alarm_timer (self);
-}
-
-static void
-on_upcoming_appointments_ready (GObject * source,
- GAsyncResult * res,
- gpointer self)
-{
- IndicatorDatetimePlanner * planner;
- GError * error;
- GSList * appointments;
-
- planner = INDICATOR_DATETIME_PLANNER (source);
- error = NULL;
- appointments = indicator_datetime_planner_get_appointments_finish (planner,
- res,
- &error);
-
- if (error != NULL)
- {
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("can't get upcoming appointments: %s", error->message);
-
- g_error_free (error);
- }
- else
- {
- set_upcoming_appointments (INDICATOR_DATETIME_SERVICE (self),
- appointments);
- }
-}
-
-static void
-update_appointment_lists (IndicatorDatetimeService * self)
-{
- IndicatorDatetimePlanner * planner;
- GDateTime * calendar_date;
- GDateTime * begin;
- GDateTime * end;
- int y, m, d;
-
- planner = self->priv->planner;
- calendar_date = get_calendar_date (self);
-
- /* get all the appointments in the calendar month */
- g_date_time_get_ymd (calendar_date, &y, &m, &d);
- begin = g_date_time_new_local (y, m, 1, 0, 0, 0.1);
- end = g_date_time_new_local (y, m, g_date_get_days_in_month(m,y), 23, 59, 59.9);
- if (begin && end)
- indicator_datetime_planner_get_appointments (planner, begin, end,
- on_calendar_appointments_ready,
- self);
- g_clear_pointer (&begin, g_date_time_unref);
- g_clear_pointer (&end, g_date_time_unref);
-
- /* get the upcoming appointments */
- begin = g_date_time_ref (calendar_date);
- end = g_date_time_add_months (begin, 1);
- if (begin && end)
- indicator_datetime_planner_get_appointments (planner, begin, end,
- on_upcoming_appointments_ready,
- self);
- g_clear_pointer (&begin, g_date_time_unref);
- g_clear_pointer (&end, g_date_time_unref);
- g_clear_pointer (&calendar_date, g_date_time_unref);
-}
-
-
-/***
-**** GDBus
-***/
-
-static void
-on_bus_acquired (GDBusConnection * connection,
- const gchar * name,
- gpointer gself)
-{
- int i;
- guint id;
- GError * err = NULL;
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE(gself);
- priv_t * p = self->priv;
-
- g_debug ("bus acquired: %s", name);
-
- p->conn = g_object_ref (G_OBJECT (connection));
-
- /* export the actions */
- if ((id = g_dbus_connection_export_action_group (connection,
- BUS_PATH,
- G_ACTION_GROUP (p->actions),
- &err)))
- {
- p->actions_export_id = id;
- }
- else
- {
- g_warning ("cannot export action group: %s", err->message);
- g_clear_error (&err);
- }
-
- /* export the menus */
- for (i=0; i<N_PROFILES; ++i)
- {
- char * path = g_strdup_printf ("%s/%s", BUS_PATH, menu_names[i]);
- struct ProfileMenuInfo * menu = &p->menus[i];
-
- if ((id = g_dbus_connection_export_menu_model (connection,
- path,
- G_MENU_MODEL (menu->menu),
- &err)))
- {
- menu->export_id = id;
- }
- else
- {
- g_warning ("cannot export %s menu: %s", menu_names[i], err->message);
- g_clear_error (&err);
- }
-
- g_free (path);
- }
-}
-
-static void
-unexport (IndicatorDatetimeService * self)
-{
- int i;
- priv_t * p = self->priv;
-
- /* unexport the menus */
- for (i=0; i<N_PROFILES; ++i)
- {
- guint * id = &self->priv->menus[i].export_id;
-
- if (*id)
- {
- g_dbus_connection_unexport_menu_model (p->conn, *id);
- *id = 0;
- }
- }
-
- /* unexport the actions */
- if (p->actions_export_id)
- {
- g_dbus_connection_unexport_action_group (p->conn, p->actions_export_id);
- p->actions_export_id = 0;
- }
-}
-
-static void
-on_name_lost (GDBusConnection * connection G_GNUC_UNUSED,
- const gchar * name,
- gpointer gself)
-{
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself);
-
- g_debug ("%s %s name lost %s", G_STRLOC, G_STRFUNC, name);
-
- unexport (self);
-
- g_signal_emit (self, signals[SIGNAL_NAME_LOST], 0, NULL);
-}
-
-
-/***
-**** GObject virtual functions
-***/
-
-static void
-my_get_property (GObject * o,
- guint property_id,
- GValue * value,
- GParamSpec * pspec)
-{
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (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;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
- }
-}
-
-static void
-my_set_property (GObject * o,
- guint property_id,
- const GValue * value,
- GParamSpec * pspec)
-{
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (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;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
- }
-}
-
-
-static void
-my_dispose (GObject * o)
-{
- int i;
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE(o);
- priv_t * p = self->priv;
-
- if (p->own_id)
- {
- g_bus_unown_name (p->own_id);
- p->own_id = 0;
- }
-
- unexport (self);
-
- if (p->cancellable != NULL)
- {
- g_cancellable_cancel (p->cancellable);
- g_clear_object (&p->cancellable);
- }
-
- indicator_datetime_service_set_clock (self, NULL);
- indicator_datetime_service_set_planner (self, NULL);
-
- if (p->login1_manager != NULL)
- {
- g_signal_handlers_disconnect_by_data (p->login1_manager, self);
- g_clear_object (&p->login1_manager);
- }
-
- indicator_clear_timer (&p->skew_timer);
- indicator_clear_timer (&p->rebuild_id);
- indicator_clear_timer (&p->timezone_timer);
- indicator_clear_timer (&p->header_timer);
- indicator_clear_timer (&p->alarm_timer);
-
- if (p->settings != NULL)
- {
- g_signal_handlers_disconnect_by_data (p->settings, self);
- g_clear_object (&p->settings);
- }
-
- g_clear_object (&p->actions);
-
- for (i=0; i<N_PROFILES; ++i)
- g_clear_object (&p->menus[i].menu);
-
- g_clear_object (&p->calendar_action);
- g_clear_object (&p->desktop_header_action);
- g_clear_object (&p->phone_header_action);
- g_clear_object (&p->conn);
-
- /* clear the serialized icon cache */
- g_clear_pointer (&p->alarm_icon_serialized, g_variant_unref);
- g_clear_pointer (&p->calendar_icon_serialized, g_variant_unref);
- g_clear_pointer (&p->clock_app_icon_serialized, g_variant_unref);
-
- G_OBJECT_CLASS (indicator_datetime_service_parent_class)->dispose (o);
-}
-
-static void
-my_finalize (GObject * o)
-{
- IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE(o);
- priv_t * p = self->priv;
-
- g_free (p->header_label_format_string);
- g_clear_pointer (&p->skew_time, g_date_time_unref);
- g_clear_pointer (&p->calendar_date, g_date_time_unref);
-
- G_OBJECT_CLASS (indicator_datetime_service_parent_class)->finalize (o);
-}
-
-/***
-**** Instantiation
-***/
-
-static void
-indicator_datetime_service_init (IndicatorDatetimeService * self)
-{
- GIcon * icon;
- 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);
-
- /* build the serialized icon cache */
-
- icon = g_themed_icon_new_with_default_fallbacks (ALARM_CLOCK_ICON_NAME);
- p->alarm_icon_serialized = g_icon_serialize (icon);
- g_object_unref (icon);
-
- icon = g_themed_icon_new_with_default_fallbacks ("calendar");
- p->calendar_icon_serialized = g_icon_serialize (icon);
- g_object_unref (icon);
-
- p->clock_app_icon_serialized = get_clock_app_icon ();
-}
-
-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 */
- const char * const header_settings[] = {
- SETTINGS_SHOW_CLOCK_S,
- SETTINGS_TIME_FORMAT_S,
- SETTINGS_SHOW_SECONDS_S,
- SETTINGS_SHOW_DAY_S,
- SETTINGS_SHOW_DATE_S,
- SETTINGS_SHOW_YEAR_S,
- SETTINGS_CUSTOM_TIME_FORMAT_S
- };
- const char * const calendar_settings[] = {
- SETTINGS_SHOW_CALENDAR_S,
- SETTINGS_SHOW_WEEK_NUMBERS_S
- };
- const char * const appointment_settings[] = {
- SETTINGS_SHOW_EVENTS_S,
- SETTINGS_TIME_FORMAT_S,
- SETTINGS_SHOW_SECONDS_S
- };
- const char * const location_settings[] = {
- SETTINGS_TIME_FORMAT_S,
- SETTINGS_SHOW_SECONDS_S,
- SETTINGS_CUSTOM_TIME_FORMAT_S,
- SETTINGS_SHOW_LOCATIONS_S,
- SETTINGS_LOCATIONS_S,
- SETTINGS_SHOW_DETECTED_S,
- SETTINGS_TIMEZONE_NAME_S
- };
- const char * const time_format_string_settings[] = {
- SETTINGS_TIME_FORMAT_S,
- SETTINGS_SHOW_SECONDS_S,
- SETTINGS_CUSTOM_TIME_FORMAT_S
- };
-
-
- /***
- **** Listen for settings changes
- ***/
-
- for (i=0, n=G_N_ELEMENTS(header_settings); i<n; i++)
- {
- g_string_printf (gstr, "changed::%s", header_settings[i]);
- g_signal_connect_swapped (p->settings, gstr->str,
- G_CALLBACK(rebuild_header_soon), self);
- }
-
- for (i=0, n=G_N_ELEMENTS(calendar_settings); i<n; i++)
- {
- g_string_printf (gstr, "changed::%s", calendar_settings[i]);
- g_signal_connect_swapped (p->settings, gstr->str,
- G_CALLBACK(rebuild_calendar_section_soon), self);
- }
-
- for (i=0, n=G_N_ELEMENTS(appointment_settings); i<n; i++)
- {
- g_string_printf (gstr, "changed::%s", appointment_settings[i]);
- g_signal_connect_swapped (p->settings, gstr->str,
- G_CALLBACK(rebuild_appointments_section_soon), self);
- }
-
- for (i=0, n=G_N_ELEMENTS(location_settings); i<n; i++)
- {
- g_string_printf (gstr, "changed::%s", location_settings[i]);
- g_signal_connect_swapped (p->settings, gstr->str,
- G_CALLBACK(rebuild_locations_section_soon), self);
- }
-
- /* The keys in time_format_string_settings affect the time format strings we build.
- When these change, we need to rebuild everything that has a time format string. */
- for (i=0, n=G_N_ELEMENTS(time_format_string_settings); i<n; i++)
- {
- g_string_printf (gstr, "changed::%s", time_format_string_settings[i]);
- g_signal_connect_swapped (p->settings, gstr->str,
- G_CALLBACK(on_local_time_jumped), self);
- }
-
- init_gactions (self);
-
- g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
- G_DBUS_PROXY_FLAGS_NONE,
- NULL,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- p->cancellable,
- on_login1_manager_proxy_ready,
- self);
-
- p->skew_timer = g_timeout_add_seconds (SKEW_CHECK_INTERVAL_SEC,
- skew_timer_func,
- self);
-
- p->own_id = g_bus_own_name (G_BUS_TYPE_SESSION,
- BUS_NAME,
- G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
- on_bus_acquired,
- NULL,
- on_name_lost,
- self,
- NULL);
-
- on_local_time_jumped (self);
-
- set_alarm_timer (self);
-
- for (i=0; i<N_PROFILES; ++i)
- create_menu (self, i);
-
- g_string_free (gstr, TRUE);
-}
-
-static void
-indicator_datetime_service_class_init (IndicatorDatetimeServiceClass * klass)
-{
- GObjectClass * object_class = G_OBJECT_CLASS (klass);
- const GParamFlags flags = G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS;
-
- object_class->dispose = 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;
-
- g_type_class_add_private (klass, sizeof (IndicatorDatetimeServicePrivate));
-
- signals[SIGNAL_NAME_LOST] = g_signal_new (
- INDICATOR_DATETIME_SERVICE_SIGNAL_NAME_LOST,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (IndicatorDatetimeServiceClass, name_lost),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- /* install properties */
-
- properties[PROP_0] = NULL;
-
- properties[PROP_CLOCK] = g_param_spec_object ("clock",
- "Clock",
- "The clock",
- INDICATOR_TYPE_DATETIME_CLOCK,
- flags);
-
- properties[PROP_PLANNER] = g_param_spec_object ("planner",
- "Planner",
- "The appointment provider",
- INDICATOR_TYPE_DATETIME_PLANNER,
- flags);
-
- g_object_class_install_properties (object_class, PROP_LAST, properties);
-}
-
-/***
-**** Public API
-***/
-
-IndicatorDatetimeService *
-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);
-}
-
-void
-indicator_datetime_service_set_calendar_date (IndicatorDatetimeService * self,
- GDateTime * date)
-{
- gboolean dirty;
- priv_t * p = self->priv;
-
- dirty = !date || !p->calendar_date || g_date_time_compare (date, p->calendar_date);
-
- /* update calendar_date */
- g_clear_pointer (&p->calendar_date, g_date_time_unref);
- if (date != NULL)
- p->calendar_date = g_date_time_ref (date);
-
- /* sync the menuitems and action states */
- if (dirty)
- 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)
-{
- priv_t * p;
-
- g_return_if_fail (INDICATOR_IS_DATETIME_SERVICE (self));
- g_return_if_fail ((planner == NULL) || INDICATOR_IS_DATETIME_PLANNER (planner));
-
- p = self->priv;
-
- /* clear the old planner & appointments */
-
- if (p->planner != NULL)
- {
- g_signal_handlers_disconnect_by_data (p->planner, self);
- g_clear_object (&p->planner);
- }
-
- g_clear_pointer (&p->upcoming_appointments, indicator_datetime_planner_free_appointments);
- g_clear_pointer (&p->calendar_appointments, indicator_datetime_planner_free_appointments);
-
- /* set the new planner & begin fetching appointments from it */
-
- if (planner != NULL)
- {
- p->planner = g_object_ref (planner);
-
- g_signal_connect_swapped (p->planner, "appointments-changed",
- G_CALLBACK(update_appointment_lists), self);
-
- update_appointment_lists (self);
- }
-}