aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README61
-rw-r--r--debian/changelog28
-rw-r--r--debian/control2
-rwxr-xr-xdebian/rules2
-rw-r--r--src/Makefile.am19
-rw-r--r--src/datetime-interface.c2
-rw-r--r--src/datetime-service.c1550
-rw-r--r--src/location-geoclue.h61
-rw-r--r--src/location.h68
-rw-r--r--src/main.c96
-rw-r--r--src/planner-eds.c330
-rw-r--r--src/planner-eds.h60
-rw-r--r--src/planner.c232
-rw-r--r--src/planner.h138
-rw-r--r--src/service.c638
-rw-r--r--src/service.h71
-rw-r--r--src/timezone-file.c240
-rw-r--r--src/timezone-file.h58
-rw-r--r--src/timezone-geoclue.c (renamed from src/location-geoclue.c)85
-rw-r--r--src/timezone-geoclue.h57
-rw-r--r--src/timezone.c (renamed from src/location.c)30
-rw-r--r--src/timezone.h75
22 files changed, 2818 insertions, 1085 deletions
diff --git a/README b/README
index e69de29..ebeed8b 100644
--- a/README
+++ b/README
@@ -0,0 +1,61 @@
+ACTIONS
+=======
+
+ * "aboutToShow"
+ Description: notifies the indicator that its menu is about to be shown.
+ Workitems that are expensive on startup (such as loading EDS to query
+ it for appointments, or loading GeoClue to guess our current location)
+ may be deferred until this is called.
+ So, calendarDay's state may not be fully populated until this is called.
+ FIXME: aboutToShow should be spec'ed once for all indicators, not ad-hoc
+
+ * "activateSettings"
+ Description: opens a page for changing indicator-datetime's settings
+ State: NULL
+ Parameter: NULL
+
+ * "activatePlanner"
+ Description: opens up the appointment editor.
+ State: NULL
+ Parameter: uint64 (a time_t hinting which day/time to show in the planner,
+ or 0 for the current day)
+
+ * "calendarDay"
+ Description: set which month/day should be given focus in the indicator's
+ calendar and to use as a starting point when listing upcoming
+ appointments in the indicator.
+ Client code implementing the calendar widget should call this
+ when the user clicks to a different day, month, or year.
+ State: a dictionary containing these key value pairs:
+ "calendarDay": string ("YYYY-MM-DD"). Used by the calendar menuitem
+ to know which year/month should be visible and which
+ day should have the cursor.
+ "daysWithAppointments": an array of day-of-month ints. Used by the
+ calendar menuitem to mark appointment days.
+ Parameter: uint64 (a time_t specifying which day to give focus to)
+
+ * "location"
+ Description: Sets the user's current location. Called by location menuitems.
+ State: string containing a location and a timezone
+ Parameter: string containing a location and a timezone
+
+
+CUSTOM MENUITEMS
+================
+
+ * Calendar
+ - x-canonical-type s "com.canonical.indicator.calendar"
+
+ * Appointment
+ - x-canonical-type s "com.canonical.indicator.appointment"
+ - x-canonical-color s color of the appt's type, to give a visual cue
+ - label s short summary of the appointment
+ - x-canonical-right-label s the date of the appointment
+
+ * Location
+ - x-canonical-type s "com.canonical.indicator.location"
+ - label s the location's name, eg "Oklahoma City"
+ - x-canonical-timezone s timezone that the location is in
+ - x-canonical-time-format s strftime format string
+
+
diff --git a/debian/changelog b/debian/changelog
index 3223098..7d949a1 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,31 @@
+indicator-datetime (12.10.3daily13.05.06.1-0ubuntu1) saucy; urgency=low
+
+ [ Sebastien Bacher ]
+ * [FFE] Use systemd-services rather than ubuntu-system-service
+ systemdcompatibility code (LP: #1153567)
+
+ [ Iain Lane ]
+ * Stop using ConsoleKit (LP: #1156613)
+
+ [ Mathieu Trudel-Lapierre ]
+ * [FFE] Use systemd-services rather than ubuntu-system-service
+ systemdcompatibility code (LP: #1153567)
+
+ [ Ubuntu daily release ]
+ * Automatic snapshot from revision 216
+
+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 06 May 2013 19:23:23 +0000
+
+indicator-datetime (12.10.3daily13.05.02-0ubuntu1) saucy; urgency=low
+
+ [ Charles Kerr ]
+ * g_critical hit when datetime indicator first shown (LP: #1175392)
+
+ [ Ubuntu daily release ]
+ * Automatic snapshot from revision 213
+
+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 02 May 2013 22:59:08 +0000
+
indicator-datetime (12.10.3daily13.03.26-0ubuntu1) raring; urgency=low
* Use systemd's service backend, ffe lp: #1153567
diff --git a/debian/control b/debian/control
index 7645232..41bdb0f 100644
--- a/debian/control
+++ b/debian/control
@@ -41,7 +41,7 @@ Depends: ${shlibs:Depends},
gnome-control-center,
geoclue-ubuntu-geoip | geoclue-provider,
systemd-services,
- systemd-shim
+ systemd-shim,
Recommends: indicator-applet | indicator-renderer,
evolution-data-server,
Description: Simple clock
diff --git a/debian/rules b/debian/rules
index f98cf93..a350b13 100755
--- a/debian/rules
+++ b/debian/rules
@@ -9,7 +9,7 @@ override_dh_autoreconf:
NOCONFIGURE=1 dh_autoreconf ./autogen.sh
override_dh_auto_configure:
- dh_auto_configure -- --disable-static
+ dh_auto_configure -- --disable-static --disable-silent-rules
override_dh_install:
find debian/indicator-datetime -name \*.la -delete
diff --git a/src/Makefile.am b/src/Makefile.am
index f9b8562..fee2245 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -10,17 +10,26 @@ indicator_datetime_service_SOURCES = \
datetime-interface.c \
datetime-interface.h \
gen-datetime-service.xml.c \
- datetime-service.c \
- location.c \
- location.h \
- location-geoclue.c \
- location-geoclue.h \
+ planner.c \
+ planner.h \
+ planner-eds.c \
+ planner-eds.h \
+ service.c \
+ service.h \
+ main.c \
+ timezone.c \
+ timezone.h \
+ timezone-file.c \
+ timezone-file.h \
+ timezone-geoclue.c \
+ timezone-geoclue.h \
utils.c \
utils.h \
dbus-shared.h \
settings-shared.h
indicator_datetime_service_CFLAGS = \
-Wall \
+ -Wextra -Wno-missing-field-initializers \
-Werror \
$(SERVICE_CFLAGS) \
$(COVERAGE_CFLAGS) \
diff --git a/src/datetime-interface.c b/src/datetime-interface.c
index e67be85..72c7437 100644
--- a/src/datetime-interface.c
+++ b/src/datetime-interface.c
@@ -108,7 +108,7 @@ datetime_interface_init (DatetimeInterface *self)
}
static void
-bus_get_cb (GObject * object, GAsyncResult * res, gpointer user_data)
+bus_get_cb (GObject * object G_GNUC_UNUSED, GAsyncResult * res, gpointer user_data)
{
GError * error = NULL;
GDBusConnection * connection = g_bus_get_finish(res, &error);
diff --git a/src/datetime-service.c b/src/datetime-service.c
index ff22db5..1a29949 100644
--- a/src/datetime-service.c
+++ b/src/datetime-service.c
@@ -7,16 +7,16 @@ Copyright 2010 Canonical Ltd.
Authors:
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
+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
+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
+You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -27,26 +27,21 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <glib/gi18n.h>
-#include <gio/gio.h>
-#include <math.h>
+#include <math.h> /* fabs() */
#include <libdbusmenu-gtk/menuitem.h>
#include <libdbusmenu-glib/server.h>
#include <libdbusmenu-glib/client.h>
#include <libdbusmenu-glib/menuitem.h>
-#include <time.h>
-#include <libecal/libecal.h>
-#include <libical/ical.h>
-#include <libedataserver/libedataserver.h>
-// Other users of ecal seem to also include these, not sure why they should be included by the above
-#include <libical/icaltime.h>
#include <cairo/cairo.h>
#include "datetime-interface.h"
#include "dbus-shared.h"
-#include "location-geoclue.h"
#include "settings-shared.h"
+#include "planner-eds.h"
+#include "timezone-file.h"
+#include "timezone-geoclue.h"
#include "utils.h"
/* how often to check for clock skew */
@@ -62,118 +57,120 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#define SETTINGS_APP_INVOCATION "gnome-control-center datetime"
#endif
-static gboolean update_appointment_menu_items (gpointer user_data);
-static void update_location_menu_items (void);
-static void day_timer_reset (void);
static gboolean get_greeter_mode (void);
static void quick_set_tz (DbusmenuMenuitem * menuitem, guint timestamp, gpointer user_data);
-static IndicatorService * service = NULL;
-static GMainLoop * mainloop = NULL;
-static DbusmenuServer * server = NULL;
static DbusmenuMenuitem * root = NULL;
static DatetimeInterface * dbus = NULL;
-/* Global Items */
-static DbusmenuMenuitem * date = NULL;
-static DbusmenuMenuitem * calendar = NULL;
-static DbusmenuMenuitem * settings = NULL;
-static DbusmenuMenuitem * events_separator = NULL;
-static DbusmenuMenuitem * locations_separator = NULL;
-static DbusmenuMenuitem * add_appointment = NULL;
-static DbusmenuMenuitem * appointments[MAX_APPOINTMENT_MENUITEMS];
-static GSList * location_menu_items = NULL;
-static GList * comp_instances = NULL;
-static gboolean updating_appointments = FALSE;
-static time_t start_time_appointments = (time_t) 0;
-static GSettings * conf = NULL;
-static ESourceRegistry * source_registry = NULL;
-static GList * appointment_sources = NULL;
-static IndicatorDatetimeLocation * geo_location = NULL;
-
-
-/* Our 2 important timezones */
-static gchar * current_timezone = NULL;
-
-struct comp_instance {
- ECalComponent *comp;
- time_t start;
- time_t end;
- ESource *source;
-};
+typedef struct IndicatorDatetimeService
+{
+ DbusmenuMenuitem * date;
+ DbusmenuMenuitem * calendar;
+ DbusmenuMenuitem * settings;
+ DbusmenuMenuitem * events_separator;
+ DbusmenuMenuitem * locations_separator;
+ DbusmenuMenuitem * add_appointment;
+ DbusmenuMenuitem * appointment_menuitems[MAX_APPOINTMENT_MENUITEMS];
+
+ GSList * location_menu_items;
+ gboolean updating_appointments;
+ time_t start_time_appointments;
+ GSettings * conf;
+
+ IndicatorDatetimeTimezone * geo_location;
+ IndicatorDatetimeTimezone * tz_file;
+ IndicatorDatetimePlanner * planner;
+
+ guint ecaltimer;
+ guint day_timer;
+}
+IndicatorDatetimeService;
+
+static void update_location_menu_items (IndicatorDatetimeService * self);
+static void update_appointment_menu_items (IndicatorDatetimeService * self);
+static void day_timer_reset (IndicatorDatetimeService * self);
/**
* A temp struct used by update_location_menu_items() for pruning duplicates and sorting.
*/
struct TimeLocation
{
- gint32 offset;
- gchar * zone;
- gchar * name;
- gboolean visible;
+ gint32 offset;
+ gchar * zone;
+ gchar * name;
+ gboolean visible;
};
+
static void
time_location_free (struct TimeLocation * loc)
{
- g_free (loc->name);
- g_free (loc->zone);
- g_free (loc);
+ g_free (loc->name);
+ g_free (loc->zone);
+ g_free (loc);
}
+
static struct TimeLocation*
time_location_new (const char * zone, const char * name, gboolean visible, time_t now)
{
- struct TimeLocation * loc = g_new (struct TimeLocation, 1);
- GTimeZone * tz = g_time_zone_new (zone);
- gint interval = g_time_zone_find_interval (tz, G_TIME_TYPE_UNIVERSAL, now);
- loc->offset = g_time_zone_get_offset (tz, interval);
- loc->zone = g_strdup (zone);
- loc->name = g_strdup (name);
- loc->visible = visible;
- g_time_zone_unref (tz);
- g_debug ("%s zone '%s' name '%s' offset is %d", G_STRLOC, zone, name, (int)loc->offset);
- return loc;
+ struct TimeLocation * loc = g_new (struct TimeLocation, 1);
+ GTimeZone * tz = g_time_zone_new (zone);
+ gint interval = g_time_zone_find_interval (tz, G_TIME_TYPE_UNIVERSAL, now);
+ loc->offset = g_time_zone_get_offset (tz, interval);
+ loc->zone = g_strdup (zone);
+ loc->name = g_strdup (name);
+ loc->visible = visible;
+ g_time_zone_unref (tz);
+ g_debug ("%s zone '%s' name '%s' offset is %d", G_STRLOC, zone, name, (int)loc->offset);
+ return loc;
}
+
static int
time_location_compare (const struct TimeLocation * a, const struct TimeLocation * b)
{
- int ret = a->offset - b->offset; /* primary key */
- if (!ret)
- ret = g_strcmp0 (a->name, b->name); /* secondary key */
- if (!ret)
- ret = a->visible - b->visible; /* tertiary key */
- g_debug ("%s comparing '%s' (%d) to '%s' (%d), returning %d", G_STRLOC, a->name, (int)a->offset, b->name, (int)b->offset, ret);
- return ret;
+ int ret = a->offset - b->offset; /* primary key */
+ if (!ret)
+ ret = g_strcmp0 (a->name, b->name); /* secondary key */
+ if (!ret)
+ ret = a->visible - b->visible; /* tertiary key */
+ g_debug ("%s comparing '%s' (%d) to '%s' (%d), returning %d", G_STRLOC, a->name, (int)a->offset, b->name, (int)b->offset, ret);
+ return ret;
}
+
static GSList*
locations_add (GSList * locations, const char * zone, const char * name, gboolean visible, time_t now)
{
- struct TimeLocation * loc = time_location_new (zone, name, visible, now);
+ struct TimeLocation * loc = time_location_new (zone, name, visible, now);
- if (g_slist_find_custom (locations, loc, (GCompareFunc)time_location_compare) == NULL) {
- g_debug ("%s Adding zone '%s', name '%s'", G_STRLOC, zone, name);
- locations = g_slist_append (locations, loc);
- } else {
- g_debug("%s Skipping duplicate zone '%s' name '%s'", G_STRLOC, zone, name);
- time_location_free (loc);
- }
- return locations;
+ if (g_slist_find_custom (locations, loc, (GCompareFunc)time_location_compare) == NULL)
+ {
+ g_debug ("%s Adding zone '%s', name '%s'", G_STRLOC, zone, name);
+ locations = g_slist_append (locations, loc);
+ }
+ else
+ {
+ g_debug("%s Skipping duplicate zone '%s' name '%s'", G_STRLOC, zone, name);
+ time_location_free (loc);
+ }
+
+ return locations;
}
/* Update the timezone entries */
static void
-update_location_menu_items (void)
+update_location_menu_items (IndicatorDatetimeService * self)
{
/* if we're in greeter mode, don't bother */
- if (locations_separator == NULL)
+ if (self->locations_separator == NULL)
return;
/* remove the previous locations */
- while (location_menu_items != NULL) {
- DbusmenuMenuitem * item = DBUSMENU_MENUITEM(location_menu_items->data);
- location_menu_items = g_slist_remove(location_menu_items, item);
- dbusmenu_menuitem_child_delete(root, DBUSMENU_MENUITEM(item));
- g_object_unref(G_OBJECT(item));
+ while (self->location_menu_items != NULL) {
+ DbusmenuMenuitem * item = DBUSMENU_MENUITEM(self->location_menu_items->data);
+ self->location_menu_items = g_slist_remove (self->location_menu_items, item);
+ dbusmenu_menuitem_child_delete (root, DBUSMENU_MENUITEM(item));
+ g_object_unref (item);
}
/***
@@ -182,13 +179,13 @@ update_location_menu_items (void)
***/
GSList * locations = NULL;
- const time_t now = time(NULL);
+ const time_t now = time(NULL); /* FIXME: unmockable */
/* maybe add geo_timezone */
- if (geo_location != NULL) {
- const char * geo_timezone = indicator_datetime_location_get_timezone (geo_location);
+ if (self->geo_location != NULL) {
+ const char * geo_timezone = indicator_datetime_timezone_get_timezone (self->geo_location);
if (geo_timezone && *geo_timezone) {
- const gboolean visible = g_settings_get_boolean (conf, SETTINGS_SHOW_DETECTED_S);
+ const gboolean visible = g_settings_get_boolean (self->conf, SETTINGS_SHOW_DETECTED_S);
gchar * name = get_current_zone_name (geo_timezone);
locations = locations_add (locations, geo_timezone, name, visible, now);
g_free (name);
@@ -196,19 +193,22 @@ update_location_menu_items (void)
}
/* maybe add current_timezone */
- if (current_timezone != NULL) {
- const gboolean visible = g_settings_get_boolean (conf, SETTINGS_SHOW_DETECTED_S);
- gchar * name = get_current_zone_name (current_timezone);
- locations = locations_add (locations, current_timezone, name, visible, now);
- g_free (name);
+ if (self->tz_file != NULL) {
+ const char * tz = indicator_datetime_timezone_get_timezone (self->tz_file);
+ if (tz && *tz) {
+ const gboolean visible = g_settings_get_boolean (self->conf, SETTINGS_SHOW_DETECTED_S);
+ gchar * name = get_current_zone_name (tz);
+ locations = locations_add (locations, tz, name, visible, now);
+ g_free (name);
+ }
}
/* maybe add the user-specified custom locations */
- gchar ** user_locations = g_settings_get_strv (conf, SETTINGS_LOCATIONS_S);
- if (user_locations != NULL) {
- gint i;
+ gchar ** user_locations = g_settings_get_strv (self->conf, SETTINGS_LOCATIONS_S);
+ if (user_locations != NULL) {
+ guint i;
const guint location_count = g_strv_length (user_locations);
- const gboolean visible = g_settings_get_boolean (conf, SETTINGS_SHOW_LOCATIONS_S);
+ const gboolean visible = g_settings_get_boolean (self->conf, SETTINGS_SHOW_LOCATIONS_S);
g_debug ("%s Found %u user-specified locations", G_STRLOC, location_count);
for (i=0; i<location_count; i++) {
gchar * zone;
@@ -223,7 +223,7 @@ update_location_menu_items (void)
}
/* finally create menuitems for each location */
- gint offset = dbusmenu_menuitem_get_position (locations_separator, root)+1;
+ gint offset = dbusmenu_menuitem_get_position (self->locations_separator, root)+1;
GSList * l;
gboolean have_visible_location = FALSE;
for (l=locations; l!=NULL; l=l->next) {
@@ -238,7 +238,7 @@ update_location_menu_items (void)
dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, loc->visible);
dbusmenu_menuitem_child_add_position (root, item, offset++);
g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL);
- location_menu_items = g_slist_append (location_menu_items, item);
+ self->location_menu_items = g_slist_append (self->location_menu_items, item);
if (loc->visible)
have_visible_location = TRUE;
time_location_free (loc);
@@ -247,32 +247,11 @@ update_location_menu_items (void)
locations = NULL;
/* if there's at least one item being shown, show the separator too */
- dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, have_visible_location);
+ dbusmenu_menuitem_property_set_bool (self->locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, have_visible_location);
}
-/* Update the current timezone */
static void
-update_current_timezone (void) {
- /* Clear old data */
- if (current_timezone != NULL) {
- g_free(current_timezone);
- current_timezone = NULL;
- }
-
- current_timezone = read_timezone ();
- if (current_timezone == NULL) {
- return;
- }
-
- g_debug("System timezone is: %s", current_timezone);
-
- update_location_menu_items();
-
- return;
-}
-
-static void
-quick_set_tz_cb (GObject *object, GAsyncResult *res, gpointer data)
+quick_set_tz_cb (GObject *object, GAsyncResult *res, gpointer data G_GNUC_UNUSED)
{
GError * error = NULL;
GVariant * answers = g_dbus_proxy_call_finish (G_DBUS_PROXY (object), res, &error);
@@ -287,7 +266,7 @@ quick_set_tz_cb (GObject *object, GAsyncResult *res, gpointer data)
}
static void
-quick_set_tz_proxy_cb (GObject *object, GAsyncResult *res, gpointer zone)
+quick_set_tz_proxy_cb (GObject *object G_GNUC_UNUSED, GAsyncResult *res, gpointer zone)
{
GError * error = NULL;
@@ -307,7 +286,7 @@ quick_set_tz_proxy_cb (GObject *object, GAsyncResult *res, gpointer zone)
}
static void
-quick_set_tz (DbusmenuMenuitem * menuitem, guint timestamp, gpointer user_data)
+quick_set_tz (DbusmenuMenuitem * menuitem, guint timestamp G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED)
{
const gchar * tz = dbusmenu_menuitem_property_get(menuitem, TIMEZONE_MENUITEM_PROP_ZONE);
g_debug("Quick setting timezone to: %s", tz);
@@ -334,29 +313,27 @@ quick_set_tz (DbusmenuMenuitem * menuitem, guint timestamp, gpointer user_data)
/* Updates the label in the date menuitem */
static gboolean
-update_datetime (gpointer user_data)
+update_datetime (gpointer gself)
{
GDateTime *datetime;
- gchar *utf8;
+ gchar * utf8;
+ IndicatorDatetimeService * self = gself;
g_debug("Updating Date/Time");
- datetime = g_date_time_new_now_local ();
+ datetime = g_date_time_new_now_local (); /* FIXME: unmockable */
if (datetime == NULL) {
g_warning("Error getting local time");
- dbusmenu_menuitem_property_set(date, DBUSMENU_MENUITEM_PROP_LABEL, _("Error getting time"));
- g_date_time_unref (datetime);
+ dbusmenu_menuitem_property_set(self->date, DBUSMENU_MENUITEM_PROP_LABEL, _("Error getting time"));
return FALSE;
}
/* eranslators: strftime(3) style date format on top of the menu when you click on the clock */
utf8 = g_date_time_format (datetime, _("%A, %e %B %Y"));
-
- dbusmenu_menuitem_property_set(date, DBUSMENU_MENUITEM_PROP_LABEL, utf8);
-
- g_date_time_unref (datetime);
+ dbusmenu_menuitem_property_set (self->date, DBUSMENU_MENUITEM_PROP_LABEL, utf8);
g_free(utf8);
+ g_date_time_unref (datetime);
return G_SOURCE_REMOVE;
}
@@ -383,172 +360,193 @@ activate_cb (DbusmenuMenuitem * menuitem G_GNUC_UNUSED,
}
static gboolean
-update_appointment_menu_items_idle (gpointer user_data)
+update_appointment_menu_items_idle (gpointer gself)
{
- update_appointment_menu_items(user_data);
- return FALSE;
+ update_appointment_menu_items (gself);
+
+ return G_SOURCE_REMOVE;
}
static void
-hide_all_appointments (void)
+update_appointment_menu_items_soon (IndicatorDatetimeService * self)
{
- int i;
+ g_idle_add (update_appointment_menu_items_idle, self);
+}
- for (i=0; i<MAX_APPOINTMENT_MENUITEMS; i++) {
- if (appointments[i]) {
- dbusmenu_menuitem_property_set_bool(appointments[i], DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
- dbusmenu_menuitem_property_set_bool(appointments[i], DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- }
- }
+static void
+hide_all_appointments (IndicatorDatetimeService * self)
+{
+ int i;
+
+ for (i=0; i<MAX_APPOINTMENT_MENUITEMS; i++)
+ {
+ if (self->appointment_menuitems[i])
+ {
+ dbusmenu_menuitem_property_set_bool (self->appointment_menuitems[i], DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
+ dbusmenu_menuitem_property_set_bool (self->appointment_menuitems[i], DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+ }
+ }
}
static gboolean
-month_changed_cb (DbusmenuMenuitem * menuitem, gchar *name, GVariant *variant, guint timestamp)
+month_changed_cb (DbusmenuMenuitem * menuitem,
+ gchar * name G_GNUC_UNUSED,
+ GVariant * variant,
+ guint timestamp G_GNUC_UNUSED,
+ gpointer gself)
{
- start_time_appointments = (time_t)g_variant_get_uint32(variant);
+ IndicatorDatetimeService * self = gself;
+
+ self->start_time_appointments = (time_t)g_variant_get_uint32(variant);
- g_debug("Received month changed with timestamp: %d -> %s",(int)start_time_appointments, ctime(&start_time_appointments));
- /* By default one of the first things we do is
- clear the marks as we don't know the correct
- ones yet and we don't want to confuse the
- user. */
- dbusmenu_menuitem_property_remove(menuitem, CALENDAR_MENUITEM_PROP_MARKS);
-
- g_idle_add(update_appointment_menu_items_idle, NULL);
- return TRUE;
+ g_debug("Received month changed with timestamp: %d -> %s",(int)self->start_time_appointments, ctime(&self->start_time_appointments));
+
+ /* By default, one of the first things we do is
+ clear the marks as we don't know the correct
+ ones yet and we don't want to confuse the user. */
+
+ dbusmenu_menuitem_property_remove(menuitem, CALENDAR_MENUITEM_PROP_MARKS);
+
+ update_appointment_menu_items_soon (self);
+ return TRUE;
}
static gboolean
-day_selected_cb (DbusmenuMenuitem * menuitem, gchar *name, GVariant *variant, guint timestamp)
+day_selected_cb (DbusmenuMenuitem * menuitem,
+ gchar * name G_GNUC_UNUSED,
+ GVariant * variant,
+ guint timestamp G_GNUC_UNUSED,
+ gpointer gself)
{
- time_t new_time = (time_t)g_variant_get_uint32(variant);
- g_warn_if_fail(new_time != 0);
+ time_t new_time;
+ IndicatorDatetimeService * self = gself;
- if (start_time_appointments == 0 || new_time == 0) {
- /* If we've got nothing, assume everyhting is going to
- get repopulated, let's start with a clean slate */
- dbusmenu_menuitem_property_remove(menuitem, CALENDAR_MENUITEM_PROP_MARKS);
- } else {
- /* No check to see if we changed months. If we did we'll
- want to clear the marks. Otherwise we're cool keeping
- them around. */
- struct tm start_tm;
- struct tm new_tm;
+ new_time = (time_t)g_variant_get_uint32(variant);
- localtime_r(&start_time_appointments, &start_tm);
- localtime_r(&new_time, &new_tm);
+ if (self->start_time_appointments == 0 || new_time == 0)
+ {
+ /* If we've got nothing, assume everyhting is going to
+ get repopulated, let's start with a clean slate */
+ dbusmenu_menuitem_property_remove (menuitem, CALENDAR_MENUITEM_PROP_MARKS);
+ }
+ else
+ {
+ /* No check to see if we changed months. If we did we'll
+ want to clear the marks. Otherwise we're cool keeping
+ them around. */
+ struct tm start_tm;
+ struct tm new_tm;
- if (start_tm.tm_mon != new_tm.tm_mon) {
- dbusmenu_menuitem_property_remove(menuitem, CALENDAR_MENUITEM_PROP_MARKS);
- }
- }
+ localtime_r (&self->start_time_appointments, &start_tm);
+ localtime_r (&new_time, &new_tm);
+
+ if (start_tm.tm_mon != new_tm.tm_mon)
+ dbusmenu_menuitem_property_remove(menuitem, CALENDAR_MENUITEM_PROP_MARKS);
+ }
- start_time_appointments = new_time;
+ self->start_time_appointments = new_time;
- g_debug("Received day-selected with timestamp: %d -> %s",(int)start_time_appointments, ctime(&start_time_appointments));
- g_idle_add(update_appointment_menu_items_idle, NULL);
+ g_debug ("Received day-selected with timestamp: %d -> %s",(int)self->start_time_appointments, ctime(&self->start_time_appointments));
+ update_appointment_menu_items_soon (self);
- return TRUE;
+ return TRUE;
}
static gboolean
day_selected_double_click_cb (DbusmenuMenuitem * menuitem G_GNUC_UNUSED,
gchar * name G_GNUC_UNUSED,
GVariant * variant,
- guint timestamp G_GNUC_UNUSED)
+ guint timestamp G_GNUC_UNUSED,
+ gpointer gself)
{
- const time_t evotime = (time_t)g_variant_get_uint32(variant);
-
- g_debug("Received day-selected-double-click with timestamp: %d -> %s",(int)evotime, ctime(&evotime));
-
- gchar *ad = isodate_from_time_t(evotime);
- gchar *cmd = g_strconcat("evolution calendar:///?startdate=", ad, NULL);
-
- execute_command (cmd);
+ time_t evotime;
+ GDateTime * dt;
+ IndicatorDatetimeService * self = gself;
- g_free (cmd);
- g_free (ad);
-
- return TRUE;
+ evotime = (time_t) g_variant_get_uint32 (variant);
+ dt = g_date_time_new_from_unix_utc (evotime);
+ indicator_datetime_planner_activate_time (self->planner, dt);
+ g_date_time_unref (dt);
+
+ return TRUE;
}
-static guint ecaltimer = 0;
+
+static gboolean
+update_appointment_menu_items_timerfunc (gpointer self)
+{
+ update_appointment_menu_items (self);
+ return G_SOURCE_CONTINUE;
+}
static void
-start_ecal_timer(void)
+start_ecal_timer (IndicatorDatetimeService * self)
{
- if (ecaltimer != 0) {
- g_source_remove(ecaltimer);
- ecaltimer = 0;
- }
- if (update_appointment_menu_items(NULL))
- ecaltimer = g_timeout_add_seconds(60*5, update_appointment_menu_items, NULL);
+ if (self->ecaltimer != 0)
+ self->ecaltimer = g_timeout_add_seconds (60*5, update_appointment_menu_items_timerfunc, self);
}
static void
-stop_ecal_timer(void)
+stop_ecal_timer (IndicatorDatetimeService * self)
{
- if (ecaltimer != 0) {
- g_source_remove(ecaltimer);
- ecaltimer = 0;
- }
+ if (self->ecaltimer != 0)
+ {
+ g_source_remove (self->ecaltimer);
+ self->ecaltimer = 0;
+ }
}
+
static gboolean
-idle_start_ecal_timer (gpointer data)
+idle_start_ecal_timer (gpointer gself)
{
- start_ecal_timer();
- return FALSE;
+ start_ecal_timer (gself);
+
+ return G_SOURCE_REMOVE;
}
static void
-show_events_changed (void)
+show_events_changed (IndicatorDatetimeService * self)
{
- if (g_settings_get_boolean(conf, SETTINGS_SHOW_EVENTS_S)) {
- dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- start_ecal_timer();
- } else {
- dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- hide_all_appointments ();
- stop_ecal_timer();
- }
-}
+ const gboolean b = g_settings_get_boolean (self->conf, SETTINGS_SHOW_EVENTS_S);
-static gboolean
-calendar_app_is_usable (void)
-{
- /* confirm that it's installed... */
- gchar *evo = g_find_program_in_path("evolution");
- if (evo == NULL)
- return FALSE;
- g_debug ("found calendar app: '%s'", evo);
- g_free (evo);
+ dbusmenu_menuitem_property_set_bool (self->add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, b);
+ dbusmenu_menuitem_property_set_bool (self->events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, b);
- /* see if there are any calendar sources */
- return appointment_sources > 0;
+ if (b)
+ {
+ start_ecal_timer (self);
+ }
+ else
+ {
+ hide_all_appointments (self);
+ stop_ecal_timer (self);
+ }
}
+
/* Looks for the calendar application and enables the item if
we have one, starts ecal timer if events are turned on */
static gboolean
-check_for_calendar (gpointer user_data)
+check_for_calendar (gpointer gself)
{
- g_return_val_if_fail (calendar != NULL, FALSE);
+ gboolean b;
+ IndicatorDatetimeService * self = gself;
+
+ g_return_val_if_fail (self->calendar != NULL, FALSE);
- dbusmenu_menuitem_property_set_bool(date, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+ dbusmenu_menuitem_property_set_bool(self->date, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
- if (!get_greeter_mode () && calendar_app_is_usable()) {
+ if (!get_greeter_mode () && indicator_datetime_planner_is_configured(self->planner)) {
int i;
int pos = 2;
- g_signal_connect (G_OBJECT(date), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+ g_signal_connect (G_OBJECT(self->date), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
G_CALLBACK (activate_cb), "evolution -c calendar");
- events_separator = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set(events_separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
- dbusmenu_menuitem_child_add_position(root, events_separator, pos++);
+ self->events_separator = dbusmenu_menuitem_new();
+ dbusmenu_menuitem_property_set(self->events_separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
+ dbusmenu_menuitem_child_add_position(root, self->events_separator, pos++);
for (i=0; i<MAX_APPOINTMENT_MENUITEMS; i++)
{
@@ -556,631 +554,452 @@ check_for_calendar (gpointer user_data)
dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_TYPE, APPOINTMENT_MENUITEM_TYPE);
dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- appointments[i] = item;
+ self->appointment_menuitems[i] = item;
dbusmenu_menuitem_child_add_position(root, item, pos++);
}
- add_appointment = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set (add_appointment, DBUSMENU_MENUITEM_PROP_LABEL, _("Add Event…"));
- dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
- g_signal_connect(G_OBJECT(add_appointment), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), "evolution -c calendar");
- dbusmenu_menuitem_child_add_position (root, add_appointment, pos++);
+ self->add_appointment = dbusmenu_menuitem_new();
+ dbusmenu_menuitem_property_set (self->add_appointment, DBUSMENU_MENUITEM_PROP_LABEL, _("Add Event…"));
+ dbusmenu_menuitem_property_set_bool(self->add_appointment, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+ g_signal_connect(G_OBJECT(self->add_appointment), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), "evolution -c calendar");
+ dbusmenu_menuitem_child_add_position (root, self->add_appointment, pos++);
- if (g_settings_get_boolean(conf, SETTINGS_SHOW_EVENTS_S)) {
- dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- g_idle_add((GSourceFunc)idle_start_ecal_timer, NULL);
+ if (g_settings_get_boolean(self->conf, SETTINGS_SHOW_EVENTS_S)) {
+ dbusmenu_menuitem_property_set_bool(self->add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+ dbusmenu_menuitem_property_set_bool(self->events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+ g_idle_add((GSourceFunc)idle_start_ecal_timer, self);
} else {
- dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- stop_ecal_timer();
+ dbusmenu_menuitem_property_set_bool(self->add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+ dbusmenu_menuitem_property_set_bool(self->events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+ stop_ecal_timer (self);
}
// Connect to calendar events
- g_signal_connect(calendar, "event::month-changed", G_CALLBACK(month_changed_cb), NULL);
- g_signal_connect(calendar, "event::day-selected", G_CALLBACK(day_selected_cb), NULL);
- g_signal_connect(calendar, "event::day-selected-double-click", G_CALLBACK(day_selected_double_click_cb), NULL);
+ g_signal_connect(self->calendar, "event::month-changed", G_CALLBACK(month_changed_cb), self);
+ g_signal_connect(self->calendar, "event::day-selected", G_CALLBACK(day_selected_cb), self);
+ g_signal_connect(self->calendar, "event::day-selected-double-click", G_CALLBACK(day_selected_double_click_cb), self);
} else {
g_debug("Unable to find calendar app.");
- if (add_appointment != NULL)
- dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- if (events_separator != NULL)
- dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+ if (self->add_appointment != NULL)
+ dbusmenu_menuitem_property_set_bool(self->add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+ if (self->events_separator != NULL)
+ dbusmenu_menuitem_property_set_bool(self->events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
}
- if (g_settings_get_boolean(conf, SETTINGS_SHOW_CALENDAR_S)) {
- dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
- dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- } else {
- dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
- dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- }
+ b = g_settings_get_boolean (self->conf, SETTINGS_SHOW_CALENDAR_S);
+ dbusmenu_menuitem_property_set_bool(self->calendar, DBUSMENU_MENUITEM_PROP_ENABLED, b);
+ dbusmenu_menuitem_property_set_bool(self->calendar, DBUSMENU_MENUITEM_PROP_VISIBLE, b);
return FALSE;
}
-static gint
-compare_comp_instances (gconstpointer ga, gconstpointer gb)
+static GdkPixbuf *
+create_color_icon_pixbuf (const char * color_spec)
{
- const struct comp_instance * a = ga;
- const struct comp_instance * b = gb;
+ static int width = -1;
+ static int height = -1;
+ GdkPixbuf * pixbuf = NULL;
- /* sort by start time */
- if (a->start < b->start) return -1;
- if (a->start > b->start) return 1;
- return 0;
-}
+ if (width == -1)
+ {
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height);
+ width = CLAMP (width, 10, 30);
+ height = CLAMP (height, 10, 30);
+ }
-static struct comp_instance*
-comp_instance_new (ECalComponent * comp, time_t start, time_t end, ESource * source)
-{
- g_debug("Using times start %s, end %s", ctime(&start), ctime(&end));
-
- struct comp_instance *ci = g_new (struct comp_instance, 1);
- ci->comp = g_object_ref (comp);
- ci->source = source;
- ci->start = start;
- ci->end = end;
- return ci;
-}
-static void
-comp_instance_free (struct comp_instance* ci)
-{
- if (ci != NULL) {
- g_clear_object (&ci->comp);
- g_free (ci);
- }
-}
+ if (color_spec && *color_spec)
+ {
+ cairo_surface_t * surface;
+ cairo_t * cr;
+ GdkRGBA rgba;
-static gboolean
-populate_appointment_instances (ECalComponent * comp,
- time_t start,
- time_t end,
- gpointer data)
-{
- const ECalComponentVType vtype = e_cal_component_get_vtype (comp);
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ cr = cairo_create (surface);
- if ((vtype == E_CAL_COMPONENT_EVENT) || (vtype == E_CAL_COMPONENT_TODO))
- {
- icalproperty_status status;
- e_cal_component_get_status (comp, &status);
+ if (gdk_rgba_parse (&rgba, color_spec))
+ gdk_cairo_set_source_rgba (cr, &rgba);
- if ((status != ICAL_STATUS_COMPLETED) && (status != ICAL_STATUS_CANCELLED))
- {
- gchar * str = e_cal_component_get_as_string (comp);
- g_debug("Appending item %s", str);
- struct comp_instance *ci = comp_instance_new (comp, start, end, E_SOURCE(data));
- comp_instances = g_list_append (comp_instances, ci);
- g_free (str);
- }
- }
+ cairo_paint (cr);
+ cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
+ cairo_set_line_width (cr, 1);
+ cairo_rectangle (cr, 0.5, 0.5, width-1, height-1);
+ cairo_stroke (cr);
+
+ pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+ }
- return TRUE; /* tell eds to keep iterating */
+ return pixbuf;
}
-/* Populate the menu with todays, next 5 appointments.
+
+/**
+ * Populate the menu with todays, next MAX_APPOINTMENT_MENUITEMS appointments.
* we should hook into the ABOUT TO SHOW signal and use that to update the appointments.
* Experience has shown that caldav's and webcals can be slow to load from eds
- * this is a problem mainly on the EDS side of things, not ours.
+ * this is a problem mainly on the EDS side of things, not ours.
*/
-static gboolean
-update_appointment_menu_items (gpointer user_data __attribute__ ((unused)))
+static void
+update_appointment_menu_items (IndicatorDatetimeService * self)
{
- // FFR: we should take into account short term timers, for instance
- // tea timers, pomodoro timers etc... that people may add, this is hinted to in the spec.
- g_debug("Update appointments called");
- if (calendar == NULL) return FALSE;
- if (!g_settings_get_boolean(conf, SETTINGS_SHOW_EVENTS_S)) return FALSE;
- if (updating_appointments) return TRUE;
- updating_appointments = TRUE;
-
- time_t curtime = 0, t1 = 0, t2 = 0;
- GList *l, *s;
- GError *gerror = NULL;
- gint i;
- gint width = 0, height = 0;
- GList * sources = NULL;
-
- // Get today & work out query times
- time(&curtime);
- struct tm *today = localtime(&curtime);
- const int mday = today->tm_mday;
- const int mon = today->tm_mon;
- const int year = today->tm_year;
-
- int start_month_saved = mon;
-
- struct tm *start_tm = NULL;
- int this_year = today->tm_year + 1900;
- int days[12]={31,28,31,30,31,30,31,31,30,31,30,31};
- if ((this_year % 400 == 0) || (this_year % 100 > 0 && this_year % 4 == 0)) days[1] = 29;
-
- int highlightdays = days[mon] - mday + 1;
- t1 = curtime; // By default the current time is the appointment start time.
-
- if (start_time_appointments > 0) {
- start_tm = localtime(&start_time_appointments);
- int start_month = start_tm->tm_mon;
- start_month_saved = start_month;
- int start_year = start_tm->tm_year + 1900;
- if ((start_month != mon) || (start_year != this_year)) {
- // Set t1 to the start of that month.
- struct tm month_start = {0};
- month_start.tm_year = start_tm->tm_year;
- month_start.tm_mon = start_tm->tm_mon;
- month_start.tm_mday = 1;
- t1 = mktime(&month_start);
- highlightdays = days[start_month];
- }
- }
-
- g_debug("Will highlight %d days from %s", highlightdays, ctime(&t1));
+ char * str;
+ GSList * l;
+ GSList * appointments;
+ gint i;
+ GDateTime * begin;
+ GDateTime * end;
+ GdkPixbuf * pixbuf;
+ gint apt_output;
+ GVariantBuilder markeddays;
+ GVariant * marks;
+
+ // FFR: we should take into account short term timers, for instance
+ // tea timers, pomodoro timers etc... that people may add, this is hinted to in the spec.
+
+ g_debug ("Update appointments called");
+
+ if (self->calendar == NULL)
+ return;
+ if (!g_settings_get_boolean (self->conf, SETTINGS_SHOW_EVENTS_S))
+ return;
+ if (self->updating_appointments)
+ return;
- highlightdays = highlightdays + 7; // Minimum of 7 days ahead
- t2 = t1 + (time_t) (highlightdays * 24 * 60 * 60);
+ self->updating_appointments = TRUE;
- // clear any previous comp_instances
- g_list_free_full (comp_instances, (GDestroyNotify)comp_instance_free);
- comp_instances = NULL;
-
- // Generate instances for all sources
- for (s=appointment_sources; s!=NULL; s=s->next) {
-
- ESource *source = E_SOURCE (s->data);
- ECalClient *ecal = e_cal_client_new(source, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, &gerror);
-
- if (!ecal) {
- g_debug ("Cannot create ecal client: %s", gerror->message);
- g_clear_error (&gerror);
- continue;
- }
-
- icaltimezone* current_zone = icaltimezone_get_builtin_timezone(current_timezone);
- if (!current_zone) {
- // current_timezone may be a TZID?
- current_zone = icaltimezone_get_builtin_timezone_from_tzid(current_timezone);
- }
-
- e_cal_client_set_default_timezone (ecal, current_zone);
-
- g_debug("Checking if source %s is enabled", e_source_get_uid(source));
- if (e_source_get_enabled (source)) {
- g_debug("source is enabled, generating instances");
-
- if (!e_client_open_sync (E_CLIENT (ecal), TRUE, NULL, &gerror)) {
- g_debug("Failed to open source: %s", gerror->message);
- g_clear_error (&gerror);
- g_object_unref(ecal);
- continue;
- }
-
- e_cal_client_generate_instances_sync (ecal,
- t1,
- t2,
- populate_appointment_instances,
- source);
- }
- g_object_unref(ecal);
- }
-
- g_debug("Number of ECalComponents returned: %d", g_list_length(comp_instances));
- GList *sorted_comp_instances = g_list_sort(comp_instances, compare_comp_instances);
- comp_instances = NULL;
- g_debug("Components sorted");
-
- hide_all_appointments ();
-
- gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
- if (width <= 0) width = 12;
- if (height <= 0) height = 12;
- if (width > 30) width = 12;
- if (height > 30) height = 12;
+ g_variant_builder_init (&markeddays, G_VARIANT_TYPE ("ai"));
+
+ if (self->start_time_appointments != 0)
+ begin = g_date_time_new_from_unix_local (self->start_time_appointments);
+ else
+ begin = g_date_time_new_now_local (); /* FIXME: unmockable */
+ end = g_date_time_add_months (begin, 1);
+ indicator_datetime_planner_set_timezone (self->planner, indicator_datetime_timezone_get_timezone (self->tz_file));
+ appointments = indicator_datetime_planner_get_appointments (self->planner, begin, end);
+
+ hide_all_appointments (self);
+
+ /* decide whether to use 12hr or 24hr format */
+ str = g_settings_get_string (self->conf, SETTINGS_TIME_FORMAT_S);
+ if (g_strcmp0 (str, "12-hour") == 0)
+ apt_output = SETTINGS_TIME_12_HOUR;
+ else if (g_strcmp0 (str, "24-hour") == 0)
+ apt_output = SETTINGS_TIME_24_HOUR;
+ else if (is_locale_12h())
+ apt_output = SETTINGS_TIME_12_HOUR;
+ else
+ apt_output = SETTINGS_TIME_24_HOUR;
+ g_free (str);
- gchar *time_format_str = g_settings_get_string(conf, SETTINGS_TIME_FORMAT_S);
- gint apt_output;
- if (g_strcmp0(time_format_str, "12-hour") == 0) {
- apt_output = SETTINGS_TIME_12_HOUR;
- } else if (g_strcmp0(time_format_str, "24-hour") == 0) {
- apt_output = SETTINGS_TIME_24_HOUR;
- } else if (is_locale_12h()) {
- apt_output = SETTINGS_TIME_12_HOUR;
- } else {
- apt_output = SETTINGS_TIME_24_HOUR;
- }
- g_free (time_format_str);
-
- GVariantBuilder markeddays;
- g_variant_builder_init (&markeddays, G_VARIANT_TYPE ("ai"));
-
- i = 0;
- for (l = sorted_comp_instances; l; l = l->next) {
- struct comp_instance *ci = l->data;
- ECalComponent *ecalcomp = ci->comp;
- char right[20];
- //const gchar *uri;
- DbusmenuMenuitem * item;
-
- ECalComponentVType vtype = e_cal_component_get_vtype (ecalcomp);
- struct tm due_data = {0};
- struct tm *due = NULL;
- if (vtype == E_CAL_COMPONENT_EVENT) due = localtime_r(&ci->start, &due_data);
- else if (vtype == E_CAL_COMPONENT_TODO) due = localtime_r(&ci->end, &due_data);
- else continue;
-
- const int dmday = due->tm_mday;
- const int dmon = due->tm_mon;
- const int dyear = due->tm_year;
-
- if (start_month_saved == dmon) {
- // Mark day if our query hasn't hit the next month.
- g_debug("Adding marked date %s, %d", ctime(&ci->start), dmday);
- g_variant_builder_add (&markeddays, "i", dmday);
- }
+ i = 0;
+ for (l=appointments; l!=NULL; l=l->next)
+ {
+ GDateTime * due;
+ DbusmenuMenuitem * item;
+ const struct IndicatorDatetimeAppt * appt = l->data;
+ char * right = NULL;
+
+ due = appt->is_event ? appt->begin : appt->end;
+
+ /* mark day if our query hasn't hit the next month. */
+ if (g_date_time_get_month (begin) == g_date_time_get_month (due))
+ g_variant_builder_add (&markeddays, "i", g_date_time_get_day_of_month (due));
+
+ if (i >= MAX_APPOINTMENT_MENUITEMS)
+ continue;
+
+ item = self->appointment_menuitems[i];
+ i++;
+
+ /* remove the icon as we might not replace it on error */
+ dbusmenu_menuitem_property_remove(item, APPOINTMENT_MENUITEM_PROP_ICON);
+
+ /* remove the activate handler */
+ g_signal_handlers_disconnect_matched(G_OBJECT(item), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, G_CALLBACK(activate_cb), NULL);
+
+ dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+ dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+ dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_LABEL, appt->summary);
+
+ gboolean full_day = FALSE;
+ if (appt->is_event)
+ full_day = g_date_time_difference (appt->end, appt->begin) == G_TIME_SPAN_DAY;
+
+ if (full_day)
+ {
+ /* TRANSLATORS: This is a strftime string for the day for full day events
+ in the menu. It should most likely be either '%A' for a full text day
+ (Wednesday) or '%a' for a shortened one (Wed). You should only need to
+ change for '%a' in the case of languages with very long day names. */
+ right = g_date_time_format (due, _("%A"));
+ }
+ else
+ {
+ int ay, am, ad;
+ int by, bm, bd;
+ gboolean same_day;
+ gboolean hr12;
+ const char * fmt;
+
+ g_date_time_get_ymd (due, &ay, &am, &ad);
+ g_date_time_get_ymd (begin, &by, &bm, &bd);
+ same_day = (ay==by) && (am==bm) && (ad==bd);
+ hr12 = apt_output == SETTINGS_TIME_12_HOUR;
+
+ if (same_day && hr12)
+ fmt = _(DEFAULT_TIME_12_FORMAT);
+ else if (same_day)
+ fmt = _(DEFAULT_TIME_24_FORMAT);
+ else if (hr12)
+ fmt = _(DEFAULT_TIME_12_FORMAT_WITH_DAY);
+ else
+ fmt = _(DEFAULT_TIME_24_FORMAT_WITH_DAY);
+
+ right = g_date_time_format (due, fmt);
+ }
+
+ dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, right);
+ g_free (right);
- // If the appointment time is less than the selected date,
- // don't create an appointment item for it.
- if (vtype == E_CAL_COMPONENT_EVENT) {
- if (ci->start < start_time_appointments) continue;
- } else if (vtype == E_CAL_COMPONENT_TODO) {
- if (ci->end < start_time_appointments) continue;
- }
-
- if (i >= MAX_APPOINTMENT_MENUITEMS)
- continue;
-
- item = appointments[i];
- i++;
-
- /* Remove the icon as we might not replace it on error */
- dbusmenu_menuitem_property_remove(item, APPOINTMENT_MENUITEM_PROP_ICON);
-
- /* Remove the activate handler */
- g_signal_handlers_disconnect_matched(G_OBJECT(item), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, G_CALLBACK(activate_cb), NULL);
-
- dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
- dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
-
-
- // Label text
- ECalComponentText valuetext;
- e_cal_component_get_summary (ecalcomp, &valuetext);
- const gchar * summary = valuetext.value;
- g_debug("Summary: %s", summary);
- dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_LABEL, summary);
-
- gboolean full_day = FALSE;
- if (vtype == E_CAL_COMPONENT_EVENT) {
- time_t start = ci->start;
- if (time_add_day(start, 1) == ci->end) {
- full_day = TRUE;
- }
- }
-
- // Due text
- if (full_day) {
- struct tm fulldaytime = {0};
- localtime_r(&ci->start, &fulldaytime);
+ // Now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution
+ // FIXME Because the URI stuff is really broken, we're going to open the calendar at todays date instead
+ //e_cal_component_get_uid(ecalcomp, &uri);
+/* FIXME: appointment menuitems aren't clickable */
+#if 0
+ gchar * ad = isodate_from_time_t(mktime(due));
+ gchar * cmd = g_strconcat("evolution calendar:///?startdate=", ad, NULL);
+ g_debug("Command to Execute: %s", cmd);
+ g_signal_connect_data (G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+ G_CALLBACK(activate_cb), cmd, (GClosureNotify)g_free, 0);
+ g_free (ad);
+#endif
- /* TRANSLATORS: This is a strftime string for the day for full day events
- in the menu. It should most likely be either '%A' for a full text day
- (Wednesday) or '%a' for a shortened one (Wed). You should only need to
- change for '%a' in the case of langauges with very long day names. */
- strftime(right, 20, _("%A"), &fulldaytime);
- } else {
- if (apt_output == SETTINGS_TIME_12_HOUR) {
- if ((mday == dmday) && (mon == dmon) && (year == dyear))
- strftime(right, 20, _(DEFAULT_TIME_12_FORMAT), due);
- else
- strftime(right, 20, _(DEFAULT_TIME_12_FORMAT_WITH_DAY), due);
- } else if (apt_output == SETTINGS_TIME_24_HOUR) {
- if ((mday == dmday) && (mon == dmon) && (year == dyear))
- strftime(right, 20, _(DEFAULT_TIME_24_FORMAT), due);
- else
- strftime(right, 20, _(DEFAULT_TIME_24_FORMAT_WITH_DAY), due);
- }
- }
- g_debug("Appointment time: %s, for date %s", right, asctime(due));
- dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, right);
-
- // Now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution
- // FIXME Because the URI stuff is really broken, we're going to open the calendar at todays date instead
- //e_cal_component_get_uid(ecalcomp, &uri);
- gchar * ad = isodate_from_time_t(mktime(due));
- gchar * cmd = g_strconcat("evolution calendar:///?startdate=", ad, NULL);
- g_debug("Command to Execute: %s", cmd);
- g_signal_connect_data (G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
- G_CALLBACK(activate_cb), cmd, (GClosureNotify)g_free, 0);
- g_free (ad);
-
- const gchar *color_spec = e_source_selectable_get_color (e_source_get_extension (ci->source, E_SOURCE_EXTENSION_CALENDAR));
- g_debug("Colour to use: %s", color_spec);
-
- // Draw the correct icon for the appointment type and then tint it using mask fill.
- // For now we'll create a circle
- if (color_spec != NULL) {
- g_debug("Creating a cairo surface: size, %d by %d", width, height);
- cairo_surface_t *surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height );
- cairo_t *cr = cairo_create(surface);
- GdkRGBA rgba;
- if (gdk_rgba_parse (&rgba, color_spec))
- gdk_cairo_set_source_rgba (cr, &rgba);
- cairo_paint(cr);
- cairo_set_source_rgba(cr, 0,0,0,0.5);
- cairo_set_line_width(cr, 1);
- cairo_rectangle (cr, 0.5, 0.5, width-1, height-1);
- cairo_stroke(cr);
- // Convert to pixbuf, in gtk3 this is done with gdk_pixbuf_get_from_surface
- cairo_content_t content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR;
- GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
- !!(content & CAIRO_CONTENT_ALPHA),
- 8, width, height);
- if (pixbuf != NULL) {
- gint sstride = cairo_image_surface_get_stride( surface );
- gint dstride = gdk_pixbuf_get_rowstride (pixbuf);
- guchar *spixels = cairo_image_surface_get_data( surface );
- guchar *dpixels = gdk_pixbuf_get_pixels (pixbuf);
-
- int x, y;
- for (y = 0; y < height; y++) {
- guint32 *src = (guint32 *) spixels;
-
- for (x = 0; x < width; x++) {
- guint alpha = src[x] >> 24;
-
- if (alpha == 0) {
- dpixels[x * 4 + 0] = 0;
- dpixels[x * 4 + 1] = 0;
- dpixels[x * 4 + 2] = 0;
- } else {
- dpixels[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
- dpixels[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
- dpixels[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
- }
- dpixels[x * 4 + 3] = alpha;
- }
- spixels += sstride;
- dpixels += dstride;
- }
-
- dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf);
- g_clear_object (&pixbuf);
- } else {
- g_debug("Creating pixbuf from surface failed");
- }
- cairo_surface_destroy (surface);
- cairo_destroy(cr);
- }
- g_debug("Adding appointment: %p", item);
- }
-
- g_clear_error (&gerror);
+ if ((pixbuf = create_color_icon_pixbuf (appt->color)))
+ {
+ dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf);
+ g_clear_object (&pixbuf);
+ }
+ }
- g_list_free_full (sorted_comp_instances, (GDestroyNotify)comp_instance_free);
- sorted_comp_instances = NULL;
- GVariant * marks = g_variant_builder_end (&markeddays);
- dbusmenu_menuitem_property_set_variant (calendar, CALENDAR_MENUITEM_PROP_MARKS, marks);
+ marks = g_variant_builder_end (&markeddays);
+ dbusmenu_menuitem_property_set_variant (self->calendar, CALENDAR_MENUITEM_PROP_MARKS, marks);
- g_clear_object (&sources);
+ g_slist_free_full (appointments, (GDestroyNotify)indicator_datetime_appt_free);
- updating_appointments = FALSE;
- g_debug("End of objects");
- return TRUE;
+ self->updating_appointments = FALSE;
+ g_date_time_unref (end);
+ g_date_time_unref (begin);
}
/* Looks for the time and date admin application and enables the
item we have one */
static gboolean
-check_for_timeadmin (gpointer user_data)
+check_for_timeadmin (gpointer gself)
{
- g_return_val_if_fail (settings != NULL, FALSE);
-
- gchar * timeadmin = g_find_program_in_path("gnome-control-center");
- if (timeadmin != NULL) {
- g_debug("Found the gnome-control-center application: %s", timeadmin);
- dbusmenu_menuitem_property_set_bool(settings, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
- g_free(timeadmin);
- } else {
- g_debug("Unable to find gnome-control-center app.");
- dbusmenu_menuitem_property_set_bool(settings, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
- }
+ gchar * timeadmin;
+ IndicatorDatetimeService * self = gself;
- return FALSE;
-}
+ g_return_val_if_fail (self->settings != NULL, FALSE);
-static void
-show_locations_changed (void)
-{
- /* Re-calculate */
- update_location_menu_items();
-}
+ timeadmin = g_find_program_in_path ("gnome-control-center");
+ if (timeadmin != NULL)
+ {
+ g_debug ("Found the gnome-control-center application: %s", timeadmin);
+ dbusmenu_menuitem_property_set_bool (self->settings, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+ g_free(timeadmin);
+ }
+ else
+ {
+ g_debug ("Unable to find gnome-control-center app.");
+ dbusmenu_menuitem_property_set_bool (self->settings, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
+ }
-static void
-time_format_changed (void)
-{
- update_appointment_menu_items(NULL);
+ return G_SOURCE_REMOVE;
}
/* Does the work to build the default menu, really calls out
to other functions but this is the core to clean up the
main function. */
static void
-build_menus (DbusmenuMenuitem * root)
+build_menus (IndicatorDatetimeService * self, DbusmenuMenuitem * root)
{
g_debug("Building Menus.");
- if (date == NULL) {
- date = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set (date, DBUSMENU_MENUITEM_PROP_LABEL, _("No date yet…"));
- dbusmenu_menuitem_property_set_bool(date, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
- dbusmenu_menuitem_child_append(root, date);
+ if (self->date == NULL) {
+ self->date = dbusmenu_menuitem_new();
+ dbusmenu_menuitem_property_set (self->date, DBUSMENU_MENUITEM_PROP_LABEL, _("No date yet…"));
+ dbusmenu_menuitem_property_set_bool(self->date, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
+ dbusmenu_menuitem_child_append(root, self->date);
- g_idle_add(update_datetime, NULL);
+ g_idle_add(update_datetime, self);
}
- if (calendar == NULL) {
- calendar = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set (calendar, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CALENDAR_MENUITEM_TYPE);
+ if (self->calendar == NULL) {
+ self->calendar = dbusmenu_menuitem_new();
+ dbusmenu_menuitem_property_set (self->calendar, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CALENDAR_MENUITEM_TYPE);
/* insensitive until we check for available apps */
- dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
- g_signal_connect (G_OBJECT(calendar), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+ dbusmenu_menuitem_property_set_bool(self->calendar, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
+ g_signal_connect (G_OBJECT(self->calendar), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
G_CALLBACK (activate_cb), "evolution -c calendar");
- dbusmenu_menuitem_child_append(root, calendar);
+ dbusmenu_menuitem_child_append(root, self->calendar);
- g_idle_add(check_for_calendar, NULL);
+ g_idle_add(check_for_calendar, self);
}
if (!get_greeter_mode ()) {
- locations_separator = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set(locations_separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
- dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- dbusmenu_menuitem_child_append(root, locations_separator);
+ self->locations_separator = dbusmenu_menuitem_new();
+ dbusmenu_menuitem_property_set(self->locations_separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
+ dbusmenu_menuitem_property_set_bool (self->locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+ dbusmenu_menuitem_child_append(root, self->locations_separator);
- update_location_menu_items();
+ update_location_menu_items (self);
- g_signal_connect (conf, "changed::" SETTINGS_SHOW_LOCATIONS_S, G_CALLBACK (show_locations_changed), NULL);
- g_signal_connect (conf, "changed::" SETTINGS_SHOW_DETECTED_S, G_CALLBACK (show_locations_changed), NULL);
- g_signal_connect (conf, "changed::" SETTINGS_LOCATIONS_S, G_CALLBACK (show_locations_changed), NULL);
- g_signal_connect (conf, "changed::" SETTINGS_SHOW_EVENTS_S, G_CALLBACK (show_events_changed), NULL);
- g_signal_connect (conf, "changed::" SETTINGS_TIME_FORMAT_S, G_CALLBACK (time_format_changed), NULL);
+ g_signal_connect (self->conf, "changed::" SETTINGS_SHOW_EVENTS_S, G_CALLBACK (show_events_changed), self);
+ g_signal_connect_swapped (self->conf, "changed::" SETTINGS_SHOW_LOCATIONS_S, G_CALLBACK (update_location_menu_items), self);
+ g_signal_connect_swapped (self->conf, "changed::" SETTINGS_SHOW_DETECTED_S, G_CALLBACK (update_location_menu_items), self);
+ g_signal_connect_swapped (self->conf, "changed::" SETTINGS_LOCATIONS_S, G_CALLBACK (update_location_menu_items), self);
+ g_signal_connect_swapped (self->conf, "changed::" SETTINGS_TIME_FORMAT_S, G_CALLBACK (update_appointment_menu_items), self);
DbusmenuMenuitem * separator = dbusmenu_menuitem_new();
dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
dbusmenu_menuitem_child_append(root, separator);
- settings = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set (settings, DBUSMENU_MENUITEM_PROP_LABEL, _("Time & Date Settings…"));
+ self->settings = dbusmenu_menuitem_new();
+ dbusmenu_menuitem_property_set (self->settings, DBUSMENU_MENUITEM_PROP_LABEL, _("Time & Date Settings…"));
/* insensitive until we check for available apps */
- dbusmenu_menuitem_property_set_bool(settings, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
- g_signal_connect(G_OBJECT(settings), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), SETTINGS_APP_INVOCATION);
- dbusmenu_menuitem_child_append(root, settings);
- g_idle_add(check_for_timeadmin, NULL);
+ dbusmenu_menuitem_property_set_bool(self->settings, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
+ g_signal_connect(G_OBJECT(self->settings), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), SETTINGS_APP_INVOCATION);
+ dbusmenu_menuitem_child_append(root, self->settings);
+ g_idle_add(check_for_timeadmin, self);
+ update_appointment_menu_items_soon (self);
}
return;
}
static void
-on_clock_skew (void)
+on_clock_skew (gpointer self)
{
- /* tell the indicators to refresh */
- if (IS_DATETIME_INTERFACE (dbus))
- datetime_interface_update (DATETIME_INTERFACE(dbus));
-
- /* update our day label */
- update_datetime (NULL);
- day_timer_reset();
+ /* tell the indicators to refresh */
+ if (IS_DATETIME_INTERFACE (dbus))
+ datetime_interface_update (DATETIME_INTERFACE(dbus));
- return;
+ /* update our day label */
+ update_datetime (self);
+ day_timer_reset (self);
}
-/* Run when the timezone file changes */
static void
-timezone_changed (GFileMonitor * monitor, GFile * file, GFile * otherfile, GFileMonitorEvent event, gpointer user_data)
+on_timezone_changed (gpointer self)
{
- update_current_timezone();
- on_clock_skew();
- return;
-}
+ update_location_menu_items (self);
-/* Set up monitoring the timezone file */
-static void
-build_timezone (DatetimeInterface * dbus)
-{
- GFile * timezonefile = g_file_new_for_path(TIMEZONE_FILE);
- GFileMonitor * monitor = g_file_monitor_file(timezonefile, G_FILE_MONITOR_NONE, NULL, NULL);
- if (monitor != NULL) {
- g_signal_connect(G_OBJECT(monitor), "changed", G_CALLBACK(timezone_changed), dbus);
- g_debug("Monitoring timezone file: '" TIMEZONE_FILE "'");
- } else {
- g_warning("Unable to monitor timezone file: '" TIMEZONE_FILE "'");
- }
- g_object_unref(timezonefile);
- return;
+ on_clock_skew (self);
}
-/* Source ID for the timer */
-static guint day_timer = 0;
-
/* Execute at a given time, update and setup a new
timer to go again. */
static gboolean
-day_timer_func (gpointer user_data)
+day_timer_func (gpointer self)
{
- day_timer = 0;
- /* Reset up each time to reduce error */
- day_timer_reset();
- update_datetime(NULL);
- return G_SOURCE_REMOVE;
+ day_timer_reset (self);
+ update_datetime (self);
+
+ return G_SOURCE_REMOVE;
}
/* Sets up the time to launch the timer to update the
date in the datetime entry */
static void
-day_timer_reset (void)
+day_timer_reset (IndicatorDatetimeService * self)
{
- if (day_timer != 0) {
- g_source_remove(day_timer);
- day_timer = 0;
- }
-
- time_t t;
- t = time(NULL);
- struct tm * ltime = localtime(&t);
+ GDateTime * now;
+ GDateTime * tomorrow;
+ GDateTime * new_day;
+ guint seconds_until_tomorrow;
- day_timer = g_timeout_add_seconds(((23 - ltime->tm_hour) * 60 * 60) +
- ((59 - ltime->tm_min) * 60) +
- ((60 - ltime->tm_sec)) + 60 /* one minute past */,
- day_timer_func, NULL);
+ if (self->day_timer != 0)
+ {
+ g_source_remove (self->day_timer);
+ self->day_timer = 0;
+ }
- return;
+ now = g_date_time_new_now_local ();
+ tomorrow = g_date_time_add_days (now, 1);
+ new_day = g_date_time_new_local (g_date_time_get_year (tomorrow),
+ g_date_time_get_month (tomorrow),
+ g_date_time_get_day_of_month (tomorrow),
+ 0, 0, 0);
+ seconds_until_tomorrow = (guint)(g_date_time_difference (new_day, now) / G_TIME_SPAN_SECOND);
+g_message ("seconds until tomorrow is %u", seconds_until_tomorrow);
+
+ self->day_timer = g_timeout_add_seconds (seconds_until_tomorrow + 15,
+ day_timer_func,
+ self);
+
+ g_date_time_unref (new_day);
+ g_date_time_unref (tomorrow);
+ g_date_time_unref (now);
}
static gboolean
-skew_check_timer_func (gpointer unused G_GNUC_UNUSED)
+skew_check_timer_func (gpointer self)
{
- static time_t prev_time = 0;
- const time_t cur_time = time (NULL);
- const double diff_sec = fabs (difftime (cur_time, prev_time));
+ static time_t prev_time = 0;
+ const time_t cur_time = time (NULL); /* FIXME: unmockable */
+ const double diff_sec = fabs (difftime (cur_time, prev_time));
- if (prev_time && (diff_sec > SKEW_DIFF_THRESHOLD_SEC)) {
- g_debug (G_STRLOC" clock skew detected (%.0f seconds)", diff_sec);
- on_clock_skew ();
- }
+ if (prev_time && (diff_sec > SKEW_DIFF_THRESHOLD_SEC))
+ {
+ g_debug (G_STRLOC" clock skew detected (%.0f seconds)", diff_sec);
+ on_clock_skew (self);
+ }
- prev_time = cur_time;
- return G_SOURCE_CONTINUE;
+ prev_time = cur_time;
+ return G_SOURCE_CONTINUE;
}
static void
-session_active_change_cb (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name,
- GVariant * parameters, gpointer user_data)
+session_active_change_cb (GDBusProxy * proxy G_GNUC_UNUSED,
+ gchar * sender_name G_GNUC_UNUSED,
+ gchar * signal_name,
+ GVariant * parameters,
+ gpointer gself)
{
- // Just returned from suspend
- if (g_strcmp0(signal_name, "SystemIdleHintChanged") == 0) {
- gboolean idle = FALSE;
- g_variant_get(parameters, "(b)", &idle);
- if (!idle) {
- on_clock_skew ();
- }
- }
- return;
+ IndicatorDatetimeService * self = gself;
+
+ /* suspending / returning from suspend (true / false) */
+ if (g_strcmp0(signal_name, "PrepareForSleep") == 0)
+ {
+ gboolean sleeping = FALSE;
+ g_variant_get (parameters, "(b)", &sleeping);
+ if (!sleeping)
+ {
+ g_debug ("System has been resumed; adjusting clock");
+ on_clock_skew (self);
+ }
+ }
}
/* for hooking into console kit signal on wake from suspend */
static void
-system_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data)
+system_proxy_cb (GObject * object G_GNUC_UNUSED,
+ GAsyncResult * res,
+ gpointer gself)
{
GError * error = NULL;
GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error);
if (error != NULL) {
- g_warning("Could not grab DBus proxy for ConsoleKit: %s", error->message);
+ g_warning("Could not grab DBus proxy for logind: %s", error->message);
g_clear_error (&error);
return;
}
- g_signal_connect(proxy, "g-signal", G_CALLBACK(session_active_change_cb), user_data);
+ g_signal_connect(proxy, "g-signal", G_CALLBACK(session_active_change_cb), gself);
}
/****
@@ -1197,77 +1016,33 @@ get_greeter_mode (void)
/* Repsonds to the service object saying it's time to shutdown.
It stops the mainloop. */
-static void
-service_shutdown (IndicatorService * service, gpointer user_data)
-{
- g_warning("Shutting down service!");
- g_main_loop_quit(mainloop);
- return;
-}
-
-static void
-free_appointment_sources (void)
-{
- g_list_free_full (appointment_sources, g_object_unref);
- appointment_sources = NULL;
-}
-
static void
-source_changed_cb (ESource *source __attribute__ ((unused)),
- gpointer user_data)
+service_shutdown (IndicatorService * service G_GNUC_UNUSED,
+ gpointer gmainloop)
{
- update_appointment_menu_items (user_data);
+ g_warning ("Shutting down service!");
+ g_main_loop_quit (gmainloop);
}
static void
-init_appointment_sources (ESourceRegistry *registry)
+on_use_geoclue_changed_cb (GSettings * settings,
+ gchar * key G_GNUC_UNUSED,
+ gpointer gself)
{
- GList * l;
+ IndicatorDatetimeService * self = gself;
+ const gboolean use_geoclue = g_settings_get_boolean (settings, "show-auto-detected-location");
- appointment_sources = e_source_registry_list_sources (registry, E_SOURCE_EXTENSION_CALENDAR);
-
- for (l=appointment_sources; l!=NULL; l=l->next)
- g_signal_connect (G_OBJECT(l->data), "changed", G_CALLBACK (source_changed_cb), NULL);
-}
-
-/* rebuilds both the appointment sources and menu */
-static void
-update_appointments (ESourceRegistry *registry,
- ESource *source __attribute__ ((unused)),
- gpointer user_data __attribute__ ((unused)))
-{
- free_appointment_sources ();
- init_appointment_sources (registry);
-
- update_appointment_menu_items (NULL);
-}
-
-static void
-source_registry_changed_cb (ESourceRegistry *registry __attribute__ ((unused)),
- ESource *source __attribute__ ((unused)),
- gpointer user_data)
-{
- update_appointment_menu_items (user_data);
-}
-
-static void
-on_use_geoclue_changed_cb (GSettings *settings,
- gchar *key G_GNUC_UNUSED,
- gpointer user_data G_GNUC_UNUSED)
-{
- const gboolean use_geoclue = g_settings_get_boolean (conf, "show-auto-detected-location");
-
- if (geo_location && !use_geoclue)
+ if (self->geo_location && !use_geoclue)
{
- g_signal_handlers_disconnect_by_func (geo_location, update_location_menu_items, 0);
- g_clear_object (&geo_location);
- update_location_menu_items ();
+ g_signal_handlers_disconnect_by_func (self->geo_location, update_location_menu_items, self);
+ g_clear_object (&self->geo_location);
+ update_location_menu_items (self);
}
- else if (use_geoclue && !geo_location)
+ else if (use_geoclue && !self->geo_location)
{
- geo_location = indicator_datetime_location_geoclue_new ();
- g_signal_connect (geo_location, "notify::timezone",
- G_CALLBACK(update_location_menu_items), NULL);
+ self->geo_location = indicator_datetime_timezone_geoclue_new ();
+ g_signal_connect_swapped (self->geo_location, "notify::timezone",
+ G_CALLBACK(update_location_menu_items), self);
}
}
@@ -1275,88 +1050,89 @@ on_use_geoclue_changed_cb (GSettings *settings,
int
main (int argc, char ** argv)
{
- gtk_init (&argc, &argv);
-
- /* Acknowledging the service init and setting up the interface */
- service = indicator_service_new_version(SERVICE_NAME, SERVICE_VERSION);
- g_signal_connect(service, INDICATOR_SERVICE_SIGNAL_SHUTDOWN, G_CALLBACK(service_shutdown), NULL);
-
- /* Setting up i18n and gettext. Apparently, we need
- all of these. */
- setlocale (LC_ALL, "");
- bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
- textdomain (GETTEXT_PACKAGE);
-
- /* Set up GSettings */
- conf = g_settings_new(SETTINGS_INTERFACE);
- g_signal_connect (conf, "changed::show-auto-detected-location",
- G_CALLBACK(on_use_geoclue_changed_cb), NULL);
- // TODO Add a signal handler to catch other gsettings changes and respond to them
-
- /* Build our list of appointment calendar sources.
- When a source changes, update our menu items.
- When sources are added or removed, update our list and menu items. */
- source_registry = e_source_registry_new_sync (NULL, NULL);
- g_object_connect (source_registry,
- "signal::source-added", G_CALLBACK (update_appointments), NULL,
- "signal::source-removed", G_CALLBACK (update_appointments), NULL,
- "signal::source-changed", G_CALLBACK (source_registry_changed_cb), NULL,
- "signal::source-disabled", G_CALLBACK (source_registry_changed_cb), NULL,
- "signal::source-enabled", G_CALLBACK (source_registry_changed_cb), NULL,
- NULL);
- init_appointment_sources (source_registry);
-
- /* Building the base menu */
- server = dbusmenu_server_new(MENU_OBJ);
- root = dbusmenu_menuitem_new();
- dbusmenu_server_set_root(server, root);
+ GMainLoop * mainloop;
+ IndicatorService * service;
+ DbusmenuServer * server;
+ struct IndicatorDatetimeService self;
+
+ memset (&self, 0, sizeof(struct IndicatorDatetimeService));
+
+ gtk_init (&argc, &argv);
+ mainloop = g_main_loop_new (NULL, FALSE);
+
+ /* acknowledging the service init and setting up the interface */
+ service = indicator_service_new_version(SERVICE_NAME, SERVICE_VERSION);
+ g_signal_connect (service, INDICATOR_SERVICE_SIGNAL_SHUTDOWN,
+ G_CALLBACK(service_shutdown), mainloop);
+
+ /* setting up i18n and gettext. apparently we need all of these. */
+ setlocale (LC_ALL, "");
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ textdomain (GETTEXT_PACKAGE);
+
+ /* set up GSettings */
+ self.conf = g_settings_new (SETTINGS_INTERFACE);
+ g_signal_connect (self.conf, "changed::show-auto-detected-location",
+ G_CALLBACK(on_use_geoclue_changed_cb), &self);
+
+ /* setup geoclue */
+ on_use_geoclue_changed_cb (self.conf, NULL, &self);
+
+ /* setup timezone watch */
+ self.tz_file = indicator_datetime_timezone_file_new (TIMEZONE_FILE);
+ g_signal_connect_swapped (self.tz_file, "notify::timezone",
+ G_CALLBACK(on_timezone_changed), &self);
+
+ /* build our list of appointment calendar sources.
+ When a source changes, update our menu items.
+ When sources are added or removed, update our list and menu items. */
+ self.planner = indicator_datetime_planner_eds_new ();
+ g_signal_connect_swapped (self.planner, "appointments-changed",
+ G_CALLBACK(update_appointment_menu_items_soon), &self);
+
+ /* building the base menu */
+ server = dbusmenu_server_new (MENU_OBJ);
+ root = dbusmenu_menuitem_new ();
+ dbusmenu_server_set_root (server, root);
- build_menus(root);
+ build_menus (&self, root);
- /* Cache the timezone */
- update_current_timezone();
-
- /* Setup geoclue */
- on_use_geoclue_changed_cb (conf, NULL, NULL);
-
- /* Setup dbus interface */
- dbus = g_object_new(DATETIME_INTERFACE_TYPE, NULL);
-
- /* Setup timezone watch */
- build_timezone(dbus);
-
- /* Set up the day timer */
- day_timer_reset();
-
- /* Set up the skew-check timer */
- g_timeout_add_seconds (SKEW_CHECK_INTERVAL_SEC,
- skew_check_timer_func,
- NULL);
-
- /* And watch for system resumes */
- g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
- G_DBUS_PROXY_FLAGS_NONE,
- NULL,
- "org.freedesktop.ConsoleKit",
- "/org/freedesktop/ConsoleKit/Manager",
- "org.freedesktop.ConsoleKit.Manager",
- NULL, system_proxy_cb, dbus);
-
- mainloop = g_main_loop_new(NULL, FALSE);
- g_main_loop_run(mainloop);
-
- free_appointment_sources();
-
- g_object_unref(G_OBJECT(conf));
- g_object_unref(G_OBJECT(dbus));
- g_object_unref(G_OBJECT(service));
- g_object_unref(G_OBJECT(server));
- g_object_unref(G_OBJECT(root));
- g_object_unref(G_OBJECT(source_registry));
-
- icaltimezone_free_builtin_timezones();
-
- g_clear_object (&geo_location);
-
- return 0;
+ /* cache the timezone */
+ update_location_menu_items (&self);
+
+ /* setup dbus interface */
+ dbus = g_object_new (DATETIME_INTERFACE_TYPE, NULL);
+
+ /* set up the day timer */
+ day_timer_reset (&self);
+
+ /* set up the skew-check timer */
+ g_timeout_add_seconds (SKEW_CHECK_INTERVAL_SEC,
+ skew_check_timer_func,
+ &self);
+
+ /* and watch for system resumes */
+ 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",
+ NULL, /* FIXME: cancellable */
+ system_proxy_cb,
+ &self);
+
+ g_main_loop_run (mainloop);
+ g_main_loop_unref (mainloop);
+
+ g_object_unref (self.conf);
+ g_object_unref (dbus);
+ g_object_unref (service);
+ g_object_unref (server);
+ g_object_unref (root);
+ g_object_unref (self.planner);
+ g_object_unref (self.geo_location);
+ g_object_unref (self.tz_file);
+
+ return 0;
}
diff --git a/src/location-geoclue.h b/src/location-geoclue.h
deleted file mode 100644
index 7b65917..0000000
--- a/src/location-geoclue.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2013 Canonical Ltd.
- *
- * Authors:
- * Charles Kerr <charles.kerr@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/>.
- */
-
-#ifndef __INDICATOR_DATETIME_LOCATION_GEOCLUE__H__
-#define __INDICATOR_DATETIME_LOCATION_GEOCLUE__H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "location.h" /* parent class */
-
-G_BEGIN_DECLS
-
-#define INDICATOR_TYPE_DATETIME_LOCATION_GEOCLUE (indicator_datetime_location_geoclue_get_type())
-#define INDICATOR_DATETIME_LOCATION_GEOCLUE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_LOCATION_GEOCLUE, IndicatorDatetimeLocationGeoclue))
-#define INDICATOR_DATETIME_LOCATION_GEOCLUE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_LOCATION_GEOCLUE, IndicatorDatetimeLocationGeoclueClass))
-#define INDICATOR_IS_DATETIME_LOCATION_GEOCLUE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_LOCATION_GEOCLUE))
-
-typedef struct _IndicatorDatetimeLocationGeoclue IndicatorDatetimeLocationGeoclue;
-typedef struct _IndicatorDatetimeLocationGeocluePriv IndicatorDatetimeLocationGeocluePriv;
-typedef struct _IndicatorDatetimeLocationGeoclueClass IndicatorDatetimeLocationGeoclueClass;
-
-GType indicator_datetime_location_geoclue_get_type (void);
-
-/**
- * An implementation of IndicatorDatetimeLocation that gets its user information
- * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus.
- */
-struct _IndicatorDatetimeLocationGeoclue
-{
- /*< private >*/
- IndicatorDatetimeLocation parent;
- IndicatorDatetimeLocationGeocluePriv * priv;
-};
-
-struct _IndicatorDatetimeLocationGeoclueClass
-{
- IndicatorDatetimeLocationClass parent_class;
-};
-
-IndicatorDatetimeLocation * indicator_datetime_location_geoclue_new (void);
-
-G_END_DECLS
-
-#endif /* __INDICATOR_DATETIME_LOCATION_GEOCLUE__H__ */
diff --git a/src/location.h b/src/location.h
deleted file mode 100644
index f9fd2ce..0000000
--- a/src/location.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2013 Canonical Ltd.
- *
- * Authors:
- * Charles Kerr <charles.kerr@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/>.
- */
-
-#ifndef __INDICATOR_DATETIME_LOCATION__H__
-#define __INDICATOR_DATETIME_LOCATION__H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define INDICATOR_TYPE_DATETIME_LOCATION (indicator_datetime_location_get_type())
-#define INDICATOR_DATETIME_LOCATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_LOCATION, IndicatorDatetimeLocation))
-#define INDICATOR_DATETIME_LOCATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_LOCATION, IndicatorDatetimeLocationClass))
-#define INDICATOR_DATETIME_LOCATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_DATETIME_LOCATION, IndicatorDatetimeLocationClass))
-#define INDICATOR_IS_DATETIME_LOCATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_LOCATION))
-
-typedef struct _IndicatorDatetimeLocation IndicatorDatetimeLocation;
-typedef struct _IndicatorDatetimeLocationClass IndicatorDatetimeLocationClass;
-
-GType indicator_datetime_location_get_type (void);
-
-/**
- * Abstract Base Class for the mechanisms that determine timezone by location
- */
-struct _IndicatorDatetimeLocation
-{
- /*< private >*/
- GObject parent;
-};
-
-struct _IndicatorDatetimeLocationClass
-{
- GObjectClass parent_class;
-
- /* virtual functions */
- const char * (*get_timezone) (IndicatorDatetimeLocation * self);
-};
-
-/***
-****
-***/
-
-#define INDICATOR_DATETIME_LOCATION_PROPERTY_TIMEZONE "timezone"
-
-const char * indicator_datetime_location_get_timezone (IndicatorDatetimeLocation *);
-
-void indicator_datetime_location_notify_timezone (IndicatorDatetimeLocation *);
-
-G_END_DECLS
-
-#endif /* __INDICATOR_DATETIME_LOCATION__H__ */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..162bb16
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@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 "config.h"
+
+#include <locale.h>
+#include <stdlib.h> /* exit() */
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "service.h"
+
+/***
+****
+***/
+
+static gboolean replace = FALSE;
+
+static void
+parse_command_line (int * argc, char *** argv)
+{
+ GError * error;
+ GOptionContext * option_context;
+
+ static GOptionEntry entries[] =
+ {
+ { "replace", 'r', 0, G_OPTION_ARG_NONE, &replace, "Replace the currently-running service", NULL },
+ { NULL }
+ };
+
+ error = NULL;
+ option_context = g_option_context_new ("- indicator-datetime service");
+ g_option_context_add_main_entries (option_context, entries, GETTEXT_PACKAGE);
+ if (!g_option_context_parse (option_context, argc, argv, &error))
+ {
+ g_print ("option parsing failed: %s\n", error->message);
+ g_error_free (error);
+ exit (EXIT_FAILURE);
+ }
+
+ g_option_context_free (option_context);
+}
+
+/***
+****
+***/
+
+static void
+on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop)
+{
+ g_debug ("exiting: service couldn't acquire or lost ownership of busname");
+ g_main_loop_quit ((GMainLoop*)loop);
+}
+
+int
+main (int argc, char ** argv)
+{
+ GMainLoop * loop;
+ IndicatorDatetimeService * service;
+
+ /* boilerplate i18n */
+ setlocale (LC_ALL, "");
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ textdomain (GETTEXT_PACKAGE);
+
+ parse_command_line (&argc, &argv);
+
+ /* run */
+ service = indicator_datetime_service_new (replace);
+ 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);
+ return 0;
+}
diff --git a/src/planner-eds.c b/src/planner-eds.c
new file mode 100644
index 0000000..6677b32
--- /dev/null
+++ b/src/planner-eds.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@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 "config.h"
+
+#include <gio/gio.h> /* GFile, GFileMonitor */
+
+#include <libical/ical.h>
+#include <libical/icaltime.h>
+#include <libecal/libecal.h>
+#include <libedataserver/libedataserver.h>
+
+#include "planner-eds.h"
+
+struct _IndicatorDatetimePlannerEdsPriv
+{
+ ESourceRegistry * source_registry;
+};
+
+typedef IndicatorDatetimePlannerEdsPriv priv_t;
+
+G_DEFINE_TYPE (IndicatorDatetimePlannerEds,
+ indicator_datetime_planner_eds,
+ INDICATOR_TYPE_DATETIME_PLANNER)
+
+/***
+****
+***/
+
+void
+indicator_datetime_appt_free (struct IndicatorDatetimeAppt * appt)
+{
+ if (appt != NULL)
+ {
+ g_date_time_unref (appt->end);
+ g_date_time_unref (appt->begin);
+ g_free (appt->color);
+ g_free (appt->summary);
+ g_free (appt);
+ }
+}
+
+/***
+**** my_get_appointments() helpers
+***/
+
+struct my_get_appointments_data
+{
+ ESource * source;
+ GSList * appointments;
+};
+
+static gboolean
+my_get_appointments_foreach (ECalComponent * component,
+ time_t begin,
+ time_t end,
+ gpointer gdata)
+{
+ const ECalComponentVType vtype = e_cal_component_get_vtype (component);
+ struct my_get_appointments_data * data = gdata;
+
+ if ((vtype == E_CAL_COMPONENT_EVENT) || (vtype == E_CAL_COMPONENT_TODO))
+ {
+ icalproperty_status status;
+ e_cal_component_get_status (component, &status);
+ if ((status != ICAL_STATUS_COMPLETED) && (status != ICAL_STATUS_CANCELLED))
+ {
+ ECalComponentText text;
+ struct IndicatorDatetimeAppt * appt = g_new0 (struct IndicatorDatetimeAppt, 1);
+
+ text.value = "";
+ e_cal_component_get_summary (component, &text);
+
+ appt->begin = g_date_time_new_from_unix_local (begin);
+ appt->end = g_date_time_new_from_unix_local (end);
+ appt->color = e_source_selectable_dup_color (e_source_get_extension (data->source, E_SOURCE_EXTENSION_CALENDAR));
+ appt->is_event = vtype == E_CAL_COMPONENT_EVENT;
+ appt->summary = g_strdup (text.value);
+
+ data->appointments = g_slist_prepend (data->appointments, appt);
+ }
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+
+/***
+**** IndicatorDatetimePlanner virtual funcs
+***/
+
+static GSList *
+my_get_appointments (IndicatorDatetimePlanner * planner,
+ GDateTime * begin_datetime,
+ GDateTime * end_datetime)
+{
+ GList * l;
+ GList * sources;
+ priv_t * p;
+ const char * str;
+ icaltimezone * default_timezone;
+ struct my_get_appointments_data data;
+ const int64_t begin = g_date_time_to_unix (begin_datetime);
+ const int64_t end = g_date_time_to_unix (end_datetime);
+
+ p = INDICATOR_DATETIME_PLANNER_EDS (planner)->priv;
+
+ /**
+ *** init the default timezone
+ **/
+
+ default_timezone = NULL;
+
+ if ((str = indicator_datetime_planner_get_timezone (planner)))
+ {
+ default_timezone = icaltimezone_get_builtin_timezone (str);
+
+ if (default_timezone == NULL) /* maybe str is a tzid? */
+ default_timezone = icaltimezone_get_builtin_timezone_from_tzid (str);
+ }
+
+ /**
+ *** walk through the sources to build the appointment list
+ **/
+
+ data.source = NULL;
+ data.appointments = NULL;
+
+ sources = e_source_registry_list_sources (p->source_registry, E_SOURCE_EXTENSION_CALENDAR);
+ for (l=sources; l!=NULL; l=l->next)
+ {
+ GError * err;
+ ESource * source;
+ ECalClient * ecc;
+
+ source = E_SOURCE (l->data);
+ if (e_source_get_enabled (source))
+ {
+ err = NULL;
+ ecc = e_cal_client_new (source, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, &err);
+ if (err != NULL)
+ {
+ g_warning ("Can't create ecal client: %s", err->message);
+ g_error_free (err);
+ }
+ else
+ {
+ if (!e_client_open_sync (E_CLIENT (ecc), TRUE, NULL, &err))
+ {
+ g_debug ("Failed to open ecal client: %s", err->message);
+ g_error_free (err);
+ }
+ else
+ {
+ if (default_timezone != NULL)
+ e_cal_client_set_default_timezone (ecc, default_timezone);
+
+ data.source = source;
+ e_cal_client_generate_instances_sync (ecc, begin, end, my_get_appointments_foreach, &data);
+ }
+
+ g_object_unref (ecc);
+ }
+ }
+ }
+
+ g_list_free_full (sources, g_object_unref);
+
+ g_debug ("%s EDS get_appointments returning %d appointments", G_STRLOC, g_slist_length (data.appointments));
+ return data.appointments;
+}
+
+gboolean
+my_is_configured (IndicatorDatetimePlanner * planner)
+{
+ GList * sources;
+ gboolean have_sources;
+ IndicatorDatetimePlannerEds * self;
+
+ /* confirm that it's installed... */
+ gchar *evo = g_find_program_in_path ("evolution");
+ if (evo == NULL)
+ return FALSE;
+
+ g_debug ("found calendar app: '%s'", evo);
+ g_free (evo);
+
+ /* see if there are any calendar sources */
+ self = INDICATOR_DATETIME_PLANNER_EDS (planner);
+ sources = e_source_registry_list_sources (self->priv->source_registry, E_SOURCE_EXTENSION_CALENDAR);
+ have_sources = sources != NULL;
+ g_list_free_full (sources, g_object_unref);
+ return have_sources;
+}
+
+static void
+my_activate (IndicatorDatetimePlanner * self G_GNUC_UNUSED)
+{
+ GError * error = NULL;
+ const char * const command = "evolution -c calendar";
+
+ if (!g_spawn_command_line_async (command, &error))
+ {
+ g_warning ("Unable to start %s: %s", command, error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+my_activate_time (IndicatorDatetimePlanner * self G_GNUC_UNUSED,
+ GDateTime * activate_time)
+{
+ gchar * isodate;
+ gchar * command;
+ GError * error;
+
+ isodate = g_date_time_format (activate_time, "%F");
+ command = g_strconcat ("evolution calendar:///?startdate=", isodate, NULL);
+ error = 0;
+ if (!g_spawn_command_line_async (command, &error))
+ {
+ g_warning ("Unable to start %s: %s", command, error->message);
+ g_error_free (error);
+ }
+
+ g_free (command);
+ g_free (isodate);
+}
+
+/***
+**** GObject virtual funcs
+***/
+
+static void
+my_dispose (GObject * o)
+{
+ IndicatorDatetimePlannerEds * self = INDICATOR_DATETIME_PLANNER_EDS (o);
+ priv_t * p = self->priv;
+
+ if (p->source_registry != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (p->source_registry,
+ indicator_datetime_planner_emit_appointments_changed,
+ self);
+
+ g_clear_object (&self->priv->source_registry);
+ }
+
+ G_OBJECT_CLASS (indicator_datetime_planner_eds_parent_class)->dispose (o);
+}
+
+/***
+**** Insantiation
+***/
+
+static void
+indicator_datetime_planner_eds_class_init (IndicatorDatetimePlannerEdsClass * 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;
+
+ g_type_class_add_private (klass, sizeof (IndicatorDatetimePlannerEdsPriv));
+}
+
+static void
+indicator_datetime_planner_eds_init (IndicatorDatetimePlannerEds * self)
+{
+ priv_t * p;
+ GError * err;
+
+ p = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ INDICATOR_TYPE_DATETIME_PLANNER_EDS,
+ IndicatorDatetimePlannerEdsPriv);
+
+ self->priv = p;
+
+ err = 0;
+ p->source_registry = e_source_registry_new_sync (NULL, &err);
+ if (err != NULL)
+ {
+ g_warning ("indicator-datetime cannot show EDS appointments: %s", err->message);
+ g_error_free (err);
+ }
+ else
+ {
+ gpointer o = p->source_registry;
+ g_signal_connect_swapped (o, "source-added", G_CALLBACK(indicator_datetime_planner_emit_appointments_changed), self);
+ g_signal_connect_swapped (o, "source-removed", G_CALLBACK(indicator_datetime_planner_emit_appointments_changed), self);
+ g_signal_connect_swapped (o, "source-changed", G_CALLBACK(indicator_datetime_planner_emit_appointments_changed), self);
+ g_signal_connect_swapped (o, "source-disabled", G_CALLBACK(indicator_datetime_planner_emit_appointments_changed), self);
+ g_signal_connect_swapped (o, "source-enabled", G_CALLBACK(indicator_datetime_planner_emit_appointments_changed), self);
+ }
+}
+
+/***
+**** Public
+***/
+
+IndicatorDatetimePlanner *
+indicator_datetime_planner_eds_new (void)
+{
+ gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_PLANNER_EDS, NULL);
+
+ return INDICATOR_DATETIME_PLANNER (o);
+}
diff --git a/src/planner-eds.h b/src/planner-eds.h
new file mode 100644
index 0000000..a2c803a
--- /dev/null
+++ b/src/planner-eds.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@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/>.
+ */
+
+#ifndef __INDICATOR_DATETIME_PLANNER_EDS__H__
+#define __INDICATOR_DATETIME_PLANNER_EDS__H__
+
+#include "planner.h" /* parent class */
+
+G_BEGIN_DECLS
+
+#define INDICATOR_TYPE_DATETIME_PLANNER_EDS (indicator_datetime_planner_eds_get_type())
+#define INDICATOR_DATETIME_PLANNER_EDS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_PLANNER_EDS, IndicatorDatetimePlannerEds))
+#define INDICATOR_DATETIME_PLANNER_EDS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_PLANNER_EDS, IndicatorDatetimePlannerEdsClass))
+#define INDICATOR_IS_DATETIME_PLANNER_EDS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_PLANNER_EDS))
+
+typedef struct _IndicatorDatetimePlannerEds IndicatorDatetimePlannerEds;
+typedef struct _IndicatorDatetimePlannerEdsPriv IndicatorDatetimePlannerEdsPriv;
+typedef struct _IndicatorDatetimePlannerEdsClass IndicatorDatetimePlannerEdsClass;
+
+GType indicator_datetime_planner_eds_get_type (void);
+
+/**
+ * An IndicatorDatetimePlanner which uses Evolution Data Server
+ * to get its list of appointments.
+ */
+struct _IndicatorDatetimePlannerEds
+{
+ /*< private >*/
+ IndicatorDatetimePlanner parent;
+ IndicatorDatetimePlannerEdsPriv * priv;
+};
+
+struct _IndicatorDatetimePlannerEdsClass
+{
+ IndicatorDatetimePlannerClass parent_class;
+};
+
+gboolean indicator_datetime_planner_eds_is_usable (void);
+
+IndicatorDatetimePlanner * indicator_datetime_planner_eds_new (void);
+
+G_END_DECLS
+
+#endif /* __INDICATOR_DATETIME_PLANNER_EDS__H__ */
diff --git a/src/planner.c b/src/planner.c
new file mode 100644
index 0000000..f16a05a
--- /dev/null
+++ b/src/planner.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@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 "planner.h"
+
+/**
+*** Signals Boilerplate
+**/
+
+enum
+{
+ SIGNAL_APPTS_CHANGED,
+ SIGNAL_LAST
+};
+
+static guint signals[SIGNAL_LAST] = { 0 };
+
+/**
+*** Properties Boilerplate
+**/
+
+enum
+{
+ PROP_0,
+ PROP_TIMEZONE,
+ PROP_LAST
+};
+
+static GParamSpec * properties[PROP_LAST] = { 0 };
+
+/**
+*** GObject Boilerplate
+**/
+
+G_DEFINE_TYPE (IndicatorDatetimePlanner,
+ indicator_datetime_planner,
+ G_TYPE_OBJECT)
+
+struct _IndicatorDatetimePlannerPriv
+{
+ char * timezone;
+};
+
+/***
+**** GObjectClass virtual funcs
+***/
+
+static void
+my_get_property (GObject * o,
+ guint property_id,
+ GValue * value,
+ GParamSpec * pspec)
+{
+ IndicatorDatetimePlanner * self = INDICATOR_DATETIME_PLANNER (o);
+
+ switch (property_id)
+ {
+ case PROP_TIMEZONE:
+ g_value_set_string (value, self->priv->timezone);
+ 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)
+{
+ IndicatorDatetimePlanner * self = INDICATOR_DATETIME_PLANNER (o);
+
+ switch (property_id)
+ {
+ case PROP_TIMEZONE:
+ indicator_datetime_planner_set_timezone (self, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
+ }
+}
+
+static void
+my_finalize (GObject * o)
+{
+ IndicatorDatetimePlanner * self = INDICATOR_DATETIME_PLANNER(o);
+
+ g_free (self->priv->timezone);
+
+ G_OBJECT_CLASS (indicator_datetime_planner_parent_class)->dispose (o);
+}
+
+/***
+**** Instantiation
+***/
+
+static void
+indicator_datetime_planner_class_init (IndicatorDatetimePlannerClass * klass)
+{
+ GObjectClass * object_class;
+ const GParamFlags flags = G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS;
+
+ g_type_class_add_private (klass, sizeof (IndicatorDatetimePlannerPriv));
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = my_finalize;
+ object_class->get_property = my_get_property;
+ object_class->set_property = my_set_property;
+
+ klass->get_appointments = NULL;
+
+ signals[SIGNAL_APPTS_CHANGED] = g_signal_new ("appointments-changed",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (IndicatorDatetimePlannerClass, appointments_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /* install properties */
+
+ properties[PROP_0] = NULL;
+
+ properties[PROP_TIMEZONE] = g_param_spec_string ("timezone",
+ "Timezone",
+ "Default timezone for the EDS appointments",
+ "",
+ flags);
+
+ g_object_class_install_properties (object_class, PROP_LAST, properties);
+}
+
+static void
+indicator_datetime_planner_init (IndicatorDatetimePlanner * self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ INDICATOR_TYPE_DATETIME_PLANNER,
+ IndicatorDatetimePlannerPriv);
+}
+
+/***
+**** Public API
+***/
+
+void
+indicator_datetime_planner_emit_appointments_changed (IndicatorDatetimePlanner * self)
+{
+ g_return_if_fail (INDICATOR_IS_DATETIME_PLANNER (self));
+
+ g_signal_emit (self, signals[SIGNAL_APPTS_CHANGED], 0, NULL);
+}
+
+static gint
+compare_appointments_by_start_time (gconstpointer ga, gconstpointer gb)
+{
+ const struct IndicatorDatetimeAppt * a = ga;
+ const struct IndicatorDatetimeAppt * b = gb;
+
+ return g_date_time_compare (a->begin, b->begin);
+}
+
+GSList *
+indicator_datetime_planner_get_appointments (IndicatorDatetimePlanner * self, GDateTime * begin, GDateTime * end)
+{
+ GSList * appointments;
+
+ g_return_val_if_fail (INDICATOR_IS_DATETIME_PLANNER (self), NULL);
+
+ appointments = INDICATOR_DATETIME_PLANNER_GET_CLASS (self)->get_appointments (self, begin, end);
+ return g_slist_sort (appointments, compare_appointments_by_start_time);
+}
+
+gboolean
+indicator_datetime_planner_is_configured (IndicatorDatetimePlanner * self)
+{
+ g_return_val_if_fail (INDICATOR_IS_DATETIME_PLANNER (self), FALSE);
+
+ return INDICATOR_DATETIME_PLANNER_GET_CLASS (self)->is_configured (self);
+}
+
+void
+indicator_datetime_planner_activate (IndicatorDatetimePlanner * self)
+{
+ g_return_if_fail (INDICATOR_IS_DATETIME_PLANNER (self));
+
+ INDICATOR_DATETIME_PLANNER_GET_CLASS (self)->activate (self);
+}
+
+void
+indicator_datetime_planner_activate_time (IndicatorDatetimePlanner * self, GDateTime * time)
+{
+ g_return_if_fail (INDICATOR_IS_DATETIME_PLANNER (self));
+
+ INDICATOR_DATETIME_PLANNER_GET_CLASS (self)->activate_time (self, time);
+}
+
+void
+indicator_datetime_planner_set_timezone (IndicatorDatetimePlanner * self, const char * timezone)
+{
+ g_return_if_fail (INDICATOR_IS_DATETIME_PLANNER (self));
+
+ g_free (self->priv->timezone);
+ self->priv->timezone = g_strdup (timezone);
+ g_object_notify_by_pspec (G_OBJECT(self), properties[PROP_TIMEZONE]);
+}
+
+const char *
+indicator_datetime_planner_get_timezone (IndicatorDatetimePlanner * self)
+{
+ g_return_val_if_fail (INDICATOR_IS_DATETIME_PLANNER (self), NULL);
+
+ return self->priv->timezone;
+}
diff --git a/src/planner.h b/src/planner.h
new file mode 100644
index 0000000..45a6d3c
--- /dev/null
+++ b/src/planner.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@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/>.
+ */
+
+#ifndef __INDICATOR_DATETIME_PLANNER__H__
+#define __INDICATOR_DATETIME_PLANNER__H__
+
+#include <glib.h>
+#include <glib-object.h> /* parent class */
+#include <gdk/gdk.h> /* GdkRGBA */
+
+G_BEGIN_DECLS
+
+#define INDICATOR_TYPE_DATETIME_PLANNER (indicator_datetime_planner_get_type())
+#define INDICATOR_DATETIME_PLANNER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_PLANNER, IndicatorDatetimePlanner))
+#define INDICATOR_DATETIME_PLANNER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_PLANNER, IndicatorDatetimePlannerClass))
+#define INDICATOR_DATETIME_PLANNER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_DATETIME_PLANNER, IndicatorDatetimePlannerClass))
+#define INDICATOR_IS_DATETIME_PLANNER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_PLANNER))
+
+typedef struct _IndicatorDatetimePlanner IndicatorDatetimePlanner;
+typedef struct _IndicatorDatetimePlannerPriv IndicatorDatetimePlannerPriv;
+typedef struct _IndicatorDatetimePlannerClass IndicatorDatetimePlannerClass;
+
+GType indicator_datetime_planner_get_type (void);
+
+struct IndicatorDatetimeAppt
+{
+ char * color;
+ char * summary;
+ GDateTime * begin;
+ GDateTime * end;
+ gboolean is_event;
+};
+
+/**
+ * Abstract Base Class for objects that provides appointments and events.
+ *
+ * These will be listed in the appointments section of indicator-datetime's menu.
+ */
+struct _IndicatorDatetimePlanner
+{
+ /*< private >*/
+ GObject parent;
+ IndicatorDatetimePlannerPriv * priv;
+};
+
+struct _IndicatorDatetimePlannerClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+
+ void (*appointments_changed) (IndicatorDatetimePlanner * self);
+
+ /* virtual functions */
+
+ GSList* (*get_appointments) (IndicatorDatetimePlanner * self, GDateTime * begin, GDateTime * end);
+
+ gboolean (*is_configured) (IndicatorDatetimePlanner * self);
+ void (*activate) (IndicatorDatetimePlanner * self);
+ void (*activate_time) (IndicatorDatetimePlanner * self, GDateTime *);
+};
+
+/***
+****
+***/
+
+void indicator_datetime_appt_free (struct IndicatorDatetimeAppt * appt);
+
+/**
+ * Get a list of appointments, sorted by start time.
+ *
+ * An easy way to free the list properly in one step is as follows:
+ *
+ * g_slist_free_full (list, (GDestroyNotify)indicator_datetime_appt_free);
+ *
+ *
+ * Return value: (element-type IndicatorDatetimeAppt)
+ * (transfer full):
+ * list of appointments
+ */
+GSList * indicator_datetime_planner_get_appointments (IndicatorDatetimePlanner * self, GDateTime * begin, GDateTime * end);
+
+/**
+ * Returns false if the planner's backend is not configured.
+ *
+ * This can be used on startup to determine whether or not to use this planner.
+ */
+gboolean indicator_datetime_planner_is_configured (IndicatorDatetimePlanner * self);
+
+/**
+ * Activate this planner.
+ *
+ * This is used to activate the planner's backend's event editor.
+ */
+void indicator_datetime_planner_activate (IndicatorDatetimePlanner * self);
+
+/**
+ * Activate this planner.
+ *
+ * This is used to activate the planner's backend's event editor,
+ * with an added hint of the specific time that the user would like to edit.
+ */
+void indicator_datetime_planner_activate_time (IndicatorDatetimePlanner * self, GDateTime * time);
+
+/**
+ * Set the timezone.
+ *
+ * This is used as a default timezone if the backend's events don't provide their own.
+ */
+void indicator_datetime_planner_set_timezone (IndicatorDatetimePlanner * self, const char * timezone);
+
+const char * indicator_datetime_planner_get_timezone (IndicatorDatetimePlanner * self);
+
+
+/**
+ * Emits the "appointments-changed" signal. This should only be called by subclasses.
+ */
+void indicator_datetime_planner_emit_appointments_changed (IndicatorDatetimePlanner * self);
+
+G_END_DECLS
+
+#endif /* __INDICATOR_DATETIME_PLANNER__H__ */
diff --git a/src/service.c b/src/service.c
new file mode 100644
index 0000000..f5e16a0
--- /dev/null
+++ b/src/service.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@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 <locale.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "service.h"
+
+/* FIXME: remove -test */
+#define BUS_NAME "com.canonical.indicator.datetime-test"
+#define BUS_PATH "/com/canonical/indicator/datetime"
+
+G_DEFINE_TYPE (IndicatorDatetimeService,
+ indicator_datetime_service,
+ G_TYPE_OBJECT)
+
+/* signals enum */
+enum
+{
+ NAME_LOST,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum
+{
+ PROP_0,
+ PROP_REPLACE,
+ PROP_LAST
+};
+
+static GParamSpec * properties[PROP_LAST];
+
+enum
+{
+ SECTION_HEADER = (1<<0),
+ SECTION_CALENDAR = (1<<1),
+ SECTION_APPOINTMENTS = (1<<2),
+ SECTION_LOCATIONS = (1<<3),
+ SECTION_SETTINGS = (1<<4),
+};
+
+enum
+{
+ PROFILE_DESKTOP,
+ PROFILE_GREETER,
+ N_PROFILES
+};
+
+static const char * const menu_names[N_PROFILES] =
+{
+ "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
+{
+ guint own_id;
+ GSimpleActionGroup * actions;
+ guint actions_export_id;
+ struct ProfileMenuInfo menus[N_PROFILES];
+ guint rebuild_id;
+ int rebuild_flags;
+ GDBusConnection * conn;
+ GCancellable * cancellable;
+ GSimpleAction * header_action;
+
+ gboolean replace;
+};
+
+typedef IndicatorDatetimeServicePrivate priv_t;
+
+/***
+****
+***/
+
+static void rebuild_now (IndicatorDatetimeService * self, int section);
+static void rebuild_soon (IndicatorDatetimeService * self, int section);
+
+static inline void
+rebuild_header_soon (IndicatorDatetimeService * self)
+{
+ rebuild_soon (self, SECTION_HEADER);
+}
+static inline void
+rebuild_calendar_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);
+}
+
+/***
+****
+***/
+
+static void
+update_header_action (IndicatorDatetimeService * self)
+{
+ GVariant * v;
+ gchar * a11y = g_strdup ("a11y");
+ const gchar * label = "Hello World";
+ const gchar * iconstr = "icon";
+ const priv_t * const p = self->priv;
+
+ g_return_if_fail (p->header_action != NULL);
+
+ v = g_variant_new ("(sssb)", label, iconstr, a11y, TRUE);
+ g_simple_action_set_state (p->header_action, v);
+ g_free (a11y);
+}
+
+/***
+****
+***/
+
+static GMenuModel *
+create_calendar_section (IndicatorDatetimeService * self G_GNUC_UNUSED)
+{
+ GMenu * menu;
+
+ menu = g_menu_new ();
+
+ return G_MENU_MODEL (menu);
+}
+
+static GMenuModel *
+create_appointments_section (IndicatorDatetimeService * self G_GNUC_UNUSED)
+{
+ GMenu * menu;
+
+ menu = g_menu_new ();
+
+ return G_MENU_MODEL (menu);
+}
+
+static GMenuModel *
+create_locations_section (IndicatorDatetimeService * self G_GNUC_UNUSED)
+{
+ GMenu * menu;
+
+ menu = g_menu_new ();
+
+ return G_MENU_MODEL (menu);
+}
+
+static GMenuModel *
+create_settings_section (IndicatorDatetimeService * self G_GNUC_UNUSED)
+{
+ GMenu * menu;
+
+ menu = g_menu_new ();
+
+ g_menu_append (menu, _("Date and Time Settings\342\200\246"), "indicator.activateSettings");
+
+ return G_MENU_MODEL (menu);
+}
+
+static void
+create_menu (IndicatorDatetimeService * self, int profile)
+{
+ GMenu * menu;
+ GMenu * submenu;
+ GMenuItem * header;
+ GMenuModel * sections[16];
+ int i;
+ int n = 0;
+
+ g_assert (0<=profile && profile<N_PROFILES);
+ g_assert (self->priv->menus[profile].menu == NULL);
+
+ if (profile == PROFILE_DESKTOP)
+ {
+ sections[n++] = create_calendar_section (self);
+ sections[n++] = create_appointments_section (self);
+ sections[n++] = create_locations_section (self);
+ sections[n++] = create_settings_section (self);
+ }
+ else if (profile == PROFILE_GREETER)
+ {
+ /* FIXME: what goes here? */
+ }
+
+ /* 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, "indicator._header");
+ 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_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
+***/
+
+static void
+on_settings_activated (GSimpleAction * a G_GNUC_UNUSED,
+ GVariant * param G_GNUC_UNUSED,
+ gpointer gself G_GNUC_UNUSED)
+{
+ g_message ("settings activated");
+}
+
+static void
+init_gactions (IndicatorDatetimeService * self)
+{
+ GVariant * v;
+ GSimpleAction * a;
+ priv_t * p = self->priv;
+
+ GActionEntry entries[] = {
+ { "activateSettings", on_settings_activated, NULL, NULL, NULL },
+ };
+
+ 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 action */
+ v = g_variant_new ("(sssb)", "Hello World", "icon", "a11y", TRUE);
+ a = g_simple_action_new_stateful ("_header", NULL, v);
+ g_simple_action_group_insert (p->actions, G_ACTION(a));
+ p->header_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 * desktop = &p->menus[PROFILE_DESKTOP];
+ //struct ProfileMenuInfo * greeter = &p->menus[PROFILE_GREETER];
+
+ if (sections & SECTION_HEADER)
+ {
+ update_header_action (self);
+ }
+
+ if (sections & SECTION_CALENDAR)
+ {
+ rebuild_section (desktop->submenu, 0, create_calendar_section (self));
+ }
+
+ if (sections & SECTION_APPOINTMENTS)
+ {
+ rebuild_section (desktop->submenu, 1, create_appointments_section (self));
+ }
+
+ if (sections & SECTION_LOCATIONS)
+ {
+ rebuild_section (desktop->submenu, 2, create_locations_section (self));
+ }
+
+ if (sections & SECTION_SETTINGS)
+ {
+ rebuild_section (desktop->submenu, 3, create_settings_section (self));
+ //rebuild_section (greeter->submenu, 0, create_datetime_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);
+ }
+}
+
+/***
+**** 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 (menu->menu == NULL)
+ create_menu (self, 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[NAME_LOST], 0, NULL);
+}
+
+/***
+**** GObject virtual functions
+***/
+
+static void
+my_constructed (GObject * o)
+{
+ GBusNameOwnerFlags owner_flags;
+ IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE(o);
+
+ /* own the name in constructed() instead of init() so that
+ we'll know the value of the 'replace' property */
+ owner_flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT;
+ if (self->priv->replace)
+ owner_flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE;
+
+ self->priv->own_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ BUS_NAME,
+ owner_flags,
+ on_bus_acquired,
+ NULL,
+ on_name_lost,
+ self,
+ NULL);
+}
+
+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_REPLACE:
+ g_value_set_boolean (value, self->priv->replace);
+ 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_REPLACE:
+ self->priv->replace = g_value_get_boolean (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);
+ }
+
+ if (p->rebuild_id)
+ {
+ g_source_remove (p->rebuild_id);
+ p->rebuild_id = 0;
+ }
+
+ g_clear_object (&p->actions);
+
+ for (i=0; i<N_PROFILES; ++i)
+ g_clear_object (&p->menus[i].menu);
+
+ g_clear_object (&p->header_action);
+ g_clear_object (&p->conn);
+
+ G_OBJECT_CLASS (indicator_datetime_service_parent_class)->dispose (o);
+}
+
+/***
+**** Instantiation
+***/
+
+static void
+indicator_datetime_service_init (IndicatorDatetimeService * self)
+{
+ priv_t * p;
+
+ /* init our priv pointer */
+ p = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ INDICATOR_TYPE_DATETIME_SERVICE,
+ IndicatorDatetimeServicePrivate);
+ self->priv = p;
+
+ /* init the backend objects */
+ p->cancellable = g_cancellable_new ();
+
+ init_gactions (self);
+}
+
+static void
+indicator_datetime_service_class_init (IndicatorDatetimeServiceClass * klass)
+{
+ GObjectClass * object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = my_dispose;
+ 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[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);
+
+ properties[PROP_0] = NULL;
+
+ properties[PROP_REPLACE] = g_param_spec_boolean ("replace",
+ "Replace Service",
+ "Replace existing service",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, PROP_LAST, properties);
+}
+
+/***
+**** Public API
+***/
+
+IndicatorDatetimeService *
+indicator_datetime_service_new (gboolean replace)
+{
+ GObject * o = g_object_new (INDICATOR_TYPE_DATETIME_SERVICE,
+ "replace", replace,
+ NULL);
+
+ return INDICATOR_DATETIME_SERVICE (o);
+}
diff --git a/src/service.h b/src/service.h
new file mode 100644
index 0000000..594d7fe
--- /dev/null
+++ b/src/service.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@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/>.
+ */
+
+#ifndef __INDICATOR_DATETIME_SERVICE_H__
+#define __INDICATOR_DATETIME_SERVICE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* standard GObject macros */
+#define INDICATOR_TYPE_DATETIME_SERVICE (indicator_datetime_service_get_type())
+#define INDICATOR_DATETIME_SERVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_SERVICE, IndicatorDatetimeService))
+#define INDICATOR_DATETIME_SERVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_SERVICE, IndicatorDatetimeServiceClass))
+#define INDICATOR_DATETIME_SERVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_DATETIME_SERVICE, IndicatorDatetimeServiceClass))
+#define INDICATOR_IS_DATETIME_SERVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_SERVICE))
+
+typedef struct _IndicatorDatetimeService IndicatorDatetimeService;
+typedef struct _IndicatorDatetimeServiceClass IndicatorDatetimeServiceClass;
+typedef struct _IndicatorDatetimeServicePrivate IndicatorDatetimeServicePrivate;
+
+/* signal keys */
+#define INDICATOR_DATETIME_SERVICE_SIGNAL_NAME_LOST "name-lost"
+
+/**
+ * The Indicator Datetime Service.
+ */
+struct _IndicatorDatetimeService
+{
+ /*< private >*/
+ GObject parent;
+ IndicatorDatetimeServicePrivate * priv;
+};
+
+struct _IndicatorDatetimeServiceClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+
+ void (* name_lost)(IndicatorDatetimeService * self);
+};
+
+/***
+****
+***/
+
+GType indicator_datetime_service_get_type (void);
+
+IndicatorDatetimeService * indicator_datetime_service_new (gboolean replace);
+
+G_END_DECLS
+
+#endif /* __INDICATOR_DATETIME_SERVICE_H__ */
diff --git a/src/timezone-file.c b/src/timezone-file.c
new file mode 100644
index 0000000..2adf2ca
--- /dev/null
+++ b/src/timezone-file.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@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 "config.h"
+
+#include <gio/gio.h> /* GFile, GFileMonitor */
+
+#include "timezone-file.h"
+
+enum
+{
+ PROP_0,
+ PROP_FILENAME,
+ PROP_LAST
+};
+
+static GParamSpec * properties[PROP_LAST] = { 0 };
+
+struct _IndicatorDatetimeTimezoneFilePriv
+{
+ gchar * filename;
+ GFile * file;
+ GFileMonitor * monitor;
+ gchar * timezone;
+};
+
+typedef IndicatorDatetimeTimezoneFilePriv priv_t;
+
+G_DEFINE_TYPE (IndicatorDatetimeTimezoneFile,
+ indicator_datetime_timezone_file,
+ INDICATOR_TYPE_DATETIME_TIMEZONE)
+
+/***
+****
+***/
+
+static void
+reload (IndicatorDatetimeTimezoneFile * self)
+{
+ priv_t * p = self->priv;
+
+ GError * err = NULL;
+ gchar * new_timezone = NULL;
+
+ if (!g_file_get_contents (p->filename, &new_timezone, NULL, &err))
+ {
+ g_warning ("%s Unable to read timezone file '%s': %s", G_STRLOC, p->filename, err->message);
+ g_error_free (err);
+ }
+ else
+ {
+ g_strstrip (new_timezone);
+
+ if (g_strcmp0 (p->timezone, new_timezone))
+ {
+ g_free (p->timezone);
+ p->timezone = g_strdup (new_timezone);
+ g_debug ("%s new timezone set: '%s'", G_STRLOC, p->timezone);
+ indicator_datetime_timezone_notify_timezone (INDICATOR_DATETIME_TIMEZONE(self));
+ }
+
+ g_free (new_timezone);
+ }
+}
+
+static void
+set_filename (IndicatorDatetimeTimezoneFile * self, const char * filename)
+{
+ GError * err;
+ priv_t * p = self->priv;
+
+ g_clear_object (&p->monitor);
+ g_clear_object (&p->file);
+ g_free (p->filename);
+
+ p->filename = g_strdup (filename);
+ p->file = g_file_new_for_path (p->filename);
+
+ err = NULL;
+ p->monitor = g_file_monitor_file (p->file, G_FILE_MONITOR_NONE, NULL, &err);
+ if (err != NULL)
+ {
+ g_warning ("%s Unable to monitor timezone file '%s': %s", G_STRLOC, TIMEZONE_FILE, err->message);
+ g_error_free (err);
+ }
+ else
+ {
+ g_signal_connect_swapped (p->monitor, "changed", G_CALLBACK(reload), self);
+ g_debug ("%s Monitoring timezone file '%s'", G_STRLOC, p->filename);
+ }
+
+ reload (self);
+}
+
+/***
+**** IndicatorDatetimeTimezoneClass funcs
+***/
+
+static const char *
+my_get_timezone (IndicatorDatetimeTimezone * self)
+{
+ return INDICATOR_DATETIME_TIMEZONE_FILE(self)->priv->timezone;
+}
+
+/***
+**** GObjectClass funcs
+***/
+
+static void
+my_get_property (GObject * o,
+ guint property_id,
+ GValue * value,
+ GParamSpec * pspec)
+{
+ IndicatorDatetimeTimezoneFile * self = INDICATOR_DATETIME_TIMEZONE_FILE (o);
+
+ switch (property_id)
+ {
+ case PROP_FILENAME:
+ g_value_set_string (value, self->priv->filename);
+ 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)
+{
+ IndicatorDatetimeTimezoneFile * self = INDICATOR_DATETIME_TIMEZONE_FILE (o);
+
+ switch (property_id)
+ {
+ case PROP_FILENAME:
+ set_filename (self, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
+ }
+}
+
+static void
+my_dispose (GObject * o)
+{
+ IndicatorDatetimeTimezoneFile * self = INDICATOR_DATETIME_TIMEZONE_FILE (o);
+ priv_t * p = self->priv;
+
+ g_clear_object (&p->monitor);
+ g_clear_object (&p->file);
+
+ G_OBJECT_CLASS (indicator_datetime_timezone_file_parent_class)->dispose (o);
+}
+
+static void
+my_finalize (GObject * o)
+{
+ IndicatorDatetimeTimezoneFile * self = INDICATOR_DATETIME_TIMEZONE_FILE (o);
+ priv_t * p = self->priv;
+
+ g_free (p->filename);
+ g_free (p->timezone);
+
+ G_OBJECT_CLASS (indicator_datetime_timezone_file_parent_class)->finalize (o);
+}
+
+/***
+****
+***/
+
+static void
+indicator_datetime_timezone_file_class_init (IndicatorDatetimeTimezoneFileClass * klass)
+{
+ GObjectClass * object_class;
+ IndicatorDatetimeTimezoneClass * location_class;
+ const GParamFlags flags = G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = my_dispose;
+ object_class->finalize = my_finalize;
+ object_class->set_property = my_set_property;
+ object_class->get_property = my_get_property;
+
+ location_class = INDICATOR_DATETIME_TIMEZONE_CLASS (klass);
+ location_class->get_timezone = my_get_timezone;
+
+ g_type_class_add_private (klass, sizeof (IndicatorDatetimeTimezoneFilePriv));
+
+ /* install properties */
+
+ properties[PROP_0] = NULL;
+
+ properties[PROP_FILENAME] = g_param_spec_string ("filename",
+ "Filename",
+ "Filename to monitor for TZ changes",
+ "",
+ flags);
+
+ g_object_class_install_properties (object_class, PROP_LAST, properties);
+}
+
+static void
+indicator_datetime_timezone_file_init (IndicatorDatetimeTimezoneFile * self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ INDICATOR_TYPE_DATETIME_TIMEZONE_FILE,
+ IndicatorDatetimeTimezoneFilePriv);
+}
+
+/***
+**** Public
+***/
+
+IndicatorDatetimeTimezone *
+indicator_datetime_timezone_file_new (const char * filename)
+{
+ gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_TIMEZONE_FILE, "filename", filename, NULL);
+
+ return INDICATOR_DATETIME_TIMEZONE (o);
+}
diff --git a/src/timezone-file.h b/src/timezone-file.h
new file mode 100644
index 0000000..b02abe1
--- /dev/null
+++ b/src/timezone-file.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@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/>.
+ */
+
+#ifndef __INDICATOR_DATETIME_TIMEZONE_FILE__H__
+#define __INDICATOR_DATETIME_TIMEZONE_FILE__H__
+
+#include "timezone.h" /* parent class */
+
+G_BEGIN_DECLS
+
+#define INDICATOR_TYPE_DATETIME_TIMEZONE_FILE (indicator_datetime_timezone_file_get_type())
+#define INDICATOR_DATETIME_TIMEZONE_FILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_TIMEZONE_FILE, IndicatorDatetimeTimezoneFile))
+#define INDICATOR_DATETIME_TIMEZONE_FILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_TIMEZONE_FILE, IndicatorDatetimeTimezoneFileClass))
+#define INDICATOR_IS_DATETIME_TIMEZONE_FILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_TIMEZONE_FILE))
+
+typedef struct _IndicatorDatetimeTimezoneFile IndicatorDatetimeTimezoneFile;
+typedef struct _IndicatorDatetimeTimezoneFilePriv IndicatorDatetimeTimezoneFilePriv;
+typedef struct _IndicatorDatetimeTimezoneFileClass IndicatorDatetimeTimezoneFileClass;
+
+GType indicator_datetime_timezone_file_get_type (void);
+
+/**
+ * An IndicatorDatetimeTimezone which uses a local file,
+ * such as /etc/timezone, to determine the timezone.
+ */
+struct _IndicatorDatetimeTimezoneFile
+{
+ /*< private >*/
+ IndicatorDatetimeTimezone parent;
+ IndicatorDatetimeTimezoneFilePriv * priv;
+};
+
+struct _IndicatorDatetimeTimezoneFileClass
+{
+ IndicatorDatetimeTimezoneClass parent_class;
+};
+
+IndicatorDatetimeTimezone * indicator_datetime_timezone_file_new (const char * filename);
+
+G_END_DECLS
+
+#endif /* __INDICATOR_DATETIME_TIMEZONE_FILE__H__ */
diff --git a/src/location-geoclue.c b/src/timezone-geoclue.c
index 87358fb..08f272d 100644
--- a/src/location-geoclue.c
+++ b/src/timezone-geoclue.c
@@ -19,15 +19,12 @@
#include "config.h"
-#include <glib.h>
-#include <glib/gi18n-lib.h>
-
#include <geoclue/geoclue-master.h>
#include <geoclue/geoclue-master-client.h>
-#include "location-geoclue.h"
+#include "timezone-geoclue.h"
-struct _IndicatorDatetimeLocationGeocluePriv
+struct _IndicatorDatetimeTimezoneGeocluePriv
{
GeoclueMaster * master;
GeoclueMasterClient * client;
@@ -35,20 +32,20 @@ struct _IndicatorDatetimeLocationGeocluePriv
gchar * timezone;
};
-typedef IndicatorDatetimeLocationGeocluePriv priv_t;
+typedef IndicatorDatetimeTimezoneGeocluePriv priv_t;
-G_DEFINE_TYPE (IndicatorDatetimeLocationGeoclue,
- indicator_datetime_location_geoclue,
- INDICATOR_TYPE_DATETIME_LOCATION)
+G_DEFINE_TYPE (IndicatorDatetimeTimezoneGeoclue,
+ indicator_datetime_timezone_geoclue,
+ INDICATOR_TYPE_DATETIME_TIMEZONE)
-static void geo_restart (IndicatorDatetimeLocationGeoclue * self);
+static void geo_restart (IndicatorDatetimeTimezoneGeoclue * self);
/***
****
***/
static void
-set_timezone (IndicatorDatetimeLocationGeoclue * self, const gchar * timezone)
+set_timezone (IndicatorDatetimeTimezoneGeoclue * self, const gchar * timezone)
{
priv_t * p = self->priv;
@@ -56,15 +53,15 @@ set_timezone (IndicatorDatetimeLocationGeoclue * self, const gchar * timezone)
{
g_free (p->timezone);
p->timezone = g_strdup (timezone);
- indicator_datetime_location_notify_timezone (INDICATOR_DATETIME_LOCATION(self));
+ indicator_datetime_timezone_notify_timezone (INDICATOR_DATETIME_TIMEZONE(self));
}
}
static void
-on_address_changed (GeoclueAddress * address,
- int timestamp,
+on_address_changed (GeoclueAddress * address G_GNUC_UNUSED,
+ int timestamp G_GNUC_UNUSED,
GHashTable * addy_data,
- GeoclueAccuracy * accuracy,
+ GeoclueAccuracy * accuracy G_GNUC_UNUSED,
GError * error,
gpointer gself)
{
@@ -75,14 +72,14 @@ on_address_changed (GeoclueAddress * address,
}
else
{
- IndicatorDatetimeLocationGeoclue * self = INDICATOR_DATETIME_LOCATION_GEOCLUE (gself);
+ IndicatorDatetimeTimezoneGeoclue * self = INDICATOR_DATETIME_TIMEZONE_GEOCLUE (gself);
const char * timezone = g_hash_table_lookup (addy_data, "timezone");
set_timezone (self, timezone);
}
}
static void
-on_address_created (GeoclueMasterClient * master,
+on_address_created (GeoclueMasterClient * master G_GNUC_UNUSED,
GeoclueAddress * address,
GError * error,
gpointer gself)
@@ -94,7 +91,7 @@ on_address_created (GeoclueMasterClient * master,
}
else
{
- priv_t * p = INDICATOR_DATETIME_LOCATION_GEOCLUE(gself)->priv;
+ priv_t * p = INDICATOR_DATETIME_TIMEZONE_GEOCLUE(gself)->priv;
g_assert (p->address == NULL);
p->address = g_object_ref (address);
@@ -105,7 +102,9 @@ on_address_created (GeoclueMasterClient * master,
}
static void
-on_requirements_set (GeoclueMasterClient * master, GError * error, gpointer user_data)
+on_requirements_set (GeoclueMasterClient * master G_GNUC_UNUSED,
+ GError * error,
+ gpointer user_data G_GNUC_UNUSED)
{
if (error != NULL)
{
@@ -115,7 +114,7 @@ on_requirements_set (GeoclueMasterClient * master, GError * error, gpointer user
}
static void
-on_client_created (GeoclueMaster * master,
+on_client_created (GeoclueMaster * master G_GNUC_UNUSED,
GeoclueMasterClient * client,
gchar * path,
GError * error,
@@ -128,13 +127,9 @@ on_client_created (GeoclueMaster * master,
g_warning ("%s Unable to get timezone from GeoClue: %s", G_STRFUNC, error->message);
g_error_free (error);
}
- else if (client == NULL)
- {
- g_warning ("%s Unable to get timezone from GeoClue: %s", G_STRFUNC, error->message);
- }
else
{
- IndicatorDatetimeLocationGeoclue * self = INDICATOR_DATETIME_LOCATION_GEOCLUE (gself);
+ IndicatorDatetimeTimezoneGeoclue * self = INDICATOR_DATETIME_TIMEZONE_GEOCLUE (gself);
priv_t * p = self->priv;
g_clear_object (&p->client);
@@ -154,7 +149,7 @@ on_client_created (GeoclueMaster * master,
}
static void
-geo_start (IndicatorDatetimeLocationGeoclue * self)
+geo_start (IndicatorDatetimeTimezoneGeoclue * self)
{
priv_t * p = self->priv;
@@ -164,7 +159,7 @@ geo_start (IndicatorDatetimeLocationGeoclue * self)
}
static void
-geo_stop (IndicatorDatetimeLocationGeoclue * self)
+geo_stop (IndicatorDatetimeTimezoneGeoclue * self)
{
priv_t * p = self->priv;
@@ -184,7 +179,7 @@ geo_stop (IndicatorDatetimeLocationGeoclue * self)
}
static void
-geo_restart (IndicatorDatetimeLocationGeoclue * self)
+geo_restart (IndicatorDatetimeTimezoneGeoclue * self)
{
geo_stop (self);
geo_start (self);
@@ -195,54 +190,54 @@ geo_restart (IndicatorDatetimeLocationGeoclue * self)
***/
static const char *
-my_get_timezone (IndicatorDatetimeLocation * self)
+my_get_timezone (IndicatorDatetimeTimezone * self)
{
- return INDICATOR_DATETIME_LOCATION_GEOCLUE(self)->priv->timezone;
+ return INDICATOR_DATETIME_TIMEZONE_GEOCLUE(self)->priv->timezone;
}
static void
my_dispose (GObject * o)
{
- geo_stop (INDICATOR_DATETIME_LOCATION_GEOCLUE (o));
+ geo_stop (INDICATOR_DATETIME_TIMEZONE_GEOCLUE (o));
- G_OBJECT_CLASS (indicator_datetime_location_geoclue_parent_class)->dispose (o);
+ G_OBJECT_CLASS (indicator_datetime_timezone_geoclue_parent_class)->dispose (o);
}
static void
my_finalize (GObject * o)
{
- IndicatorDatetimeLocationGeoclue * self = INDICATOR_DATETIME_LOCATION_GEOCLUE (o);
+ IndicatorDatetimeTimezoneGeoclue * self = INDICATOR_DATETIME_TIMEZONE_GEOCLUE (o);
priv_t * p = self->priv;
g_free (p->timezone);
- G_OBJECT_CLASS (indicator_datetime_location_geoclue_parent_class)->finalize (o);
+ G_OBJECT_CLASS (indicator_datetime_timezone_geoclue_parent_class)->finalize (o);
}
static void
-indicator_datetime_location_geoclue_class_init (IndicatorDatetimeLocationGeoclueClass * klass)
+indicator_datetime_timezone_geoclue_class_init (IndicatorDatetimeTimezoneGeoclueClass * klass)
{
GObjectClass * object_class;
- IndicatorDatetimeLocationClass * location_class;
+ IndicatorDatetimeTimezoneClass * location_class;
object_class = G_OBJECT_CLASS (klass);
object_class->dispose = my_dispose;
object_class->finalize = my_finalize;
- location_class = INDICATOR_DATETIME_LOCATION_CLASS (klass);
+ location_class = INDICATOR_DATETIME_TIMEZONE_CLASS (klass);
location_class->get_timezone = my_get_timezone;
- g_type_class_add_private (klass, sizeof (IndicatorDatetimeLocationGeocluePriv));
+ g_type_class_add_private (klass, sizeof (IndicatorDatetimeTimezoneGeocluePriv));
}
static void
-indicator_datetime_location_geoclue_init (IndicatorDatetimeLocationGeoclue * self)
+indicator_datetime_timezone_geoclue_init (IndicatorDatetimeTimezoneGeoclue * self)
{
priv_t * p;
p = G_TYPE_INSTANCE_GET_PRIVATE (self,
- INDICATOR_TYPE_DATETIME_LOCATION_GEOCLUE,
- IndicatorDatetimeLocationGeocluePriv);
+ INDICATOR_TYPE_DATETIME_TIMEZONE_GEOCLUE,
+ IndicatorDatetimeTimezoneGeocluePriv);
self->priv = p;
geo_start (self);
@@ -252,10 +247,10 @@ indicator_datetime_location_geoclue_init (IndicatorDatetimeLocationGeoclue * sel
**** Public
***/
-IndicatorDatetimeLocation *
-indicator_datetime_location_geoclue_new (void)
+IndicatorDatetimeTimezone *
+indicator_datetime_timezone_geoclue_new (void)
{
- gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_LOCATION_GEOCLUE, NULL);
+ gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_TIMEZONE_GEOCLUE, NULL);
- return INDICATOR_DATETIME_LOCATION (o);
+ return INDICATOR_DATETIME_TIMEZONE (o);
}
diff --git a/src/timezone-geoclue.h b/src/timezone-geoclue.h
new file mode 100644
index 0000000..059bd81
--- /dev/null
+++ b/src/timezone-geoclue.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@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/>.
+ */
+
+#ifndef __INDICATOR_DATETIME_TIMEZONE_GEOCLUE__H__
+#define __INDICATOR_DATETIME_TIMEZONE_GEOCLUE__H__
+
+#include "timezone.h" /* parent class */
+
+G_BEGIN_DECLS
+
+#define INDICATOR_TYPE_DATETIME_TIMEZONE_GEOCLUE (indicator_datetime_timezone_geoclue_get_type())
+#define INDICATOR_DATETIME_TIMEZONE_GEOCLUE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_TIMEZONE_GEOCLUE, IndicatorDatetimeTimezoneGeoclue))
+#define INDICATOR_DATETIME_TIMEZONE_GEOCLUE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_TIMEZONE_GEOCLUE, IndicatorDatetimeTimezoneGeoclueClass))
+#define INDICATOR_IS_DATETIME_TIMEZONE_GEOCLUE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_TIMEZONE_GEOCLUE))
+
+typedef struct _IndicatorDatetimeTimezoneGeoclue IndicatorDatetimeTimezoneGeoclue;
+typedef struct _IndicatorDatetimeTimezoneGeocluePriv IndicatorDatetimeTimezoneGeocluePriv;
+typedef struct _IndicatorDatetimeTimezoneGeoclueClass IndicatorDatetimeTimezoneGeoclueClass;
+
+GType indicator_datetime_timezone_geoclue_get_type (void);
+
+/**
+ * An IndicatorDatetimeTimezone which uses GeoClue to determine the timezone.
+ */
+struct _IndicatorDatetimeTimezoneGeoclue
+{
+ /*< private >*/
+ IndicatorDatetimeTimezone parent;
+ IndicatorDatetimeTimezoneGeocluePriv * priv;
+};
+
+struct _IndicatorDatetimeTimezoneGeoclueClass
+{
+ IndicatorDatetimeTimezoneClass parent_class;
+};
+
+IndicatorDatetimeTimezone * indicator_datetime_timezone_geoclue_new (void);
+
+G_END_DECLS
+
+#endif /* __INDICATOR_DATETIME_TIMEZONE_GEOCLUE__H__ */
diff --git a/src/location.c b/src/timezone.c
index 12e25c3..546a3e3 100644
--- a/src/location.c
+++ b/src/timezone.c
@@ -17,10 +17,10 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "location.h"
+#include "timezone.h"
-G_DEFINE_TYPE (IndicatorDatetimeLocation,
- indicator_datetime_location,
+G_DEFINE_TYPE (IndicatorDatetimeTimezone,
+ indicator_datetime_timezone,
G_TYPE_OBJECT)
enum
@@ -30,7 +30,7 @@ enum
PROP_LAST
};
-static GParamSpec * properties[PROP_LAST] = { 0 };
+static GParamSpec * properties[PROP_LAST] = { 0, };
static void
my_get_property (GObject * o,
@@ -38,12 +38,12 @@ my_get_property (GObject * o,
GValue * value,
GParamSpec * pspec)
{
- IndicatorDatetimeLocation * self = INDICATOR_DATETIME_LOCATION (o);
+ IndicatorDatetimeTimezone * self = INDICATOR_DATETIME_TIMEZONE (o);
switch (property_id)
{
case PROP_TIMEZONE:
- g_value_set_string (value, indicator_datetime_location_get_timezone (self));
+ g_value_set_string (value, indicator_datetime_timezone_get_timezone (self));
break;
default:
@@ -54,12 +54,12 @@ my_get_property (GObject * o,
static void
my_dispose (GObject * object)
{
- G_OBJECT_CLASS (indicator_datetime_location_parent_class)->dispose (object);
+ G_OBJECT_CLASS (indicator_datetime_timezone_parent_class)->dispose (object);
}
static void
/* cppcheck-suppress unusedFunction */
-indicator_datetime_location_class_init (IndicatorDatetimeLocationClass * klass)
+indicator_datetime_timezone_class_init (IndicatorDatetimeTimezoneClass * klass)
{
GObjectClass * object_class;
const GParamFlags flags = G_PARAM_READABLE | G_PARAM_STATIC_STRINGS;
@@ -70,8 +70,6 @@ indicator_datetime_location_class_init (IndicatorDatetimeLocationClass * klass)
klass->get_timezone = NULL;
- properties[PROP_0] = NULL;
-
properties[PROP_TIMEZONE] = g_param_spec_string ("timezone",
"Timezone",
"Timezone",
@@ -82,7 +80,7 @@ indicator_datetime_location_class_init (IndicatorDatetimeLocationClass * klass)
}
static void
-indicator_datetime_location_init (IndicatorDatetimeLocation * self G_GNUC_UNUSED)
+indicator_datetime_timezone_init (IndicatorDatetimeTimezone * self G_GNUC_UNUSED)
{
}
@@ -91,17 +89,17 @@ indicator_datetime_location_init (IndicatorDatetimeLocation * self G_GNUC_UNUSED
***/
const char *
-indicator_datetime_location_get_timezone (IndicatorDatetimeLocation * self)
+indicator_datetime_timezone_get_timezone (IndicatorDatetimeTimezone * self)
{
- g_return_val_if_fail (INDICATOR_IS_DATETIME_LOCATION (self), NULL);
+ g_return_val_if_fail (INDICATOR_IS_DATETIME_TIMEZONE (self), NULL);
- return INDICATOR_DATETIME_LOCATION_GET_CLASS (self)->get_timezone (self);
+ return INDICATOR_DATETIME_TIMEZONE_GET_CLASS (self)->get_timezone (self);
}
void
-indicator_datetime_location_notify_timezone (IndicatorDatetimeLocation * self)
+indicator_datetime_timezone_notify_timezone (IndicatorDatetimeTimezone * self)
{
- g_return_if_fail (INDICATOR_IS_DATETIME_LOCATION (self));
+ g_return_if_fail (INDICATOR_IS_DATETIME_TIMEZONE (self));
g_object_notify_by_pspec (G_OBJECT(self), properties[PROP_TIMEZONE]);
}
diff --git a/src/timezone.h b/src/timezone.h
new file mode 100644
index 0000000..cadeb6f
--- /dev/null
+++ b/src/timezone.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@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/>.
+ */
+
+#ifndef __INDICATOR_DATETIME_TIMEZONE__H__
+#define __INDICATOR_DATETIME_TIMEZONE__H__
+
+#include <glib.h>
+#include <glib-object.h> /* parent class */
+
+G_BEGIN_DECLS
+
+#define INDICATOR_TYPE_DATETIME_TIMEZONE (indicator_datetime_timezone_get_type())
+#define INDICATOR_DATETIME_TIMEZONE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_TIMEZONE, IndicatorDatetimeTimezone))
+#define INDICATOR_DATETIME_TIMEZONE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_DATETIME_TIMEZONE, IndicatorDatetimeTimezoneClass))
+#define INDICATOR_DATETIME_TIMEZONE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_DATETIME_TIMEZONE, IndicatorDatetimeTimezoneClass))
+#define INDICATOR_IS_DATETIME_TIMEZONE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_DATETIME_TIMEZONE))
+
+typedef struct _IndicatorDatetimeTimezone IndicatorDatetimeTimezone;
+typedef struct _IndicatorDatetimeTimezoneClass IndicatorDatetimeTimezoneClass;
+
+GType indicator_datetime_timezone_get_type (void);
+
+#define INDICATOR_DATETIME_TIMEZONE_PROPERTY_TIMEZONE "timezone"
+
+/**
+ * Abstract Base Class for objects that provide a timezone.
+ *
+ * This is used in datetime to determine the user's current timezone
+ * so that it can be displayed more prominently in the locations
+ * section of the indicator's menu.
+ *
+ * This class has a 'timezone' property that clients can watch
+ * for change notifications.
+ */
+struct _IndicatorDatetimeTimezone
+{
+ /*< private >*/
+ GObject parent;
+};
+
+struct _IndicatorDatetimeTimezoneClass
+{
+ GObjectClass parent_class;
+
+ /* virtual functions */
+ const char * (*get_timezone) (IndicatorDatetimeTimezone * self);
+};
+
+/***
+****
+***/
+
+const char * indicator_datetime_timezone_get_timezone (IndicatorDatetimeTimezone *);
+
+void indicator_datetime_timezone_notify_timezone (IndicatorDatetimeTimezone *);
+
+G_END_DECLS
+
+#endif /* __INDICATOR_DATETIME_TIMEZONE__H__ */