aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/datetime-service.c216
-rw-r--r--src/indicator-datetime.c51
-rw-r--r--src/location-geoclue.c261
-rw-r--r--src/location-geoclue.h61
-rw-r--r--src/location.c108
-rw-r--r--src/location.h68
7 files changed, 567 insertions, 202 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index a31cb4b..f9b8562 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,6 +11,10 @@ indicator_datetime_service_SOURCES = \
datetime-interface.h \
gen-datetime-service.xml.c \
datetime-service.c \
+ location.c \
+ location.h \
+ location-geoclue.c \
+ location-geoclue.h \
utils.c \
utils.h \
dbus-shared.h \
diff --git a/src/datetime-service.c b/src/datetime-service.c
index 6f3cf7b..52d9647 100644
--- a/src/datetime-service.c
+++ b/src/datetime-service.c
@@ -35,9 +35,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <libdbusmenu-glib/client.h>
#include <libdbusmenu-glib/menuitem.h>
-#include <geoclue/geoclue-master.h>
-#include <geoclue/geoclue-master-client.h>
-
#include <time.h>
#include <libecal/libecal.h>
#include <libical/ical.h>
@@ -48,6 +45,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include "datetime-interface.h"
#include "dbus-shared.h"
+#include "location-geoclue.h"
#include "settings-shared.h"
#include "utils.h"
@@ -92,11 +90,11 @@ 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;
-static gchar * geo_timezone = NULL;
struct comp_instance {
ECalComponent *comp;
@@ -187,11 +185,14 @@ update_location_menu_items (void)
const time_t now = time(NULL);
/* maybe add geo_timezone */
- if (geo_timezone != NULL) {
- const gboolean visible = g_settings_get_boolean (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);
+ if (geo_location != NULL) {
+ const char * geo_timezone = indicator_datetime_location_get_timezone (geo_location);
+ if (geo_timezone && *geo_timezone) {
+ const gboolean visible = g_settings_get_boolean (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);
+ }
}
/* maybe add current_timezone */
@@ -1182,174 +1183,6 @@ system_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data)
g_signal_connect(proxy, "g-signal", G_CALLBACK(session_active_change_cb), user_data);
}
-
-/****
-***** GEOCLUE
-****/
-
-static void geo_start (void);
-static void geo_stop (void);
-static void geo_create_client (GeoclueMaster * master, GeoclueMasterClient * client, gchar * path, GError * error, gpointer user_data);
-static void geo_client_invalid (GeoclueMasterClient * client, gpointer user_data);
-
-static GeoclueMaster * geo_master = NULL;
-static GeoclueMasterClient * geo_client = NULL;
-static GeoclueAddress * geo_address = NULL;
-
-static void
-geo_set_timezone (const gchar * timezone)
-{
- if (geo_timezone != timezone) {
- g_clear_pointer (&geo_timezone, g_free);
- geo_timezone = g_strdup (timezone);
- g_debug("Geoclue timezone is: %s", timezone ? timezone : "(Null)");
- update_location_menu_items();
- }
-}
-
-/* Callback from getting the address */
-static void
-geo_address_cb (GeoclueAddress * address, int timestamp, GHashTable * addy_data, GeoclueAccuracy * accuracy, GError * error, gpointer user_data)
-{
- if (error == NULL) {
- geo_set_timezone (g_hash_table_lookup (addy_data, "timezone"));
- } else {
- g_warning("Unable to get Geoclue address: %s", error->message);
- g_clear_error (&error);
- }
-}
-
-/* Clean up the reference we kept to the address and make sure to
- drop the signals incase someone else has one. */
-static void
-geo_address_clean (void)
-{
- if (geo_address != NULL) {
- g_signal_handlers_disconnect_by_func (geo_address, geo_address_cb, NULL);
- g_clear_object (&geo_address);
- }
-}
-
-/* Clean up and remove all signal handlers from the client as we
- unreference it as well. */
-static void
-geo_client_clean (void)
-{
- if (geo_client != NULL) {
- g_signal_handlers_disconnect_by_func (geo_client, geo_client_invalid, NULL);
- g_clear_object (&geo_client);
- }
-}
-
-/* Callback from creating the address */
-static void
-geo_create_address (GeoclueMasterClient * master, GeoclueAddress * address, GError * error, gpointer user_data)
-{
- if (error != NULL) {
- g_warning("Unable to create GeoClue address: %s", error->message);
- g_clear_error (&error);
- return;
- }
-
- /* We shouldn't have created a new address if we already had one
- so this is a warning. But, it really is only a mem-leak so we
- don't need to error out. */
- g_warn_if_fail(geo_address == NULL);
- geo_address_clean();
-
- g_debug("Created Geoclue Address");
- geo_address = g_object_ref (address);
-
- geoclue_address_get_address_async (geo_address, geo_address_cb, NULL);
-
- g_signal_connect (address, "address-changed", G_CALLBACK(geo_address_cb), NULL);
-}
-
-/* Callback from setting requirements */
-static void
-geo_req_set (GeoclueMasterClient * master, GError * error, gpointer user_data)
-{
- if (error != NULL) {
- g_warning("Unable to set Geoclue requirements: %s", error->message);
- g_clear_error (&error);
- }
-}
-
-/* Client is killing itself rather oddly */
-static void
-geo_client_invalid (GeoclueMasterClient * client, gpointer user_data)
-{
- g_warning("Master client invalid, rebuilding.");
- geo_stop ();
- geo_start ();
-}
-
-static void
-geo_stop (void)
-{
- geo_set_timezone (NULL);
-
- geo_address_clean ();
- geo_client_clean ();
- g_clear_object (&geo_master);
-}
-
-static void
-geo_start (void)
-{
- g_warn_if_fail (geo_master == NULL);
-
- g_clear_object (&geo_master);
- geo_master = geoclue_master_get_default();
- geoclue_master_create_client_async (geo_master, geo_create_client, NULL);
-}
-
-/* Callback from creating the client */
-static void
-geo_create_client (GeoclueMaster * master, GeoclueMasterClient * client, gchar * path, GError * error, gpointer user_data)
-{
- g_debug("Created Geoclue client at: %s", path);
-
- geo_client = client;
-
- if (error != NULL) {
- g_warning("Unable to get a GeoClue client! '%s' Geolocation based timezone support will not be available.", error->message);
- g_clear_error (&error);
- return;
- }
-
- if (client == NULL) {
- g_warning(_("Unable to get a GeoClue client! Geolocation based timezone support will not be available."));
- return;
- }
-
- g_object_ref (geo_client);
-
- /* New client, make sure we don't have an address hanging on */
- geo_address_clean();
-
- geoclue_master_client_set_requirements_async(geo_client,
- GEOCLUE_ACCURACY_LEVEL_REGION,
- 0,
- FALSE,
- GEOCLUE_RESOURCE_ALL,
- geo_req_set,
- NULL);
-
- geoclue_master_client_create_address_async(geo_client, geo_create_address, NULL);
-
- g_signal_connect(client, "invalidated", G_CALLBACK(geo_client_invalid), NULL);
-}
-
-static void
-on_use_geoclue_changed_cb (GSettings * settings, gchar * key, gpointer unused G_GNUC_UNUSED)
-{
- geo_stop ();
-
- if (g_settings_get_boolean (conf, SETTINGS_SHOW_DETECTED_S))
- geo_start ();
-}
-
/****
*****
****/
@@ -1417,10 +1250,34 @@ source_registry_changed_cb (ESourceRegistry *registry __attribute__ ((unused)),
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 using = geo_location != NULL;
+ const gboolean should_use = g_settings_get_boolean (conf, "show-auto-detected-location");
+
+ if (using && !should_use)
+ {
+ g_signal_handlers_disconnect_by_func (geo_location, update_location_menu_items, 0);
+ g_clear_object (&geo_location);
+ update_location_menu_items ();
+ }
+ else if (should_use && !using)
+ {
+ geo_location = indicator_datetime_location_geoclue_new ();
+ g_signal_connect (geo_location, "notify::timezone",
+ G_CALLBACK(update_location_menu_items), NULL);
+ }
+}
+
/* Function to build everything up. Entry point from asm. */
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);
@@ -1461,8 +1318,7 @@ main (int argc, char ** argv)
update_current_timezone();
/* Setup geoclue */
- if (g_settings_get_boolean (conf, SETTINGS_SHOW_DETECTED_S))
- geo_start ();
+ on_use_geoclue_changed_cb (conf, NULL, NULL);
/* Setup dbus interface */
dbus = g_object_new(DATETIME_INTERFACE_TYPE, NULL);
@@ -1501,7 +1357,7 @@ main (int argc, char ** argv)
icaltimezone_free_builtin_timezones();
- geo_stop ();
+ g_clear_object (&geo_location);
return 0;
}
diff --git a/src/indicator-datetime.c b/src/indicator-datetime.c
index 9546664..f7d1a78 100644
--- a/src/indicator-datetime.c
+++ b/src/indicator-datetime.c
@@ -266,28 +266,35 @@ indicator_datetime_class_init (IndicatorDatetimeClass *klass)
}
static void
-menu_visible_notfy_cb(GtkWidget * menu, G_GNUC_UNUSED GParamSpec *pspec, gpointer user_data)
+menu_visible_notify_cb(GtkWidget * menu, G_GNUC_UNUSED GParamSpec *pspec, gpointer user_data)
{
- GtkWidget * w;
- GtkCalendar * calendar;
- IndicatorDatetime * self = INDICATOR_DATETIME(user_data);
- GDateTime *datetime;
- gint cur_y, cur_m, cur_d;
- guint cal_y, cal_m, cal_d;
-
- g_debug("notify visible signal received");
-
- /* set the calendar to today's date */
- datetime = g_date_time_new_now_local ();
- g_date_time_get_ymd (datetime, &cur_y, &cur_m, &cur_d);
- g_date_time_unref (datetime);
- w = ido_calendar_menu_item_get_calendar (self->priv->ido_calendar);
- calendar = GTK_CALENDAR(w);
- gtk_calendar_get_date (calendar, &cal_y, &cal_m, &cal_d);
- if ((cur_y != cal_y) || (cur_m-1 != cal_m))
- gtk_calendar_select_month (calendar, cur_m-1, cur_y); /* (cur_m is 1-based) */
- if (cur_d != cal_d)
- gtk_calendar_select_day (calendar, cur_d);
+ IndicatorDatetime * self;
+ g_debug ("notify visible signal received");
+
+ self = INDICATOR_DATETIME (user_data);
+ g_assert (self != NULL);
+
+ /* if the calendar widget's been created, set it to today's datë */
+ if (self->priv->ido_calendar != NULL) {
+ GtkWidget * w;
+ GtkCalendar * calendar;
+ gint cur_y, cur_m, cur_d;
+ guint cal_y, cal_m, cal_d;
+ GDateTime * datetime = g_date_time_new_now_local ();
+
+ g_date_time_get_ymd (datetime, &cur_y, &cur_m, &cur_d);
+ w = ido_calendar_menu_item_get_calendar (self->priv->ido_calendar);
+ calendar = GTK_CALENDAR(w);
+ g_return_if_fail (calendar != NULL);
+
+ gtk_calendar_get_date (calendar, &cal_y, &cal_m, &cal_d);
+ if ((cur_y != cal_y) || (cur_m-1 != cal_m))
+ gtk_calendar_select_month (calendar, cur_m-1, cur_y); /* (cur_m is 1-based) */
+ if (cur_d != cal_d)
+ gtk_calendar_select_day (calendar, cur_d);
+
+ g_date_time_unref (datetime);
+ }
/* Update in case date was changed outside of indicator-datetime */
update_label(self, NULL);
@@ -380,7 +387,7 @@ indicator_datetime_init (IndicatorDatetime *self)
self->priv->menu = dbusmenu_gtkmenu_new(SERVICE_NAME, MENU_OBJ);
- g_signal_connect(self->priv->menu, "notify::visible", G_CALLBACK(menu_visible_notfy_cb), self);
+ g_signal_connect(self->priv->menu, "notify::visible", G_CALLBACK(menu_visible_notify_cb), self);
DbusmenuGtkClient *client = dbusmenu_gtkmenu_get_client(self->priv->menu);
dbusmenu_client_add_type_handler_full(DBUSMENU_CLIENT(client), DBUSMENU_CALENDAR_MENUITEM_TYPE, new_calendar_item, self, NULL);
diff --git a/src/location-geoclue.c b/src/location-geoclue.c
new file mode 100644
index 0000000..2e57f39
--- /dev/null
+++ b/src/location-geoclue.c
@@ -0,0 +1,261 @@
+/*
+ * 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 <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <geoclue/geoclue-master.h>
+#include <geoclue/geoclue-master-client.h>
+
+#include "location-geoclue.h"
+
+struct _IndicatorDatetimeLocationGeocluePriv
+{
+ GeoclueMaster * master;
+ GeoclueMasterClient * client;
+ GeoclueAddress * address;
+ gchar * timezone;
+};
+
+typedef IndicatorDatetimeLocationGeocluePriv priv_t;
+
+G_DEFINE_TYPE (IndicatorDatetimeLocationGeoclue,
+ indicator_datetime_location_geoclue,
+ INDICATOR_TYPE_DATETIME_LOCATION)
+
+static void geo_restart (IndicatorDatetimeLocationGeoclue * self);
+
+/***
+****
+***/
+
+static void
+set_timezone (IndicatorDatetimeLocationGeoclue * self, const gchar * timezone)
+{
+ priv_t * p = self->priv;
+
+ if (p->timezone != timezone)
+ {
+ g_free (p->timezone);
+ p->timezone = g_strdup (timezone);
+ indicator_datetime_location_notify_timezone (INDICATOR_DATETIME_LOCATION(self));
+ }
+}
+
+static void
+on_address_changed (GeoclueAddress * address,
+ int timestamp,
+ GHashTable * addy_data,
+ GeoclueAccuracy * accuracy,
+ GError * error,
+ gpointer gself)
+{
+ if (error != NULL)
+ {
+ g_warning ("%s Unable to get timezone from GeoClue: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ IndicatorDatetimeLocationGeoclue * self = INDICATOR_DATETIME_LOCATION_GEOCLUE (gself);
+ const char * timezone = g_hash_table_lookup (addy_data, "timezone");
+ set_timezone (self, timezone);
+ }
+}
+
+static void
+on_address_created (GeoclueMasterClient * master,
+ GeoclueAddress * address,
+ GError * error,
+ gpointer gself)
+{
+ if (error != NULL)
+ {
+ g_warning ("%s Unable to get timezone from GeoClue: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ priv_t * p = INDICATOR_DATETIME_LOCATION_GEOCLUE(gself)->priv;
+
+ g_assert (p->address == NULL);
+ p->address = g_object_ref (address);
+
+ geoclue_address_get_address_async (address, on_address_changed, gself);
+ g_signal_connect (address, "address-changed", G_CALLBACK(on_address_changed), gself);
+ }
+}
+
+static void
+on_requirements_set (GeoclueMasterClient * master, GError * error, gpointer user_data)
+{
+ if (error != NULL)
+ {
+ g_warning ("%s Unable to get timezone from GeoClue: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+on_client_created (GeoclueMaster * master,
+ GeoclueMasterClient * client,
+ gchar * path,
+ GError * error,
+ gpointer gself)
+{
+ g_debug ("Created Geoclue client at: %s", path);
+
+ if (error != NULL)
+ {
+ 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);
+ priv_t * p = self->priv;
+
+ g_clear_object (&p->client);
+ p->client = g_object_ref (client);
+ g_signal_connect_swapped (p->client, "invalidated", G_CALLBACK(geo_restart), gself);
+
+ geoclue_master_client_set_requirements_async (p->client,
+ GEOCLUE_ACCURACY_LEVEL_REGION,
+ 0,
+ FALSE,
+ GEOCLUE_RESOURCE_ALL,
+ on_requirements_set,
+ NULL);
+
+ geoclue_master_client_create_address_async (p->client, on_address_created, gself);
+ }
+}
+
+static void
+geo_start (IndicatorDatetimeLocationGeoclue * self)
+{
+ priv_t * p = self->priv;
+
+ g_assert (p->master == NULL);
+ p->master = geoclue_master_get_default ();
+ geoclue_master_create_client_async (p->master, on_client_created, self);
+}
+
+static void
+geo_stop (IndicatorDatetimeLocationGeoclue * self)
+{
+ priv_t * p = self->priv;
+
+ if (p->address != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (p->address, on_address_changed, self);
+ g_clear_object (&p->address);
+ }
+
+ if (p->client != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (p->client, geo_restart, self);
+ g_clear_object (&p->client);
+ }
+
+ g_clear_object (&p->master);
+}
+
+static void
+geo_restart (IndicatorDatetimeLocationGeoclue * self)
+{
+ geo_stop (self);
+ geo_start (self);
+}
+
+/***
+****
+***/
+
+static const char *
+my_get_timezone (IndicatorDatetimeLocation * self)
+{
+ return INDICATOR_DATETIME_LOCATION_GEOCLUE(self)->priv->timezone;
+}
+
+static void
+my_dispose (GObject * o)
+{
+ geo_stop (INDICATOR_DATETIME_LOCATION_GEOCLUE (o));
+
+ G_OBJECT_CLASS (indicator_datetime_location_geoclue_parent_class)->dispose (o);
+}
+
+static void
+my_finalize (GObject * o)
+{
+ IndicatorDatetimeLocationGeoclue * self = INDICATOR_DATETIME_LOCATION_GEOCLUE (o);
+ priv_t * p = self->priv;
+
+ g_free (p->timezone);
+
+ G_OBJECT_CLASS (indicator_datetime_location_geoclue_parent_class)->finalize (o);
+}
+
+static void
+indicator_datetime_location_geoclue_class_init (IndicatorDatetimeLocationGeoclueClass * klass)
+{
+ GObjectClass * object_class;
+ IndicatorDatetimeLocationClass * 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->get_timezone = my_get_timezone;
+
+ g_type_class_add_private (klass, sizeof (IndicatorDatetimeLocationGeocluePriv));
+}
+
+static void
+indicator_datetime_location_geoclue_init (IndicatorDatetimeLocationGeoclue * self)
+{
+ priv_t * p;
+
+ p = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ INDICATOR_TYPE_DATETIME_LOCATION_GEOCLUE,
+ IndicatorDatetimeLocationGeocluePriv);
+ self->priv = p;
+
+ geo_start (self);
+}
+
+/***
+**** Public
+***/
+
+IndicatorDatetimeLocation *
+indicator_datetime_location_geoclue_new (void)
+{
+ gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_LOCATION_GEOCLUE, NULL);
+
+ return INDICATOR_DATETIME_LOCATION (o);
+}
diff --git a/src/location-geoclue.h b/src/location-geoclue.h
new file mode 100644
index 0000000..7b65917
--- /dev/null
+++ b/src/location-geoclue.h
@@ -0,0 +1,61 @@
+/*
+ * 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.c b/src/location.c
new file mode 100644
index 0000000..12e25c3
--- /dev/null
+++ b/src/location.c
@@ -0,0 +1,108 @@
+/*
+ * 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 "location.h"
+
+G_DEFINE_TYPE (IndicatorDatetimeLocation,
+ indicator_datetime_location,
+ G_TYPE_OBJECT)
+
+enum
+{
+ PROP_0,
+ PROP_TIMEZONE,
+ PROP_LAST
+};
+
+static GParamSpec * properties[PROP_LAST] = { 0 };
+
+static void
+my_get_property (GObject * o,
+ guint property_id,
+ GValue * value,
+ GParamSpec * pspec)
+{
+ IndicatorDatetimeLocation * self = INDICATOR_DATETIME_LOCATION (o);
+
+ switch (property_id)
+ {
+ case PROP_TIMEZONE:
+ g_value_set_string (value, indicator_datetime_location_get_timezone (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
+ }
+}
+
+static void
+my_dispose (GObject * object)
+{
+ G_OBJECT_CLASS (indicator_datetime_location_parent_class)->dispose (object);
+}
+
+static void
+/* cppcheck-suppress unusedFunction */
+indicator_datetime_location_class_init (IndicatorDatetimeLocationClass * klass)
+{
+ GObjectClass * object_class;
+ const GParamFlags flags = G_PARAM_READABLE | G_PARAM_STATIC_STRINGS;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->get_property = my_get_property;
+ object_class->dispose = my_dispose;
+
+ klass->get_timezone = NULL;
+
+ properties[PROP_0] = NULL;
+
+ properties[PROP_TIMEZONE] = g_param_spec_string ("timezone",
+ "Timezone",
+ "Timezone",
+ "",
+ flags);
+
+ g_object_class_install_properties (object_class, PROP_LAST, properties);
+}
+
+static void
+indicator_datetime_location_init (IndicatorDatetimeLocation * self G_GNUC_UNUSED)
+{
+}
+
+/***
+****
+***/
+
+const char *
+indicator_datetime_location_get_timezone (IndicatorDatetimeLocation * self)
+{
+ g_return_val_if_fail (INDICATOR_IS_DATETIME_LOCATION (self), NULL);
+
+ return INDICATOR_DATETIME_LOCATION_GET_CLASS (self)->get_timezone (self);
+}
+
+void
+indicator_datetime_location_notify_timezone (IndicatorDatetimeLocation * self)
+{
+ g_return_if_fail (INDICATOR_IS_DATETIME_LOCATION (self));
+
+ g_object_notify_by_pspec (G_OBJECT(self), properties[PROP_TIMEZONE]);
+}
+
diff --git a/src/location.h b/src/location.h
new file mode 100644
index 0000000..f9fd2ce
--- /dev/null
+++ b/src/location.h
@@ -0,0 +1,68 @@
+/*
+ * 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__ */