aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/CMakeLists.txt2
-rw-r--r--src/CMakeLists.txt50
-rw-r--r--src/clock-live.c278
-rw-r--r--src/clock-live.h73
-rw-r--r--src/clock.c110
-rw-r--r--src/clock.h76
-rw-r--r--src/dbus-shared.h24
-rw-r--r--src/formatter.cpp462
-rw-r--r--src/planner-eds.c653
-rw-r--r--src/planner.c281
-rw-r--r--src/service.h84
-rw-r--r--src/settings-shared.h50
-rw-r--r--src/timezone-file.c212
-rw-r--r--src/timezone-file.h58
-rw-r--r--src/timezone-geoclue.c227
-rw-r--r--src/timezone-geoclue.h57
-rw-r--r--src/timezone.c134
-rw-r--r--src/timezone.h72
-rw-r--r--src/timezones-live.cpp69
-rw-r--r--src/utils.c453
-rw-r--r--src/utils.cpp140
-rw-r--r--src/utils.h66
-rw-r--r--tests/CMakeLists.txt76
-rw-r--r--tests/geoclue-fixture.h142
-rw-r--r--tests/glib-fixture.h131
-rw-r--r--tests/test-core.cc148
-rw-r--r--tests/test-skew.cc209
-rw-r--r--tests/test-timezones.cc122
28 files changed, 1520 insertions, 2939 deletions
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
new file mode 100644
index 0000000..cfef04b
--- /dev/null
+++ b/include/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(core)
+add_subdirectory(datetime)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2d51385..2c847ff 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,6 +1,8 @@
-set (SERVICE_LIB "libindicatordatetimeservice")
+set (SERVICE_LIB "indicatordatetimeservice")
set (SERVICE_EXEC "indicator-datetime-service")
+SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g ${CXX_WARNING_ARGS}")
+
add_definitions (-DTIMEZONE_FILE="/etc/timezone"
-DG_LOG_DOMAIN="Indicator-Datetime")
@@ -10,36 +12,28 @@ if (BUILD_PANEL)
endif ()
add_library (${SERVICE_LIB} STATIC
- clock.c
- clock.h
- clock-live.c
- clock-live.h
- planner.c
- planner.h
- planner-eds.c
- planner-eds.h
- service.c
- service.h
- 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)
-include_directories (${SERVICE_DEPS_INCLUDE_DIRS})
+ clock.cpp
+ clock-live.cpp
+ formatter.cpp
+ formatter-desktop.cpp
+ locations.cpp
+ locations-settings.cpp
+ planner-eds.cpp
+ timezone-file.cpp
+ timezone-geoclue.cpp
+ timezones-live.cpp
+ utils.cpp)
+include_directories (${CMAKE_SOURCE_DIR})
link_directories (${SERVICE_DEPS_LIBRARY_DIRS})
-add_executable (${SERVICE_EXEC} main.c)
-target_link_libraries (${SERVICE_EXEC} ${SERVICE_LIB} ${SERVICE_DEPS_LIBRARIES} ${GCOV_LIBS})
-install (TARGETS ${SERVICE_EXEC} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR})
+
+#add_executable (${SERVICE_EXEC} main.c)
+#target_link_libraries (${SERVICE_EXEC} ${SERVICE_LIB} ${SERVICE_DEPS_LIBRARIES} ${GCOV_LIBS})
+#install (TARGETS ${SERVICE_EXEC} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR})
# common properties
-set_property (TARGET ${SERVICE_LIB} ${SERVICE_EXEC}
- APPEND_STRING PROPERTY COMPILE_FLAGS
- " -g ${CC_WARNING_ARGS} ${GCOV_FLAGS}")
+#set_property (TARGET ${SERVICE_LIB} ${SERVICE_EXEC}
+# APPEND_STRING PROPERTY COMPILE_FLAGS
+# " -g ${CC_WARNING_ARGS} ${GCOV_FLAGS}")
diff --git a/src/clock-live.c b/src/clock-live.c
deleted file mode 100644
index 2a375fd..0000000
--- a/src/clock-live.c
+++ /dev/null
@@ -1,278 +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/>.
- */
-
-#include <glib.h>
-#include <gio/gio.h>
-
-#include "clock-live.h"
-#include "settings-shared.h"
-#include "timezone-file.h"
-#include "timezone-geoclue.h"
-
-/***
-**** private struct
-***/
-
-struct _IndicatorDatetimeClockLivePriv
-{
- GSettings * settings;
-
- GSList * timezones; /* IndicatorDatetimeTimezone */
- gchar ** timezones_strv;
- GTimeZone * localtime_zone;
-};
-
-typedef IndicatorDatetimeClockLivePriv priv_t;
-
-/***
-**** GObject boilerplate
-***/
-
-static void indicator_datetime_clock_interface_init (
- IndicatorDatetimeClockInterface * iface);
-
-G_DEFINE_TYPE_WITH_CODE (
- IndicatorDatetimeClockLive,
- indicator_datetime_clock_live,
- G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (INDICATOR_TYPE_DATETIME_CLOCK,
- indicator_datetime_clock_interface_init))
-
-/***
-**** Timezones
-***/
-
-static void
-on_current_timezone_changed (IndicatorDatetimeClockLive * self)
-{
- priv_t * p = self->priv;
-
- /* Invalidate the timezone information.
- These fields will be lazily regenerated by rebuild_timezones() */
- g_clear_pointer (&p->timezones_strv, g_strfreev);
- g_clear_pointer (&p->localtime_zone, g_time_zone_unref);
-
- indicator_datetime_clock_emit_changed (INDICATOR_DATETIME_CLOCK (self));
-}
-
-static void
-set_detect_location_enabled (IndicatorDatetimeClockLive * self, gboolean enabled)
-{
- GSList * l;
- priv_t * p = self->priv;
- gboolean changed = FALSE;
-
- /* clear out the old timezone objects */
- if (p->timezones != NULL)
- {
- for (l=p->timezones; l!=NULL; l=l->next)
- {
- g_signal_handlers_disconnect_by_func (l->data, on_current_timezone_changed, self);
- g_object_unref (l->data);
- }
-
- g_slist_free (p->timezones);
- p->timezones = NULL;
- changed = TRUE;
- }
-
- /* maybe add new timezone objects */
- if (enabled)
- {
- p->timezones = g_slist_append (p->timezones, indicator_datetime_timezone_geoclue_new ());
- p->timezones = g_slist_append (p->timezones, indicator_datetime_timezone_file_new (TIMEZONE_FILE));
-
- for (l=p->timezones; l!=NULL; l=l->next)
- {
- g_signal_connect_swapped (l->data, "notify::timezone",
- G_CALLBACK(on_current_timezone_changed), self);
- }
-
- changed = TRUE;
- }
-
- if (changed)
- on_current_timezone_changed (self);
-}
-
-/* When the 'auto-detect timezone' boolean setting changes,
- start or stop watching geoclue and /etc/timezone */
-static void
-on_detect_location_changed (IndicatorDatetimeClockLive * self)
-{
- const gboolean enabled = g_settings_get_boolean (self->priv->settings, SETTINGS_SHOW_DETECTED_S);
- set_detect_location_enabled (self, enabled);
-}
-
-/***
-**** IndicatorDatetimeClock virtual functions
-***/
-
-static void
-rebuild_timezones (IndicatorDatetimeClockLive * self)
-{
- priv_t * p;
- GHashTable * hash;
- GSList * l;
- int i;
- GHashTableIter iter;
- gpointer key;
-
- p = self->priv;
-
- /* Build a hashtable of timezone strings.
- This will weed out duplicates. */
- hash = g_hash_table_new (g_str_hash, g_str_equal);
- for (l=p->timezones; l!=NULL; l=l->next)
- {
- const gchar * tz = indicator_datetime_timezone_get_timezone (l->data);
- if (tz && *tz)
- g_hash_table_add (hash, (gpointer) tz);
- }
-
- /* rebuild p->timezone_strv */
- g_strfreev (p->timezones_strv);
- p->timezones_strv = g_new0 (gchar*, g_hash_table_size(hash) + 1);
- i = 0;
- g_hash_table_iter_init (&iter, hash);
- while (g_hash_table_iter_next (&iter, &key, NULL))
- p->timezones_strv[i++] = g_strdup (key);
-
- /* rebuild localtime_zone */
- g_clear_pointer (&p->localtime_zone, g_time_zone_unref);
- p->localtime_zone = g_time_zone_new (p->timezones_strv ? p->timezones_strv[0] : NULL);
-
- /* cleanup */
- g_hash_table_unref (hash);
-}
-
-static const gchar **
-my_get_timezones (IndicatorDatetimeClock * clock)
-{
- IndicatorDatetimeClockLive * self = INDICATOR_DATETIME_CLOCK_LIVE (clock);
- priv_t * p = self->priv;
-
- if (G_UNLIKELY (p->timezones_strv == NULL))
- rebuild_timezones (self);
-
- return (const gchar **) p->timezones_strv;
-}
-
-static GDateTime *
-my_get_localtime (IndicatorDatetimeClock * clock)
-{
- IndicatorDatetimeClockLive * self = INDICATOR_DATETIME_CLOCK_LIVE (clock);
- priv_t * p = self->priv;
-
- if (G_UNLIKELY (p->localtime_zone == NULL))
- rebuild_timezones (self);
-
- return g_date_time_new_now (p->localtime_zone);
-}
-
-/***
-**** GObject virtual functions
-***/
-
-static void
-my_dispose (GObject * o)
-{
- IndicatorDatetimeClockLive * self;
- priv_t * p;
-
- self = INDICATOR_DATETIME_CLOCK_LIVE(o);
- p = self->priv;
-
- if (p->settings != NULL)
- {
- g_signal_handlers_disconnect_by_data (p->settings, self);
- g_clear_object (&p->settings);
- }
-
- set_detect_location_enabled (self, FALSE);
-
- G_OBJECT_CLASS (indicator_datetime_clock_live_parent_class)->dispose (o);
-}
-
-static void
-my_finalize (GObject * o)
-{
- IndicatorDatetimeClockLive * self;
- priv_t * p;
-
- self = INDICATOR_DATETIME_CLOCK_LIVE(o);
- p = self->priv;
-
- g_clear_pointer (&p->localtime_zone, g_time_zone_unref);
- g_strfreev (p->timezones_strv);
-
- G_OBJECT_CLASS (indicator_datetime_clock_live_parent_class)->dispose (o);
-}
-
-/***
-**** Instantiation
-***/
-
-static void
-indicator_datetime_clock_live_class_init (IndicatorDatetimeClockLiveClass * klass)
-{
- GObjectClass * object_class = G_OBJECT_CLASS (klass);
-
- object_class->dispose = my_dispose;
- object_class->finalize = my_finalize;
-
- g_type_class_add_private (klass,
- sizeof (IndicatorDatetimeClockLivePriv));
-}
-
-static void
-indicator_datetime_clock_interface_init (IndicatorDatetimeClockInterface * iface)
-{
- iface->get_localtime = my_get_localtime;
- iface->get_timezones = my_get_timezones;
-}
-
-static void
-indicator_datetime_clock_live_init (IndicatorDatetimeClockLive * self)
-{
- IndicatorDatetimeClockLivePriv * p;
-
- p = G_TYPE_INSTANCE_GET_PRIVATE (self,
- INDICATOR_TYPE_DATETIME_CLOCK_LIVE,
- IndicatorDatetimeClockLivePriv);
- self->priv = p;
-
- p->settings = g_settings_new (SETTINGS_INTERFACE);
- g_signal_connect_swapped (p->settings, "changed::" SETTINGS_SHOW_DETECTED_S,
- G_CALLBACK(on_detect_location_changed), self);
-
- on_detect_location_changed (self);
-}
-
-/***
-**** Public API
-***/
-
-IndicatorDatetimeClock *
-indicator_datetime_clock_live_new (void)
-{
- gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_CLOCK_LIVE, NULL);
-
- return INDICATOR_DATETIME_CLOCK (o);
-}
diff --git a/src/clock-live.h b/src/clock-live.h
deleted file mode 100644
index 4425f5b..0000000
--- a/src/clock-live.h
+++ /dev/null
@@ -1,73 +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_CLOCK_LIVE__H__
-#define __INDICATOR_DATETIME_CLOCK_LIVE__H__
-
-#include <glib-object.h> /* parent class */
-
-#include "clock.h"
-
-G_BEGIN_DECLS
-
-#define INDICATOR_TYPE_DATETIME_CLOCK_LIVE \
- (indicator_datetime_clock_live_get_type())
-
-#define INDICATOR_DATETIME_CLOCK_LIVE(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), \
- INDICATOR_TYPE_DATETIME_CLOCK_LIVE, \
- IndicatorDatetimeClockLive))
-
-#define INDICATOR_DATETIME_CLOCK_LIVE_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), \
- INDICATOR_TYPE_DATETIME_CLOCK_LIVE, \
- IndicatorDatetimeClockLiveClass))
-
-#define INDICATOR_IS_DATETIME_CLOCK_LIVE(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
- INDICATOR_TYPE_DATETIME_CLOCK_LIVE))
-
-typedef struct _IndicatorDatetimeClockLive
- IndicatorDatetimeClockLive;
-typedef struct _IndicatorDatetimeClockLivePriv
- IndicatorDatetimeClockLivePriv;
-typedef struct _IndicatorDatetimeClockLiveClass
- IndicatorDatetimeClockLiveClass;
-
-/**
- * An IndicatorDatetimeClock which gives live clock times
- * from timezones determined by geoclue and /etc/timezone
- */
-struct _IndicatorDatetimeClockLive
-{
- GObject parent_instance;
-
- IndicatorDatetimeClockLivePriv * priv;
-};
-
-struct _IndicatorDatetimeClockLiveClass
-{
- GObjectClass parent_class;
-};
-
-IndicatorDatetimeClock * indicator_datetime_clock_live_new (void);
-
-G_END_DECLS
-
-#endif /* __INDICATOR_DATETIME_CLOCK_LIVE__H__ */
diff --git a/src/clock.c b/src/clock.c
deleted file mode 100644
index 2c2fec2..0000000
--- a/src/clock.c
+++ /dev/null
@@ -1,110 +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/>.
- */
-
-#include "clock.h"
-
-enum
-{
- SIGNAL_CHANGED,
- SIGNAL_LAST
-};
-
-static guint signals[SIGNAL_LAST] = { 0 };
-
-G_DEFINE_INTERFACE (IndicatorDatetimeClock,
- indicator_datetime_clock,
- G_TYPE_OBJECT);
-
-static void
-indicator_datetime_clock_default_init (IndicatorDatetimeClockInterface * klass)
-{
- signals[SIGNAL_CHANGED] = g_signal_new (
- "changed",
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (IndicatorDatetimeClockInterface, changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-}
-
-/***
-**** PUBLIC API
-***/
-
-/**
- * Get a strv of timezones.
- *
- * Return value: (element-type char*)
- * (transfer full):
- * array of timezone strings
- */
-const gchar **
-indicator_datetime_clock_get_timezones (IndicatorDatetimeClock * self)
-{
- const gchar ** timezones;
- IndicatorDatetimeClockInterface * iface;
-
- g_return_val_if_fail (INDICATOR_IS_DATETIME_CLOCK(self), NULL);
- iface = INDICATOR_DATETIME_CLOCK_GET_INTERFACE(self);
-
- if (iface->get_timezones != NULL)
- timezones = iface->get_timezones (self);
- else
- timezones = NULL;
-
- return timezones;
-}
-
-/**
- * Get the current time.
- *
- * Return value: (element-type GDateTime*)
- * (transfer full):
- * the current time.
- */
-GDateTime *
-indicator_datetime_clock_get_localtime (IndicatorDatetimeClock * self)
-{
- GDateTime * now;
- IndicatorDatetimeClockInterface * iface;
-
- g_return_val_if_fail (INDICATOR_IS_DATETIME_CLOCK(self), NULL);
- iface = INDICATOR_DATETIME_CLOCK_GET_INTERFACE(self);
-
- if (iface->get_localtime != NULL)
- now = iface->get_localtime (self);
- else
- now = NULL;
-
- return now;
-}
-
-/**
- * Emits the "changed" signal.
- *
- * This should only be called by subclasses.
- */
-void
-indicator_datetime_clock_emit_changed (IndicatorDatetimeClock * self)
-{
- g_return_if_fail (INDICATOR_IS_DATETIME_CLOCK (self));
-
- g_signal_emit (self, signals[SIGNAL_CHANGED], 0, NULL);
-}
diff --git a/src/clock.h b/src/clock.h
deleted file mode 100644
index 40cdf1c..0000000
--- a/src/clock.h
+++ /dev/null
@@ -1,76 +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_CLOCK__H__
-#define __INDICATOR_DATETIME_CLOCK__H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define INDICATOR_TYPE_DATETIME_CLOCK \
- (indicator_datetime_clock_get_type ())
-
-#define INDICATOR_DATETIME_CLOCK(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
- INDICATOR_TYPE_DATETIME_CLOCK, \
- IndicatorDatetimeClock))
-
-#define INDICATOR_IS_DATETIME_CLOCK(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_TYPE_DATETIME_CLOCK))
-
-#define INDICATOR_DATETIME_CLOCK_GET_INTERFACE(inst) \
- (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
- INDICATOR_TYPE_DATETIME_CLOCK, \
- IndicatorDatetimeClockInterface))
-
-typedef struct _IndicatorDatetimeClock
- IndicatorDatetimeClock;
-
-typedef struct _IndicatorDatetimeClockInterface
- IndicatorDatetimeClockInterface;
-
-struct _IndicatorDatetimeClockInterface
-{
- GTypeInterface parent_iface;
-
- /* signals */
- void (*changed) (IndicatorDatetimeClock * self);
-
- /* virtual functions */
- const gchar** (*get_timezones) (IndicatorDatetimeClock * self);
- GDateTime* (*get_localtime) (IndicatorDatetimeClock * self);
-};
-
-GType indicator_datetime_clock_get_type (void);
-
-/***
-****
-***/
-
-const gchar ** indicator_datetime_clock_get_timezones (IndicatorDatetimeClock * clock);
-
-GDateTime * indicator_datetime_clock_get_localtime (IndicatorDatetimeClock * clock);
-
-void indicator_datetime_clock_emit_changed (IndicatorDatetimeClock * clock);
-
-
-G_END_DECLS
-
-#endif /* __INDICATOR_DATETIME_CLOCK__H__ */
diff --git a/src/dbus-shared.h b/src/dbus-shared.h
deleted file mode 100644
index 24319e3..0000000
--- a/src/dbus-shared.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
-An indicator to show date and time information.
-
-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
-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/>.
-*/
-
-#define BUS_NAME "com.canonical.indicator.datetime"
-#define BUS_PATH "/com/canonical/indicator/datetime"
-
diff --git a/src/formatter.cpp b/src/formatter.cpp
new file mode 100644
index 0000000..4e2f582
--- /dev/null
+++ b/src/formatter.cpp
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * 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/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include <datetime/formatter.h>
+
+#include <datetime/clock.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <locale.h> // setlocale()
+#include <langinfo.h> // nl_langinfo()
+#include <string.h> // strstr()
+
+namespace
+{
+void clearTimer (guint& tag)
+{
+ if (tag)
+ {
+ g_source_remove (tag);
+ tag = 0;
+ }
+}
+
+guint calculate_milliseconds_until_next_minute (GDateTime * now)
+{
+ GDateTime * next;
+ GDateTime * start_of_next;
+ GTimeSpan interval_usec;
+ guint interval_msec;
+
+ next = g_date_time_add_minutes(now, 1);
+ start_of_next = g_date_time_new_local(g_date_time_get_year (next),
+ g_date_time_get_month (next),
+ g_date_time_get_day_of_month (next),
+ g_date_time_get_hour (next),
+ g_date_time_get_minute (next),
+ 0.1);
+
+ interval_usec = g_date_time_difference(start_of_next, now);
+ interval_msec = (interval_usec + 999) / 1000;
+
+ g_date_time_unref(start_of_next);
+ g_date_time_unref(next);
+ return interval_msec;
+}
+
+gint calculate_milliseconds_until_next_second (GDateTime * now)
+{
+ gint interval_usec;
+ guint interval_msec;
+
+ interval_usec = G_USEC_PER_SEC - g_date_time_get_microsecond (now);
+ interval_msec = (interval_usec + 999) / 1000;
+ return interval_msec;
+}
+
+/*
+ * We periodically rebuild the sections that have time format strings
+ * that are dependent on the current time:
+ *
+ * 1. appointment menuitems' time format strings depend on the
+ * current time; for example, they don't show the day of week
+ * if the appointment is today.
+ *
+ * 2. location menuitems' time format strings depend on the
+ * current time; for example, they don't show the day of the week
+ * if the local date and location date are the same.
+ *
+ * 3. the "local date" menuitem in the calendar section is,
+ * obviously, dependent on the local time.
+ *
+ * In short, we want to update whenever the number of days between two zone
+ * might have changed. We do that by updating when either zone's day changes.
+ *
+ * Since not all UTC offsets are evenly divisible by hours
+ * (examples: Newfoundland UTC-03:30, Nepal UTC+05:45), refreshing on the hour
+ * is not enough. We need to refresh at HH:00, HH:15, HH:30, and HH:45.
+ */
+guint calculate_seconds_until_next_fifteen_minutes (GDateTime * now)
+{
+ char * str;
+ gint minute;
+ guint seconds;
+ GTimeSpan diff;
+ GDateTime * next;
+ GDateTime * start_of_next;
+
+ minute = g_date_time_get_minute(now);
+ minute = 15 - (minute % 15);
+ next = g_date_time_add_minutes(now, minute);
+ start_of_next = g_date_time_new_local(g_date_time_get_year (next),
+ g_date_time_get_month (next),
+ g_date_time_get_day_of_month (next),
+ g_date_time_get_hour (next),
+ g_date_time_get_minute (next),
+ 0.1);
+
+ str = g_date_time_format(start_of_next, "%F %T");
+ g_debug ("%s %s the next timestamp rebuild will be at %s", G_STRLOC, G_STRFUNC, str);
+ g_free (str);
+
+ diff = g_date_time_difference(start_of_next, now);
+ seconds = (diff + (G_TIME_SPAN_SECOND-1)) / G_TIME_SPAN_SECOND;
+
+ g_date_time_unref(start_of_next);
+ g_date_time_unref(next);
+
+ return seconds;
+}
+} // anonymous namespace
+
+
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+class Formatter::Impl
+{
+public:
+
+ Impl (Formatter* owner, const std::shared_ptr<Clock>& clock):
+ owner_(owner),
+ clock_(clock)
+ {
+ owner_->headerFormat.changed().connect([this](const std::string& fmt G_GNUC_UNUSED){updateHeader();});
+ updateHeader();
+
+ restartRelativeTimer();
+ }
+
+ ~Impl()
+ {
+ clearTimer(header_timer_);
+ }
+
+private:
+
+ void updateHeader()
+ {
+ GDateTime * now = clock_->localtime();
+ const time_t unix = g_date_time_to_unix (now);
+ struct tm tm;
+ localtime_r (&unix, &tm);
+ char str[512];
+ strftime (str, sizeof(str), owner_->headerFormat.get().c_str(), &tm);
+ owner_->header.set (str);
+ g_date_time_unref (now);
+
+ restartHeaderTimer();
+ }
+
+ void restartHeaderTimer()
+ {
+ clearTimer(header_timer_);
+
+ const std::string fmt = owner_->headerFormat.get();
+ const bool header_shows_seconds = (fmt.find("%s") != std::string::npos)
+ || (fmt.find("%S") != std::string::npos)
+ || (fmt.find("%T") != std::string::npos)
+ || (fmt.find("%X") != std::string::npos)
+ || (fmt.find("%c") != std::string::npos);
+
+ guint interval_msec;
+ GDateTime * now = clock_->localtime();
+ if (header_shows_seconds)
+ interval_msec = calculate_milliseconds_until_next_second (now);
+ else
+ interval_msec = calculate_milliseconds_until_next_minute (now);
+ g_date_time_unref (now);
+
+ interval_msec += 50; // add a small margin to ensure the callback
+ // fires /after/ next is reached
+
+ header_timer_ = g_timeout_add_full(G_PRIORITY_HIGH, interval_msec, onHeaderTimer, this, nullptr);
+ }
+
+ static gboolean onHeaderTimer(gpointer gself)
+ {
+ static_cast<Formatter::Impl*>(gself)->updateHeader();
+ return G_SOURCE_REMOVE;
+ }
+
+private:
+
+ void restartRelativeTimer()
+ {
+ clearTimer(relative_timer_);
+
+ GDateTime * now = clock_->localtime();
+ const guint seconds = calculate_seconds_until_next_fifteen_minutes(now);
+ relative_timer_ = g_timeout_add_seconds(seconds, onRelativeTimer, this);
+ g_date_time_unref(now);
+ }
+
+ static gboolean onRelativeTimer(gpointer gself)
+ {
+ auto self = static_cast<Formatter::Impl*>(gself);
+ self->owner_->relativeFormatChanged();
+ self->restartRelativeTimer();
+ return G_SOURCE_REMOVE;
+ }
+
+private:
+ Formatter * const owner_;
+ guint header_timer_ = 0;
+ guint relative_timer_ = 0;
+
+public:
+ std::shared_ptr<Clock> clock_;
+};
+
+/***
+****
+***/
+
+Formatter::Formatter(const std::shared_ptr<Clock>& clock):
+ p (new Formatter::Impl(this, clock))
+{
+}
+
+Formatter::~Formatter()
+{
+}
+
+bool
+Formatter::is_locale_12h()
+{
+ static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", nullptr};
+ const char *t_fmt = nl_langinfo (T_FMT);
+ int i;
+
+ for (i=0; formats_24h[i]; ++i)
+ if (strstr (t_fmt, formats_24h[i]))
+ return false;
+
+ return true;
+}
+
+const char *
+Formatter::T_(const char *msg)
+{
+ /* General strategy here is to make sure LANGUAGE is empty (since that
+ trumps all LC_* vars) and then to temporarily swap LC_TIME and
+ LC_MESSAGES. Then have gettext translate msg.
+
+ We strdup the strings because the setlocale & *env functions do not
+ guarantee anything about the storage used for the string, and thus
+ the string may not be portably safe after multiple calls.
+
+ Note that while you might think g_dcgettext would do the trick here,
+ that actually looks in /usr/share/locale/XX/LC_TIME, not the
+ LC_MESSAGES directory, so we won't find any translation there.
+ */
+
+ char *message_locale = g_strdup(setlocale(LC_MESSAGES, nullptr));
+ const char *time_locale = setlocale (LC_TIME, nullptr);
+ char *language = g_strdup(g_getenv("LANGUAGE"));
+ const char *rv;
+
+ if (language)
+ g_unsetenv("LANGUAGE");
+ setlocale(LC_MESSAGES, time_locale);
+
+ /* Get the LC_TIME version */
+ rv = _(msg);
+
+ /* Put everything back the way it was */
+ setlocale(LC_MESSAGES, message_locale);
+ if (language)
+ g_setenv("LANGUAGE", language, TRUE);
+
+ g_free(message_locale);
+ g_free(language);
+ return rv;
+}
+
+const char *
+Formatter::getDefaultHeaderTimeFormat(bool twelvehour, bool show_seconds)
+{
+ const char * fmt;
+
+ if (twelvehour && show_seconds)
+ /* TRANSLATORS: a strftime(3) format for 12hr time w/seconds */
+ fmt = T_("%l:%M:%S %p");
+ else if (twelvehour)
+ /* TRANSLATORS: a strftime(3) format for 12hr time */
+ fmt = T_("%l:%M %p");
+ else if (show_seconds)
+ /* TRANSLATORS: a strftime(3) format for 24hr time w/seconds */
+ fmt = T_("%H:%M:%S");
+ else
+ /* TRANSLATORS: a strftime(3) format for 24hr time */
+ fmt = T_("%H:%M");
+
+ return fmt;
+}
+
+/***
+****
+***/
+
+namespace
+{
+typedef enum
+{
+ DATE_PROXIMITY_TODAY,
+ DATE_PROXIMITY_TOMORROW,
+ DATE_PROXIMITY_WEEK,
+ DATE_PROXIMITY_FAR
+}
+date_proximity_t;
+
+date_proximity_t getDateProximity (GDateTime * now, GDateTime * time)
+{
+ date_proximity_t prox = DATE_PROXIMITY_FAR;
+ gint now_year, now_month, now_day;
+ gint time_year, time_month, time_day;
+
+ // does it happen today?
+ g_date_time_get_ymd (now, &now_year, &now_month, &now_day);
+ g_date_time_get_ymd (time, &time_year, &time_month, &time_day);
+ if ((now_year == time_year) && (now_month == time_month) && (now_day == time_day))
+ prox = DATE_PROXIMITY_TODAY;
+
+ // does it happen tomorrow?
+ if (prox == DATE_PROXIMITY_FAR)
+ {
+ GDateTime * tomorrow;
+ gint tom_year, tom_month, tom_day;
+
+ tomorrow = g_date_time_add_days (now, 1);
+ g_date_time_get_ymd (tomorrow, &tom_year, &tom_month, &tom_day);
+ if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day))
+ prox = DATE_PROXIMITY_TOMORROW;
+
+ g_date_time_unref (tomorrow);
+ }
+
+ // does it happen this week?
+ if (prox == DATE_PROXIMITY_FAR)
+ {
+ GDateTime * week;
+ GDateTime * week_bound;
+
+ week = g_date_time_add_days (now, 6);
+ week_bound = g_date_time_new_local (g_date_time_get_year(week),
+ g_date_time_get_month (week),
+ g_date_time_get_day_of_month(week),
+ 23, 59, 59.9);
+
+ if (g_date_time_compare (time, week_bound) <= 0)
+ prox = DATE_PROXIMITY_WEEK;
+
+ g_date_time_unref (week_bound);
+ g_date_time_unref (week);
+ }
+
+ return prox;
+}
+} // anonymous namespace
+
+/**
+ * _ a time today should be shown as just the time (e.g. “3:55 PM”)
+ * _ a full-day event today should be shown as “Today”
+ * _ a time any other day this week should be shown as the short version of the
+ * day and time (e.g. “Wed 3:55 PM”)
+ * _ a full-day event tomorrow should be shown as “Tomorrow”
+ * _ a full-day event another day this week should be shown as the
+ * weekday (e.g. “Friday”)
+ * _ a time after this week should be shown as the short version of the day,
+ * date, and time (e.g. “Wed 21 Apr 3:55 PM”)
+ * _ a full-day event after this week should be shown as the short version of
+ * the day and date (e.g. “Wed 21 Apr”).
+ * _ in addition, when presenting the times of upcoming events, the time should
+ * be followed by the timezone if it is different from the one the computer
+ * is currently set to. For example, “Wed 3:55 PM UTC−5”.
+ */
+std::string
+Formatter::getRelativeFormat(GDateTime* then, GDateTime* then_end) const
+{
+ std::string ret;
+ GDateTime * now = p->clock_->localtime();
+
+ if (then != nullptr)
+ {
+ const bool full_day = then_end && (g_date_time_difference (then_end, then) >= G_TIME_SPAN_DAY);
+ const auto prox = getDateProximity (now, then);
+
+ if (full_day)
+ {
+ switch (prox)
+ {
+ case DATE_PROXIMITY_TODAY: ret = _("Today"); break;
+ case DATE_PROXIMITY_TOMORROW: ret = _("Tomorrow"); break;
+ case DATE_PROXIMITY_WEEK: ret = T_("%A"); break;
+ case DATE_PROXIMITY_FAR: ret = T_("%a %d %b"); break;
+ }
+ }
+ else if (is_locale_12h())
+ {
+ switch (prox)
+ {
+ case DATE_PROXIMITY_TODAY: ret = T_("%l:%M %p"); break;
+ case DATE_PROXIMITY_TOMORROW: ret = T_("Tomorrow\u2003%l:%M %p"); break;
+ case DATE_PROXIMITY_WEEK: ret = T_("%a\u2003%l:%M %p"); break;
+ case DATE_PROXIMITY_FAR: ret = T_("%a %d %b\u2003%l:%M %p"); break;
+ }
+ }
+ else
+ {
+ switch (prox)
+ {
+ case DATE_PROXIMITY_TODAY: ret = T_("%H:%M"); break;
+ case DATE_PROXIMITY_TOMORROW: ret = T_("Tomorrow\u2003%H:%M"); break;
+ case DATE_PROXIMITY_WEEK: ret = T_("%a\u2003%H:%M"); break;
+ case DATE_PROXIMITY_FAR: ret = T_("%a %d %b\u2003%H:%M"); break;
+ }
+ }
+
+ /* if it's an appointment in a different timezone (and doesn't run for a full day)
+ then the time should be followed by its timezone. */
+ if ((then_end != nullptr) &&
+ (!full_day) &&
+ ((g_date_time_get_utc_offset (now) != g_date_time_get_utc_offset (then))))
+ {
+ ret += ' ';
+ ret += g_date_time_get_timezone_abbreviation (then);
+ }
+ }
+
+ g_date_time_unref (now);
+ return ret;
+}
+
+/***
+****
+***/
+
+} // namespace datetime
+
+} // namespace indicator
+
+} // namespace unity
diff --git a/src/planner-eds.c b/src/planner-eds.c
deleted file mode 100644
index cc2b8c5..0000000
--- a/src/planner-eds.c
+++ /dev/null
@@ -1,653 +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/>.
- */
-
-#include <libical/ical.h>
-#include <libical/icaltime.h>
-#include <libecal/libecal.h>
-#include <libedataserver/libedataserver.h>
-
-#include "planner-eds.h"
-
-struct _IndicatorDatetimePlannerEdsPriv
-{
- GSList * sources;
- GCancellable * cancellable;
- ESourceRegistry * source_registry;
-};
-
-typedef IndicatorDatetimePlannerEdsPriv priv_t;
-
-G_DEFINE_TYPE (IndicatorDatetimePlannerEds,
- indicator_datetime_planner_eds,
- INDICATOR_TYPE_DATETIME_PLANNER)
-
-G_DEFINE_QUARK ("source-client", source_client)
-
-/***
-****
-**** my_get_appointments() helpers
-****
-***/
-
-/* whole-task data that all the subtasks can see */
-struct appointment_task_data
-{
- /* a ref to the planner's cancellable */
- GCancellable * cancellable;
-
- /* how many subtasks are still running on */
- int subtask_count;
-
- /* the list of appointments to be returned */
- GSList * appointments;
-};
-
-static struct appointment_task_data *
-appointment_task_data_new (GCancellable * cancellable)
-{
- struct appointment_task_data * data;
-
- data = g_slice_new0 (struct appointment_task_data);
- data->cancellable = g_object_ref (cancellable);
- return data;
-}
-
-static void
-appointment_task_data_free (gpointer gdata)
-{
- struct appointment_task_data * data = gdata;
-
- g_object_unref (data->cancellable);
-
- g_slice_free (struct appointment_task_data, data);
-}
-
-static void
-appointment_task_done (GTask * task)
-{
- struct appointment_task_data * data = g_task_get_task_data (task);
-
- g_task_return_pointer (task, data->appointments, NULL);
- g_object_unref (task);
-}
-
-static void
-appointment_task_decrement_subtasks (GTask * task)
-{
- struct appointment_task_data * data = g_task_get_task_data (task);
-
- if (g_atomic_int_dec_and_test (&data->subtask_count))
- appointment_task_done (task);
-}
-
-static void
-appointment_task_increment_subtasks (GTask * task)
-{
- struct appointment_task_data * data = g_task_get_task_data (task);
-
- g_atomic_int_inc (&data->subtask_count);
-}
-
-/**
-*** get-the-appointment's-uri subtasks
-**/
-
-struct appointment_uri_subtask_data
-{
- /* The parent task */
- GTask * task;
-
- /* The appointment whose uri we're looking for.
- This pointer is owned by the Task and isn't reffed/unreffed by the subtask */
- struct IndicatorDatetimeAppt * appt;
-};
-
-static void
-appointment_uri_subtask_done (struct appointment_uri_subtask_data * subdata)
-{
- GTask * task = subdata->task;
-
- /* free the subtask data */
- g_slice_free (struct appointment_uri_subtask_data, subdata);
-
- appointment_task_decrement_subtasks (task);
-}
-
-static struct appointment_uri_subtask_data *
-appointment_uri_subtask_data_new (GTask * task, struct IndicatorDatetimeAppt * appt)
-{
- struct appointment_uri_subtask_data * subdata;
-
- appointment_task_increment_subtasks (task);
-
- subdata = g_slice_new0 (struct appointment_uri_subtask_data);
- subdata->task = task;
- subdata->appt = appt;
- return subdata;
-}
-
-static void
-on_appointment_uris_ready (GObject * client,
- GAsyncResult * res,
- gpointer gsubdata)
-{
- GSList * uris;
- GError * error;
- struct appointment_uri_subtask_data * subdata = gsubdata;
-
- uris = NULL;
- error = NULL;
- e_cal_client_get_attachment_uris_finish (E_CAL_CLIENT(client), res, &uris, &error);
- if (error != NULL)
- {
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("Error getting appointment uris: %s", error->message);
-
- g_error_free (error);
- }
- else if (uris != NULL)
- {
- struct IndicatorDatetimeAppt * appt = subdata->appt;
- appt->url = g_strdup (uris->data); /* copy the first URL */
- g_debug ("found url '%s' for appointment '%s'", appt->url, appt->summary);
- e_client_util_free_string_slist (uris);
- }
-
- appointment_uri_subtask_done (subdata);
-}
-
-/**
-*** enumerate-the-components subtasks
-**/
-
-/* data struct for the enumerate-components subtask */
-struct appointment_component_subtask_data
-{
- /* The parent task */
- GTask * task;
-
- /* The client we're walking through. The subtask owns a ref to this */
- ECalClient * client;
-
- /* The appointment's color coding. The subtask owns this string */
- gchar * color;
-};
-
-static void
-on_appointment_component_subtask_done (gpointer gsubdata)
-{
- struct appointment_component_subtask_data * subdata = gsubdata;
- GTask * task = subdata->task;
-
- /* free the subtask data */
- g_free (subdata->color);
- g_object_unref (subdata->client);
- g_slice_free (struct appointment_component_subtask_data, subdata);
-
- appointment_task_decrement_subtasks (task);
-}
-
-static struct appointment_component_subtask_data *
-appointment_component_subtask_data_new (GTask * task, ECalClient * client, const gchar * color)
-{
- struct appointment_component_subtask_data * subdata;
-
- appointment_task_increment_subtasks (task);
-
- subdata = g_slice_new0 (struct appointment_component_subtask_data);
- subdata->task = task;
- subdata->client = g_object_ref (client);
- subdata->color = g_strdup (color);
- return subdata;
-}
-
-static gboolean
-my_get_appointments_foreach (ECalComponent * component,
- time_t begin,
- time_t end,
- gpointer gsubdata)
-{
- const ECalComponentVType vtype = e_cal_component_get_vtype (component);
- struct appointment_component_subtask_data * subdata = gsubdata;
- struct appointment_task_data * data = g_task_get_task_data (subdata->task);
-
- if ((vtype == E_CAL_COMPONENT_EVENT) || (vtype == E_CAL_COMPONENT_TODO))
- {
- const gchar * uid = NULL;
- icalproperty_status status = 0;
-
- e_cal_component_get_uid (component, &uid);
- e_cal_component_get_status (component, &status);
-
- if ((uid != NULL) &&
- (status != ICAL_STATUS_COMPLETED) &&
- (status != ICAL_STATUS_CANCELLED))
- {
- GList * alarm_uids;
- GSList * l;
- GSList * recur_list;
- ECalComponentText text;
- struct IndicatorDatetimeAppt * appt;
- struct appointment_uri_subtask_data * uri_subdata;
-
- appt = g_slice_new0 (struct IndicatorDatetimeAppt);
-
- /* Determine whether this is a recurring event.
- NB: icalrecurrencetype supports complex recurrence patterns;
- however, since design only allows daily recurrence,
- that's all we support here. */
- e_cal_component_get_rrule_list (component, &recur_list);
- for (l=recur_list; l!=NULL; l=l->next)
- {
- const struct icalrecurrencetype * recur = l->data;
- appt->is_daily |= ((recur->freq == ICAL_DAILY_RECURRENCE)
- && (recur->interval == 1));
- }
- e_cal_component_free_recur_list (recur_list);
-
- 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 = g_strdup (subdata->color);
- appt->is_event = vtype == E_CAL_COMPONENT_EVENT;
- appt->summary = g_strdup (text.value);
- appt->uid = g_strdup (uid);
-
- alarm_uids = e_cal_component_get_alarm_uids (component);
- appt->has_alarms = alarm_uids != NULL;
- cal_obj_uid_list_free (alarm_uids);
-
- data->appointments = g_slist_prepend (data->appointments, appt);
-
- /* start a new subtask to get the associated URIs */
- uri_subdata = appointment_uri_subtask_data_new (subdata->task, appt);
- e_cal_client_get_attachment_uris (subdata->client,
- uid,
- NULL,
- data->cancellable,
- on_appointment_uris_ready,
- uri_subdata);
- }
- }
-
- return G_SOURCE_CONTINUE;
-}
-
-/***
-**** IndicatorDatetimePlanner virtual funcs
-***/
-
-static void
-my_get_appointments (IndicatorDatetimePlanner * planner,
- GDateTime * begin_datetime,
- GDateTime * end_datetime,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GSList * l;
- priv_t * p;
- const char * str;
- icaltimezone * default_timezone;
- const int64_t begin = g_date_time_to_unix (begin_datetime);
- const int64_t end = g_date_time_to_unix (end_datetime);
- GTask * task;
- gboolean subtasks_added;
-
- 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
- **/
-
- task = g_task_new (planner, p->cancellable, callback, user_data);
- g_task_set_task_data (task,
- appointment_task_data_new (p->cancellable),
- appointment_task_data_free);
-
- subtasks_added = FALSE;
- for (l=p->sources; l!=NULL; l=l->next)
- {
- ESource * source;
- ECalClient * client;
- const char * color;
- struct appointment_component_subtask_data * subdata;
-
- source = l->data;
- client = g_object_get_qdata (l->data, source_client_quark());
- if (client == NULL)
- continue;
-
- if (default_timezone != NULL)
- e_cal_client_set_default_timezone (client, default_timezone);
-
- /* start a new subtask to enumerate all the components in this client. */
- color = e_source_selectable_get_color (e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR));
- subdata = appointment_component_subtask_data_new (task, client, color);
- subtasks_added = TRUE;
- e_cal_client_generate_instances (client,
- begin,
- end,
- p->cancellable,
- my_get_appointments_foreach,
- subdata,
- on_appointment_component_subtask_done);
- }
-
- if (!subtasks_added)
- appointment_task_done (task);
-}
-
-static GSList *
-my_get_appointments_finish (IndicatorDatetimePlanner * self G_GNUC_UNUSED,
- GAsyncResult * res,
- GError ** error)
-{
- return g_task_propagate_pointer (G_TASK(res), error);
-}
-
-static gboolean
-my_is_configured (IndicatorDatetimePlanner * planner)
-{
- 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);
- return self->priv->sources != NULL;
-}
-
-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 * err;
-
- isodate = g_date_time_format (activate_time, "%Y%m%d");
- command = g_strdup_printf ("evolution \"calendar:///?startdate=%s\"", isodate);
- err = 0;
- if (!g_spawn_command_line_async (command, &err))
- {
- g_warning ("Unable to start %s: %s", command, err->message);
- g_error_free (err);
- }
-
- g_free (command);
- g_free (isodate);
-}
-
-/***
-**** Source / Client Wrangling
-***/
-
-static void
-on_client_connected (GObject * unused G_GNUC_UNUSED,
- GAsyncResult * res,
- gpointer gself)
-{
- GError * error;
- EClient * client;
-
- error = NULL;
- client = e_cal_client_connect_finish (res, &error);
- if (error != NULL)
- {
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("indicator-datetime cannot connect to EDS source: %s", error->message);
-
- g_error_free (error);
- }
- else
- {
- /* we've got a new connected ECalClient, so store it & notify clients */
-
- g_object_set_qdata_full (G_OBJECT(e_client_get_source(client)),
- source_client_quark(),
- client,
- g_object_unref);
-
- indicator_datetime_planner_emit_appointments_changed (gself);
- }
-}
-
-static void
-on_source_enabled (ESourceRegistry * registry G_GNUC_UNUSED,
- ESource * source,
- gpointer gself)
-{
- IndicatorDatetimePlannerEds * self = INDICATOR_DATETIME_PLANNER_EDS (gself);
- priv_t * p = self->priv;
-
- e_cal_client_connect (source,
- E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
- p->cancellable,
- on_client_connected,
- self);
-}
-
-static void
-on_source_added (ESourceRegistry * registry,
- ESource * source,
- gpointer gself)
-{
- IndicatorDatetimePlannerEds * self = INDICATOR_DATETIME_PLANNER_EDS (gself);
- priv_t * p = self->priv;
-
- p->sources = g_slist_prepend (p->sources, g_object_ref(source));
-
- if (e_source_get_enabled (source))
- on_source_enabled (registry, source, gself);
-}
-
-static void
-on_source_disabled (ESourceRegistry * registry G_GNUC_UNUSED,
- ESource * source,
- gpointer gself)
-{
- ECalClient * client;
-
- /* If this source has a connected ECalClient, remove it & notify clients */
- if ((client = g_object_steal_qdata (G_OBJECT(source), source_client_quark())))
- {
- g_object_unref (client);
- indicator_datetime_planner_emit_appointments_changed (gself);
- }
-}
-
-static void
-on_source_removed (ESourceRegistry * registry,
- ESource * source,
- gpointer gself)
-{
- IndicatorDatetimePlannerEds * self = INDICATOR_DATETIME_PLANNER_EDS (gself);
- priv_t * p = self->priv;
-
- on_source_disabled (registry, source, gself);
-
- p->sources = g_slist_remove (p->sources, source);
- g_object_unref (source);
-}
-
-static void
-on_source_changed (ESourceRegistry * registry G_GNUC_UNUSED,
- ESource * source G_GNUC_UNUSED,
- gpointer gself)
-{
- indicator_datetime_planner_emit_appointments_changed (gself);
-}
-
-static void
-on_source_registry_ready (GObject * source_object G_GNUC_UNUSED,
- GAsyncResult * res,
- gpointer gself)
-{
- GError * error;
- ESourceRegistry * r;
-
- error = NULL;
- r = e_source_registry_new_finish (res, &error);
- if (error != NULL)
- {
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("indicator-datetime cannot show EDS appointments: %s", error->message);
-
- g_error_free (error);
- }
- else
- {
- IndicatorDatetimePlannerEds * self;
- priv_t * p;
- GList * l;
- GList * sources;
-
- self = INDICATOR_DATETIME_PLANNER_EDS (gself);
- p = self->priv;
-
- g_signal_connect (r, "source-added", G_CALLBACK(on_source_added), self);
- g_signal_connect (r, "source-removed", G_CALLBACK(on_source_removed), self);
- g_signal_connect (r, "source-changed", G_CALLBACK(on_source_changed), self);
- g_signal_connect (r, "source-disabled", G_CALLBACK(on_source_disabled), self);
- g_signal_connect (r, "source-enabled", G_CALLBACK(on_source_enabled), self);
-
- p->source_registry = r;
-
- sources = e_source_registry_list_sources (r, E_SOURCE_EXTENSION_CALENDAR);
- for (l=sources; l!=NULL; l=l->next)
- on_source_added (r, l->data, self);
- g_list_free_full (sources, g_object_unref);
- }
-}
-
-/***
-**** GObject virtual funcs
-***/
-
-static void
-my_dispose (GObject * o)
-{
- IndicatorDatetimePlannerEds * self = INDICATOR_DATETIME_PLANNER_EDS (o);
- priv_t * p = self->priv;
-
- if (p->cancellable != NULL)
- {
- g_cancellable_cancel (p->cancellable);
- g_clear_object (&p->cancellable);
- }
-
- 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);
-}
-
-/***
-**** Instantiation
-***/
-
-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;
- planner_class->get_appointments_finish = my_get_appointments_finish;
-
- g_type_class_add_private (klass, sizeof (IndicatorDatetimePlannerEdsPriv));
-}
-
-static void
-indicator_datetime_planner_eds_init (IndicatorDatetimePlannerEds * self)
-{
- priv_t * p;
-
- p = G_TYPE_INSTANCE_GET_PRIVATE (self,
- INDICATOR_TYPE_DATETIME_PLANNER_EDS,
- IndicatorDatetimePlannerEdsPriv);
-
- self->priv = p;
-
- p->cancellable = g_cancellable_new ();
-
- e_source_registry_new (p->cancellable,
- on_source_registry_ready,
- 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.c b/src/planner.c
deleted file mode 100644
index 9b9a77f..0000000
--- a/src/planner.c
+++ /dev/null
@@ -1,281 +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/>.
- */
-
-#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)->finalize (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);
-}
-
-void
-indicator_datetime_planner_get_appointments (IndicatorDatetimePlanner * self,
- GDateTime * begin,
- GDateTime * end,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- IndicatorDatetimePlannerClass * klass;
-
- g_return_if_fail (INDICATOR_IS_DATETIME_PLANNER (self));
- g_return_val_if_fail (begin != NULL, NULL);
- g_return_val_if_fail (end != NULL, NULL);
-
- klass = INDICATOR_DATETIME_PLANNER_GET_CLASS (self);
- g_return_if_fail (klass->get_appointments != NULL);
- klass->get_appointments (self, begin, end, callback, user_data);
-}
-
-GSList *
-indicator_datetime_planner_get_appointments_finish (IndicatorDatetimePlanner * self,
- GAsyncResult * res,
- GError ** error)
-{
- IndicatorDatetimePlannerClass * klass;
- GSList * appointments;
-
- g_return_val_if_fail (INDICATOR_IS_DATETIME_PLANNER (self), NULL);
-
- klass = INDICATOR_DATETIME_PLANNER_GET_CLASS (self);
- g_return_val_if_fail (klass->get_appointments_finish != NULL, NULL);
- appointments = klass->get_appointments_finish (self, res, error);
- return g_slist_sort (appointments, compare_appointments_by_start_time);
-}
-
-void
-indicator_datetime_planner_free_appointments (GSList * l)
-{
- g_slist_free_full (l, (GDestroyNotify)indicator_datetime_appt_free);
-}
-
-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;
-}
-
-/***
-****
-***/
-
-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->url);
- g_free (appt->uid);
- g_slice_free (struct IndicatorDatetimeAppt, appt);
- }
-}
-
diff --git a/src/service.h b/src/service.h
deleted file mode 100644
index d38db72..0000000
--- a/src/service.h
+++ /dev/null
@@ -1,84 +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_SERVICE_H__
-#define __INDICATOR_DATETIME_SERVICE_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "clock.h"
-#include "planner.h"
-
-G_BEGIN_DECLS
-
-/* standard GObject macros */
-#define INDICATOR_DATETIME_SERVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_DATETIME_SERVICE, IndicatorDatetimeService))
-#define INDICATOR_TYPE_DATETIME_SERVICE (indicator_datetime_service_get_type())
-#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 (IndicatorDatetimeClock * clock,
- IndicatorDatetimePlanner * planner);
-
-void indicator_datetime_service_set_calendar_date (IndicatorDatetimeService * self,
- GDateTime * date);
-
-void indicator_datetime_service_set_planner (IndicatorDatetimeService * self,
- IndicatorDatetimePlanner * planner);
-
-
-void indicator_datetime_service_set_clock (IndicatorDatetimeService * self,
- IndicatorDatetimeClock * clock);
-
-
-G_END_DECLS
-
-#endif /* __INDICATOR_DATETIME_SERVICE_H__ */
diff --git a/src/settings-shared.h b/src/settings-shared.h
deleted file mode 100644
index 4615fe8..0000000
--- a/src/settings-shared.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-An indicator to show date and time information.
-
-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
-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 __DATETIME_SETTINGS_SHARED_H__
-#define __DATETIME_SETTINGS_SHARED_H__
-
-typedef enum
-{
- TIME_FORMAT_MODE_LOCALE_DEFAULT,
- TIME_FORMAT_MODE_12_HOUR,
- TIME_FORMAT_MODE_24_HOUR,
- TIME_FORMAT_MODE_CUSTOM
-}
-TimeFormatMode;
-
-#define SETTINGS_INTERFACE "com.canonical.indicator.datetime"
-#define SETTINGS_SHOW_CLOCK_S "show-clock"
-#define SETTINGS_TIME_FORMAT_S "time-format"
-#define SETTINGS_SHOW_SECONDS_S "show-seconds"
-#define SETTINGS_SHOW_DAY_S "show-day"
-#define SETTINGS_SHOW_DATE_S "show-date"
-#define SETTINGS_SHOW_YEAR_S "show-year"
-#define SETTINGS_CUSTOM_TIME_FORMAT_S "custom-time-format"
-#define SETTINGS_SHOW_CALENDAR_S "show-calendar"
-#define SETTINGS_SHOW_WEEK_NUMBERS_S "show-week-numbers"
-#define SETTINGS_SHOW_EVENTS_S "show-events"
-#define SETTINGS_SHOW_LOCATIONS_S "show-locations"
-#define SETTINGS_SHOW_DETECTED_S "show-auto-detected-location"
-#define SETTINGS_LOCATIONS_S "locations"
-#define SETTINGS_TIMEZONE_NAME_S "timezone-name"
-
-#endif
diff --git a/src/timezone-file.c b/src/timezone-file.c
deleted file mode 100644
index ddc4256..0000000
--- a/src/timezone-file.c
+++ /dev/null
@@ -1,212 +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/>.
- */
-
-#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;
- GFileMonitor * monitor;
-};
-
-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 * timezone = NULL;
-
- if (!g_file_get_contents (p->filename, &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 (timezone);
- indicator_datetime_timezone_set_timezone (INDICATOR_DATETIME_TIMEZONE(self), timezone);
- g_free (timezone);
- }
-}
-
-static void
-set_filename (IndicatorDatetimeTimezoneFile * self, const char * filename)
-{
- GError * err;
- GFile * file;
- priv_t * p = self->priv;
-
- g_clear_object (&p->monitor);
- g_free (p->filename);
-
- p->filename = g_strdup (filename);
- err = NULL;
- file = g_file_new_for_path (p->filename);
- p->monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &err);
- g_object_unref (file);
- 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);
-}
-
-/***
-**** 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_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_OBJECT_CLASS (indicator_datetime_timezone_file_parent_class)->finalize (o);
-}
-
-/***
-****
-***/
-
-static void
-indicator_datetime_timezone_file_class_init (IndicatorDatetimeTimezoneFileClass * klass)
-{
- GObjectClass * object_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;
-
- 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
deleted file mode 100644
index b02abe1..0000000
--- a/src/timezone-file.h
+++ /dev/null
@@ -1,58 +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_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/timezone-geoclue.c b/src/timezone-geoclue.c
deleted file mode 100644
index ac23b93..0000000
--- a/src/timezone-geoclue.c
+++ /dev/null
@@ -1,227 +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/>.
- */
-
-#include <geoclue/geoclue-master.h>
-#include <geoclue/geoclue-master-client.h>
-
-#include "timezone-geoclue.h"
-
-struct _IndicatorDatetimeTimezoneGeocluePriv
-{
- GeoclueMaster * master;
- GeoclueMasterClient * client;
- GeoclueAddress * address;
-};
-
-typedef IndicatorDatetimeTimezoneGeocluePriv priv_t;
-
-G_DEFINE_TYPE (IndicatorDatetimeTimezoneGeoclue,
- indicator_datetime_timezone_geoclue,
- INDICATOR_TYPE_DATETIME_TIMEZONE)
-
-static void geo_restart (IndicatorDatetimeTimezoneGeoclue * self);
-
-/***
-****
-***/
-
-static void
-on_address_changed (GeoclueAddress * address G_GNUC_UNUSED,
- int timestamp G_GNUC_UNUSED,
- GHashTable * addy_data,
- GeoclueAccuracy * accuracy G_GNUC_UNUSED,
- GError * error,
- gpointer gself)
-{
- if (error != NULL)
- {
- g_warning ("%s Unable to get timezone from GeoClue: %s", G_STRFUNC, error->message);
- }
- else
- {
- IndicatorDatetimeTimezoneGeoclue * self = INDICATOR_DATETIME_TIMEZONE_GEOCLUE (gself);
- const char * timezone = g_hash_table_lookup (addy_data, "timezone");
- indicator_datetime_timezone_set_timezone (INDICATOR_DATETIME_TIMEZONE(self), timezone);
- }
-}
-
-/* The signal doesn't have the parameter for an error, so it ends up needing
- a NULL inserted. */
-static void
-on_address_changed_sig (GeoclueAddress * address G_GNUC_UNUSED,
- int timestamp G_GNUC_UNUSED,
- GHashTable * addy_data,
- GeoclueAccuracy * accuracy G_GNUC_UNUSED,
- gpointer gself)
-{
- on_address_changed(address, timestamp, addy_data, accuracy, NULL, gself);
-}
-
-static void
-on_address_created (GeoclueMasterClient * master G_GNUC_UNUSED,
- GeoclueAddress * address,
- GError * error,
- gpointer gself)
-{
- if (error != NULL)
- {
- g_warning ("%s Unable to get timezone from GeoClue: %s", G_STRFUNC, error->message);
- }
- else
- {
- priv_t * p = INDICATOR_DATETIME_TIMEZONE_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_sig), gself);
- }
-}
-
-static void
-on_requirements_set (GeoclueMasterClient * master G_GNUC_UNUSED,
- GError * error,
- gpointer user_data G_GNUC_UNUSED)
-{
- if (error != NULL)
- {
- g_warning ("%s Unable to get timezone from GeoClue: %s", G_STRFUNC, error->message);
- }
-}
-
-static void
-on_client_created (GeoclueMaster * master G_GNUC_UNUSED,
- 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);
- }
- else
- {
- IndicatorDatetimeTimezoneGeoclue * self = INDICATOR_DATETIME_TIMEZONE_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 (IndicatorDatetimeTimezoneGeoclue * 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 (IndicatorDatetimeTimezoneGeoclue * self)
-{
- priv_t * p = self->priv;
-
- if (p->address != NULL)
- {
- g_signal_handlers_disconnect_by_func (p->address, on_address_changed_sig, 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 (IndicatorDatetimeTimezoneGeoclue * self)
-{
- geo_stop (self);
- geo_start (self);
-}
-
-/***
-****
-***/
-
-static void
-my_dispose (GObject * o)
-{
- geo_stop (INDICATOR_DATETIME_TIMEZONE_GEOCLUE (o));
-
- G_OBJECT_CLASS (indicator_datetime_timezone_geoclue_parent_class)->dispose (o);
-}
-
-static void
-indicator_datetime_timezone_geoclue_class_init (IndicatorDatetimeTimezoneGeoclueClass * klass)
-{
- GObjectClass * object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = my_dispose;
-
- g_type_class_add_private (klass, sizeof (IndicatorDatetimeTimezoneGeocluePriv));
-}
-
-static void
-indicator_datetime_timezone_geoclue_init (IndicatorDatetimeTimezoneGeoclue * self)
-{
- priv_t * p;
-
- p = G_TYPE_INSTANCE_GET_PRIVATE (self,
- INDICATOR_TYPE_DATETIME_TIMEZONE_GEOCLUE,
- IndicatorDatetimeTimezoneGeocluePriv);
-
- self->priv = p;
-
- geo_start (self);
-}
-
-/***
-**** Public
-***/
-
-IndicatorDatetimeTimezone *
-indicator_datetime_timezone_geoclue_new (void)
-{
- gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_TIMEZONE_GEOCLUE, NULL);
-
- return INDICATOR_DATETIME_TIMEZONE (o);
-}
diff --git a/src/timezone-geoclue.h b/src/timezone-geoclue.h
deleted file mode 100644
index 059bd81..0000000
--- a/src/timezone-geoclue.h
+++ /dev/null
@@ -1,57 +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_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/timezone.c b/src/timezone.c
deleted file mode 100644
index 4f8addc..0000000
--- a/src/timezone.c
+++ /dev/null
@@ -1,134 +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/>.
- */
-
-#include "timezone.h"
-
-G_DEFINE_TYPE (IndicatorDatetimeTimezone,
- indicator_datetime_timezone,
- G_TYPE_OBJECT)
-
-enum
-{
- PROP_0,
- PROP_TIMEZONE,
- PROP_LAST
-};
-
-static GParamSpec * properties[PROP_LAST] = { 0, };
-
-struct _IndicatorDatetimeTimezonePriv
-{
- GString * timezone;
-};
-
-typedef struct _IndicatorDatetimeTimezonePriv priv_t;
-
-static void
-my_get_property (GObject * o,
- guint property_id,
- GValue * value,
- GParamSpec * pspec)
-{
- IndicatorDatetimeTimezone * self = INDICATOR_DATETIME_TIMEZONE (o);
-
- switch (property_id)
- {
- case PROP_TIMEZONE:
- g_value_set_string (value, indicator_datetime_timezone_get_timezone (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec);
- }
-}
-
-static void
-my_finalize (GObject * o)
-{
- priv_t * p = INDICATOR_DATETIME_TIMEZONE(o)->priv;
-
- g_string_free (p->timezone, TRUE);
-
- G_OBJECT_CLASS (indicator_datetime_timezone_parent_class)->finalize (o);
-}
-
-static void
-/* cppcheck-suppress unusedFunction */
-indicator_datetime_timezone_class_init (IndicatorDatetimeTimezoneClass * klass)
-{
- GObjectClass * object_class;
- const GParamFlags flags = G_PARAM_READABLE | G_PARAM_STATIC_STRINGS;
-
- g_type_class_add_private (klass, sizeof (IndicatorDatetimeTimezonePriv));
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->get_property = my_get_property;
- object_class->finalize = my_finalize;
-
- 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_timezone_init (IndicatorDatetimeTimezone * self)
-{
- priv_t * p;
-
- p = G_TYPE_INSTANCE_GET_PRIVATE (self,
- INDICATOR_TYPE_DATETIME_TIMEZONE,
- IndicatorDatetimeTimezonePriv);
-
- p->timezone = g_string_new (NULL);
-
- self->priv = p;
-}
-
-/***
-****
-***/
-
-const char *
-indicator_datetime_timezone_get_timezone (IndicatorDatetimeTimezone * self)
-{
- g_return_val_if_fail (INDICATOR_IS_DATETIME_TIMEZONE (self), NULL);
-
- return self->priv->timezone->str;
-}
-
-void
-indicator_datetime_timezone_set_timezone (IndicatorDatetimeTimezone * self,
- const char * timezone)
-{
- priv_t * p = self->priv;
-
- if (g_strcmp0 (p->timezone->str, timezone))
- {
- if (timezone != NULL)
- g_string_assign (p->timezone, timezone);
- else
- g_string_set_size (p->timezone, 0);
- g_debug ("%s new timezone set: '%s'", G_STRLOC, p->timezone->str);
- g_object_notify_by_pspec (G_OBJECT(self), properties[PROP_TIMEZONE]);
- }
-}
diff --git a/src/timezone.h b/src/timezone.h
deleted file mode 100644
index fa6593d..0000000
--- a/src/timezone.h
+++ /dev/null
@@ -1,72 +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_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 _IndicatorDatetimeTimezonePriv IndicatorDatetimeTimezonePriv;
-typedef struct _IndicatorDatetimeTimezoneClass IndicatorDatetimeTimezoneClass;
-
-GType indicator_datetime_timezone_get_type (void);
-
-/**
- * Abstract Base Class for objects that provide a timezone.
- *
- * We use this in datetime to determine the user's current timezone
- * for display in the 'locations' section of the datetime indicator.
- *
- * This class has a 'timezone' property that clients can watch
- * for change notifications.
- */
-struct _IndicatorDatetimeTimezone
-{
- /*< private >*/
- GObject parent;
- IndicatorDatetimeTimezonePriv * priv;
-};
-
-struct _IndicatorDatetimeTimezoneClass
-{
- GObjectClass parent_class;
-};
-
-/***
-****
-***/
-
-const char * indicator_datetime_timezone_get_timezone (IndicatorDatetimeTimezone *);
-
-void indicator_datetime_timezone_set_timezone (IndicatorDatetimeTimezone *,
- const char * new_timezone);
-
-G_END_DECLS
-
-#endif /* __INDICATOR_DATETIME_TIMEZONE__H__ */
diff --git a/src/timezones-live.cpp b/src/timezones-live.cpp
new file mode 100644
index 0000000..cb5e2bc
--- /dev/null
+++ b/src/timezones-live.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * 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/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include <datetime/timezones-live.h>
+#include <glib.h>
+
+namespace unity {
+namespace indicator {
+namespace datetime {
+
+LiveTimezones::LiveTimezones (const std::string& filename):
+ file_ (filename)
+{
+ file_.timezone.changed().connect([this](const std::string&){updateTimezones();});
+
+ geolocationEnabled.changed().connect([this](bool){updateGeolocation();});
+ updateGeolocation();
+
+ updateTimezones();
+}
+
+void
+LiveTimezones::updateGeolocation()
+{
+ geo_.reset();
+
+ if (geolocationEnabled.get())
+ {
+ GeoclueTimezone * geo = new GeoclueTimezone();
+ geo->timezone.changed().connect([this](const std::string&){updateTimezones();});
+ geo_.reset(geo);
+ }
+}
+
+void
+LiveTimezones::updateTimezones()
+{
+ const std::string a = file_.timezone.get();
+ const std::string b = geo_ ? geo_->timezone.get() : "";
+
+ timezone.set (a.empty() ? b : a);
+
+ std::set<std::string> zones;
+ if (!a.empty())
+ zones.insert(a);
+ if (!b.empty())
+ zones.insert(b);
+ timezones.set(zones);
+}
+
+} // namespace datetime
+} // namespace indicator
+} // namespace unity
diff --git a/src/utils.c b/src/utils.c
deleted file mode 100644
index 5539c5c..0000000
--- a/src/utils.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/* -*- Mode: C; coding: utf-8; indent-tabs-mode: nil; tab-width: 2 -*-
-
-A dialog for setting time and date preferences.
-
-Copyright 2010 Canonical Ltd.
-
-Authors:
- Michael Terry <michael.terry@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 <glib/gi18n-lib.h>
-#include <gio/gio.h>
-#include <locale.h>
-#include <langinfo.h>
-#include <string.h>
-#include "utils.h"
-#include "settings-shared.h"
-
-/* Check the system locale setting to see if the format is 24-hour
- time or 12-hour time */
-gboolean
-is_locale_12h (void)
-{
- static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", NULL};
- const char *t_fmt = nl_langinfo (T_FMT);
- int i;
-
- for (i = 0; formats_24h[i]; ++i) {
- if (strstr (t_fmt, formats_24h[i])) {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-void
-split_settings_location (const gchar * location, gchar ** zone, gchar ** name)
-{
- gchar * location_dup;
- gchar * first;
-
- location_dup = g_strdup (location);
- g_strstrip (location_dup);
-
- if ((first = strchr (location_dup, ' ')))
- *first = '\0';
-
- if (zone != NULL)
- {
- *zone = location_dup;
- }
-
- if (name != NULL)
- {
- gchar * after = first ? g_strstrip (first + 1) : NULL;
-
- if (after && *after)
- {
- *name = g_strdup (after);
- }
- else /* make the name from zone */
- {
- gchar * chr = strrchr (location_dup, '/');
- after = g_strdup (chr ? chr + 1 : location_dup);
-
- /* replace underscores with spaces */
- for (chr=after; chr && *chr; chr++)
- if (*chr == '_')
- *chr = ' ';
-
- *name = after;
- }
- }
-}
-
-gchar *
-get_current_zone_name (const gchar * location, GSettings * settings)
-{
- gchar * new_zone, * new_name;
- gchar * tz_name;
- gchar * old_zone, * old_name;
- gchar * rv;
-
- split_settings_location (location, &new_zone, &new_name);
-
- tz_name = g_settings_get_string (settings, SETTINGS_TIMEZONE_NAME_S);
- split_settings_location (tz_name, &old_zone, &old_name);
- g_free (tz_name);
-
- /* new_name is always just a sanitized version of a timezone.
- old_name is potentially a saved "pretty" version of a timezone name from
- geonames. So we prefer to use it if available and the zones match. */
-
- if (g_strcmp0 (old_zone, new_zone) == 0) {
- rv = old_name;
- old_name = NULL;
- }
- else {
- rv = new_name;
- new_name = NULL;
- }
-
- g_free (new_zone);
- g_free (old_zone);
- g_free (new_name);
- g_free (old_name);
-
- return rv;
-}
-
-/* Translate msg according to the locale specified by LC_TIME */
-static const char *
-T_(const char *msg)
-{
- /* General strategy here is to make sure LANGUAGE is empty (since that
- trumps all LC_* vars) and then to temporarily swap LC_TIME and
- LC_MESSAGES. Then have gettext translate msg.
-
- We strdup the strings because the setlocale & *env functions do not
- guarantee anything about the storage used for the string, and thus
- the string may not be portably safe after multiple calls.
-
- Note that while you might think g_dcgettext would do the trick here,
- that actually looks in /usr/share/locale/XX/LC_TIME, not the
- LC_MESSAGES directory, so we won't find any translation there.
- */
- char *message_locale = g_strdup(setlocale(LC_MESSAGES, NULL));
- const char *time_locale = setlocale (LC_TIME, NULL);
- char *language = g_strdup(g_getenv("LANGUAGE"));
- const char *rv;
- if (language)
- g_unsetenv("LANGUAGE");
- setlocale(LC_MESSAGES, time_locale);
-
- /* Get the LC_TIME version */
- rv = _(msg);
-
- /* Put everything back the way it was */
- setlocale(LC_MESSAGES, message_locale);
- if (language)
- g_setenv("LANGUAGE", language, TRUE);
- g_free(message_locale);
- g_free(language);
- return rv;
-}
-
-gchar *
-join_date_and_time_format_strings (const char * date_string,
- const char * time_string)
-{
- gchar * str;
-
- if (date_string && time_string)
- {
- /* TRANSLATORS: This is a format string passed to strftime to combine the
- * date and the time. The value of "%s\xE2\x80\x82%s" will result in a
- * string like this in US English 12-hour time: 'Fri Jul 16 11:50 AM'.
- * The space in between date and time is a Unicode en space
- * (E28082 in UTF-8 hex). */
- str = g_strdup_printf (T_("%s\xE2\x80\x82%s"), date_string, time_string);
- }
- else if (date_string)
- {
- str = g_strdup_printf (T_("%s"), date_string);
- }
- else /* time_string */
- {
- str = g_strdup_printf (T_("%s"), time_string);
- }
-
- return str;
-}
-
-/***
-****
-***/
-
-typedef enum
-{
- DATE_PROXIMITY_TODAY,
- DATE_PROXIMITY_TOMORROW,
- DATE_PROXIMITY_WEEK,
- DATE_PROXIMITY_FAR
-}
-date_proximity_t;
-
-static date_proximity_t
-get_date_proximity (GDateTime * now, GDateTime * time)
-{
- date_proximity_t prox = DATE_PROXIMITY_FAR;
- gint now_year, now_month, now_day;
- gint time_year, time_month, time_day;
-
- /* does it happen today? */
- g_date_time_get_ymd (now, &now_year, &now_month, &now_day);
- g_date_time_get_ymd (time, &time_year, &time_month, &time_day);
- if ((now_year == time_year) && (now_month == time_month) && (now_day == time_day))
- prox = DATE_PROXIMITY_TODAY;
-
- /* does it happen tomorrow? */
- if (prox == DATE_PROXIMITY_FAR)
- {
- GDateTime * tomorrow;
- gint tom_year, tom_month, tom_day;
-
- tomorrow = g_date_time_add_days (now, 1);
- g_date_time_get_ymd (tomorrow, &tom_year, &tom_month, &tom_day);
- if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day))
- prox = DATE_PROXIMITY_TOMORROW;
-
- g_date_time_unref (tomorrow);
- }
-
- /* does it happen this week? */
- if (prox == DATE_PROXIMITY_FAR)
- {
- GDateTime * week;
- GDateTime * week_bound;
-
- week = g_date_time_add_days (now, 6);
- week_bound = g_date_time_new_local (g_date_time_get_year(week),
- g_date_time_get_month (week),
- g_date_time_get_day_of_month(week),
- 23, 59, 59.9);
-
- if (g_date_time_compare (time, week_bound) <= 0)
- prox = DATE_PROXIMITY_WEEK;
-
- g_date_time_unref (week_bound);
- g_date_time_unref (week);
- }
-
- return prox;
-}
-
-
-/*
- * "Terse" time & date format strings
- *
- * Used on the phone menu where space is at a premium, these strings
- * express the time and date in as brief a form as possible.
- *
- * Examples from spec:
- * 1. "Daily 6:30 AM"
- * 2. "5:07 PM" (note date is omitted; today's date is implicit)
- * 3. "Daily 12 PM" (note minutes are omitted for on-the-hour times)
- * 4. "Tomorrow 7 AM" (note "Tomorrow" is used instead of a day of week)
- */
-
-static const gchar *
-get_terse_date_format_string (date_proximity_t proximity)
-{
- const gchar * fmt;
-
- switch (proximity)
- {
- case DATE_PROXIMITY_TODAY:
- /* 'Today' is implicit in the terse case, so no string needed */
- fmt = NULL;
- break;
-
- case DATE_PROXIMITY_TOMORROW:
- fmt = T_("Tomorrow");
- break;
-
- case DATE_PROXIMITY_WEEK:
- /* a strftime(3) fmt string for abbreviated day of week */
- fmt = T_("%a");
- break;
-
- default:
- /* a strftime(3) fmt string for day-of-month and abbreviated month */
- fmt = T_("%d %b");
- break;
- }
-
- return fmt;
-}
-
-const gchar*
-get_terse_header_time_format_string (void)
-{
- /* a strftime(3) fmt string for a H:MM 12 hour time, eg "6:59 PM" */
- return T_("%l:%M %p");
-}
-
-const gchar *
-get_terse_time_format_string (GDateTime * time)
-{
- const gchar * fmt;
-
- if (g_date_time_get_minute (time) != 0)
- {
- fmt = get_terse_header_time_format_string ();
- }
- else
- {
- /* a strftime(3) fmt string for a 12 hour on-the-hour time, eg "7 PM" */
- fmt = T_("%l %p");
- }
-
- return fmt;
-}
-
-gchar *
-generate_terse_format_string_at_time (GDateTime * now, GDateTime * time)
-{
- const date_proximity_t prox = get_date_proximity (now, time);
- const gchar * date_fmt = get_terse_date_format_string (prox);
- const gchar * time_fmt = get_terse_time_format_string (time);
- return join_date_and_time_format_strings (date_fmt, time_fmt);
-}
-
-/***
-**** FULL
-***/
-
-static const gchar *
-get_full_date_format_string (gboolean show_day, gboolean show_date, gboolean show_year)
-{
- const char * fmt;
-
- if (show_day && show_date && show_year)
- /* TRANSLATORS: a strftime(3) format showing the weekday, date, and year */
- fmt = T_("%a %b %e %Y");
- else if (show_day && show_date)
- /* TRANSLATORS: a strftime(3) format showing the weekday and date */
- fmt = T_("%a %b %e");
- else if (show_day && show_year)
- /* TRANSLATORS: a strftime(3) format showing the weekday and year. */
- fmt = T_("%a %Y");
- else if (show_day)
- /* TRANSLATORS: a strftime(3) format showing the weekday. */
- fmt = T_("%a");
- else if (show_date && show_year)
- /* TRANSLATORS: a strftime(3) format showing the date and year */
- fmt = T_("%b %e %Y");
- else if (show_date)
- /* TRANSLATORS: a strftime(3) format showing the date */
- fmt = T_("%b %e");
- else if (show_year)
- /* TRANSLATORS: a strftime(3) format showing the year */
- fmt = T_("%Y");
- else
- fmt = NULL;
-
- return fmt;
-}
-
-
-/*
- * "Full" time & date format strings
- *
- * These are used on the desktop menu & header and honors the
- * GSettings entries for 12/24hr mode and whether or not to show seconds.
- *
- */
-
-const gchar *
-get_full_time_format_string (GSettings * settings)
-{
- gboolean twelvehour;
- gboolean show_seconds;
- const gchar * fmt;
-
- g_return_val_if_fail (settings != NULL, NULL);
-
- show_seconds = g_settings_get_boolean (settings, SETTINGS_SHOW_SECONDS_S);
-
- switch (g_settings_get_enum (settings, SETTINGS_TIME_FORMAT_S))
- {
- case TIME_FORMAT_MODE_LOCALE_DEFAULT:
- twelvehour = is_locale_12h();
- break;
-
- case TIME_FORMAT_MODE_24_HOUR:
- twelvehour = FALSE;
- break;
-
- default:
- twelvehour = TRUE;
- break;
- }
-
- if (twelvehour && show_seconds)
- /* TRANSLATORS: a strftime(3) format for 12hr time w/seconds */
- fmt = T_("%l:%M:%S %p");
- else if (twelvehour)
- /* TRANSLATORS: a strftime(3) format for 12hr time */
- fmt = T_("%l:%M %p");
- else if (show_seconds)
- /* TRANSLATORS: a strftime(3) format for 24hr time w/seconds */
- fmt = T_("%H:%M:%S");
- else
- /* TRANSLATORS: a strftime(3) format for 24hr time */
- fmt = T_("%H:%M");
-
- return fmt;
-}
-
-gchar *
-generate_full_format_string (gboolean show_day, gboolean show_date, gboolean show_year, GSettings * settings)
-{
- const gchar * date_fmt = get_full_date_format_string (show_day, show_date, show_year);
- const gchar * time_fmt = get_full_time_format_string (settings);
- return join_date_and_time_format_strings (date_fmt, time_fmt);
-}
-
-gchar *
-generate_full_format_string_at_time (GDateTime * now, GDateTime * time, GSettings * settings)
-{
- gboolean show_day;
- gboolean show_date;
-
- g_return_val_if_fail (now != NULL, NULL);
- g_return_val_if_fail (time != NULL, NULL);
- g_return_val_if_fail (settings != NULL, NULL);
-
- switch (get_date_proximity (now, time))
- {
- case DATE_PROXIMITY_TODAY:
- show_day = FALSE;
- show_date = FALSE;
- break;
-
- case DATE_PROXIMITY_TOMORROW:
- case DATE_PROXIMITY_WEEK:
- show_day = FALSE;
- show_date = TRUE;
- break;
-
- default:
- show_day = TRUE;
- show_date = TRUE;
- break;
- }
-
- return generate_full_format_string (show_day, show_date, FALSE, settings);
-}
-
diff --git a/src/utils.cpp b/src/utils.cpp
new file mode 100644
index 0000000..42e034e
--- /dev/null
+++ b/src/utils.cpp
@@ -0,0 +1,140 @@
+/* -*- Mode: C; coding: utf-8; indent-tabs-mode: nil; tab-width: 2 -*-
+
+A dialog for setting time and date preferences.
+
+Copyright 2010 Canonical Ltd.
+
+Authors:
+ Michael Terry <michael.terry@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 <datetime/utils.h>
+
+#include <datetime/clock.h>
+#include <datetime/clock-mock.h>
+#include <datetime/formatter.h>
+#include <datetime/settings-shared.h>
+
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include <locale.h>
+#include <langinfo.h>
+#include <string.h>
+
+/* Check the system locale setting to see if the format is 24-hour
+ time or 12-hour time */
+gboolean
+is_locale_12h (void)
+{
+ static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", NULL};
+ const char *t_fmt = nl_langinfo (T_FMT);
+ int i;
+
+ for (i = 0; formats_24h[i]; ++i) {
+ if (strstr (t_fmt, formats_24h[i])) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+void
+split_settings_location (const gchar * location, gchar ** zone, gchar ** name)
+{
+ gchar * location_dup;
+ gchar * first;
+
+ location_dup = g_strdup (location);
+ g_strstrip (location_dup);
+
+ if ((first = strchr (location_dup, ' ')))
+ *first = '\0';
+
+ if (zone != NULL)
+ {
+ *zone = location_dup;
+ }
+
+ if (name != NULL)
+ {
+ gchar * after = first ? g_strstrip (first + 1) : NULL;
+
+ if (after && *after)
+ {
+ *name = g_strdup (after);
+ }
+ else /* make the name from zone */
+ {
+ gchar * chr = strrchr (location_dup, '/');
+ after = g_strdup (chr ? chr + 1 : location_dup);
+
+ /* replace underscores with spaces */
+ for (chr=after; chr && *chr; chr++)
+ if (*chr == '_')
+ *chr = ' ';
+
+ *name = after;
+ }
+ }
+}
+
+gchar *
+get_current_zone_name (const gchar * location, GSettings * settings)
+{
+ gchar * new_zone, * new_name;
+ gchar * tz_name;
+ gchar * old_zone, * old_name;
+ gchar * rv;
+
+ split_settings_location (location, &new_zone, &new_name);
+
+ tz_name = g_settings_get_string (settings, SETTINGS_TIMEZONE_NAME_S);
+ split_settings_location (tz_name, &old_zone, &old_name);
+ g_free (tz_name);
+
+ /* new_name is always just a sanitized version of a timezone.
+ old_name is potentially a saved "pretty" version of a timezone name from
+ geonames. So we prefer to use it if available and the zones match. */
+
+ if (g_strcmp0 (old_zone, new_zone) == 0) {
+ rv = old_name;
+ old_name = NULL;
+ }
+ else {
+ rv = new_name;
+ new_name = NULL;
+ }
+
+ g_free (new_zone);
+ g_free (old_zone);
+ g_free (new_name);
+ g_free (old_name);
+
+ return rv;
+}
+
+gchar* generate_full_format_string_at_time(GDateTime* now, GDateTime* then)
+{
+ using unity::indicator::datetime::Clock;
+ using unity::indicator::datetime::MockClock;
+ using unity::indicator::datetime::DesktopFormatter;
+
+ std::shared_ptr<Clock> clock(new MockClock(now));
+ DesktopFormatter formatter(clock);
+ return g_strdup (formatter.getRelativeFormat(then).c_str());
+}
+
diff --git a/src/utils.h b/src/utils.h
deleted file mode 100644
index 5eacce5..0000000
--- a/src/utils.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* -*- Mode: C; coding: utf-8; indent-tabs-mode: nil; tab-width: 2 -*-
-
-A dialog for setting time and date preferences.
-
-Copyright 2010 Canonical Ltd.
-
-Authors:
- Michael Terry <michael.terry@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 __DATETIME_UTILS_H__
-#define __DATETIME_UTILS_H__
-
-#include <glib.h>
-#include <gio/gio.h> /* GSettings */
-
-G_BEGIN_DECLS
-
-gboolean is_locale_12h (void);
-
-void split_settings_location (const char * location,
- char ** zone,
- char ** name);
-
-gchar * get_current_zone_name (const char * location,
- GSettings * settings);
-
-gchar* join_date_and_time_format_strings (const char * date_fmt,
- const char * time_fmt);
-/***
-****
-***/
-
-const gchar * get_terse_time_format_string (GDateTime * time);
-
-const gchar * get_terse_header_time_format_string (void);
-
-const gchar * get_full_time_format_string (GSettings * settings);
-
-gchar * generate_terse_format_string_at_time (GDateTime * now,
- GDateTime * time);
-
-gchar * generate_full_format_string (gboolean show_day,
- gboolean show_date,
- gboolean show_year,
- GSettings * settings);
-
-gchar * generate_full_format_string_at_time (GDateTime * now,
- GDateTime * time,
- GSettings * settings);
-
-G_END_DECLS
-
-#endif
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 682896b..a424858 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,3 +1,12 @@
+# build libgtest
+add_library (gtest STATIC
+ ${GTEST_SOURCE_DIR}/gtest-all.cc
+ ${GTEST_SOURCE_DIR}/gtest_main.cc)
+set_target_properties (gtest PROPERTIES INCLUDE_DIRECTORIES ${INCLUDE_DIRECTORIES} ${GTEST_INCLUDE_DIR})
+set_target_properties (gtest PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS} -w)
+
+SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -g ${CC_WARNING_ARGS}")
+
# build the necessary schemas
set_directory_properties (PROPERTIES
ADDITIONAL_MAKE_CLEAN_FILES gschemas.compiled)
@@ -12,12 +21,73 @@ execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gio-2.0 --variable glib_compil
OUTPUT_VARIABLE COMPILE_SCHEMA_EXECUTABLE
OUTPUT_STRIP_TRAILING_WHITESPACE)
add_custom_command (OUTPUT gschemas.compiled
- DEPENDS ${CMAKE_SOURCE_DIR}/data/com.canonical.indicator.session.gschema.xml
+ DEPENDS ${CMAKE_SOURCE_DIR}/data/com.canonical.indicator.datetime.gschema.xml
COMMAND cp -f ${CMAKE_SOURCE_DIR}/data/*gschema.xml ${SCHEMA_DIR}
COMMAND ${COMPILE_SCHEMA_EXECUTABLE} ${SCHEMA_DIR})
-# look for hearder in our src dir, and also in the directories where we autogenerate files...
+# look for headers in our src dir, and also in the directories where we autogenerate files...
include_directories (${CMAKE_SOURCE_DIR}/src)
-include_directories (${CMAKE_CURRENT_BINARY_DIR} ${SERVICE_INCLUDE_DIRS})
+include_directories (${CMAKE_CURRENT_BINARY_DIR})
+include_directories (${DBUSTEST_INCLUDE_DIRS})
+
+add_definitions (-DSANDBOX="${CMAKE_CURRENT_BINARY_DIR}")
+
+# test-core
+set (TEST_NAME test-core)
+add_executable (${TEST_NAME} ${TEST_NAME}.cc)
+add_test (${TEST_NAME} ${TEST_NAME})
+target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+
+# test-timezone-file
+set (TEST_NAME test-timezone-file)
+add_executable (${TEST_NAME} ${TEST_NAME}.cc)
+add_test (${TEST_NAME} ${TEST_NAME})
+target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+
+# test-timezone-geoclue
+set (TEST_NAME test-timezone-geoclue)
+add_executable (${TEST_NAME} ${TEST_NAME}.cc)
+add_test (${TEST_NAME} ${TEST_NAME})
+target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${DBUSTEST_LIBRARIES} ${GTEST_LIBS})
+
+# test-timezones
+set (TEST_NAME test-timezones)
+add_executable (${TEST_NAME} ${TEST_NAME}.cc)
+add_test (${TEST_NAME} ${TEST_NAME})
+target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${DBUSTEST_LIBRARIES} ${GTEST_LIBS})
+
+# test-clock
+set (TEST_NAME test-clock)
+add_executable (${TEST_NAME} ${TEST_NAME}.cc)
+add_test (${TEST_NAME} ${TEST_NAME})
+target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+
+# test-formatter
+set (TEST_NAME test-formatter)
+add_executable (${TEST_NAME} test-formatter.cc)
+add_test (${TEST_NAME} ${TEST_NAME})
+add_dependencies (${TEST_NAME} libindicatordatetimeservice)
+target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+
+# test-planner
+set (TEST_NAME test-planner)
+add_executable (${TEST_NAME} ${TEST_NAME}.cc)
+add_test (${TEST_NAME} ${TEST_NAME})
+add_dependencies (${TEST_NAME} libindicatordatetimeservice)
+target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+
+# test-planner-eds
+set (TEST_NAME test-planner-eds)
+add_executable (${TEST_NAME} ${TEST_NAME}.cc)
+add_test (${TEST_NAME} ${TEST_NAME})
+add_dependencies (${TEST_NAME} libindicatordatetimeservice)
+target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
+
+# test-locations
+set (TEST_NAME test-locations)
+add_executable (${TEST_NAME} ${TEST_NAME}.cc)
+add_test (${TEST_NAME} ${TEST_NAME})
+add_dependencies (${TEST_NAME} libindicatordatetimeservice)
+target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS})
diff --git a/tests/geoclue-fixture.h b/tests/geoclue-fixture.h
new file mode 100644
index 0000000..890204a
--- /dev/null
+++ b/tests/geoclue-fixture.h
@@ -0,0 +1,142 @@
+/*
+ * 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 "glib-fixture.h"
+
+#include <libdbustest/dbus-test.h>
+
+class GeoclueFixture : public GlibFixture
+{
+ private:
+
+ typedef GlibFixture super;
+
+ GDBusConnection * bus = nullptr;
+
+ protected:
+
+ DbusTestService * service = nullptr;
+ DbusTestDbusMock * mock = nullptr;
+ DbusTestDbusMockObject * obj_master = nullptr;
+ DbusTestDbusMockObject * obj_client = nullptr;
+ const std::string timezone_1 = "America/Denver";
+
+ void SetUp ()
+ {
+ super::SetUp();
+
+ GError * error = nullptr;
+ const gchar * const client_path = "/org/freedesktop/Geoclue/Master/client0";
+ GString * gstr = g_string_new (nullptr);
+
+ service = dbus_test_service_new (nullptr);
+ mock = dbus_test_dbus_mock_new ("org.freedesktop.Geoclue.Master");
+
+ obj_master = dbus_test_dbus_mock_get_object (mock,
+ "/org/freedesktop/Geoclue/Master",
+ "org.freedesktop.Geoclue.Master",
+ nullptr);
+ g_string_printf (gstr, "ret = '%s'", client_path);
+ dbus_test_dbus_mock_object_add_method (mock, obj_master, nullptr, "Create", nullptr, G_VARIANT_TYPE_OBJECT_PATH, gstr->str, &error);
+
+ obj_client = dbus_test_dbus_mock_get_object (mock, client_path, "org.freedesktop.Geoclue.MasterClient", nullptr);
+ dbus_test_dbus_mock_object_add_method (mock, obj_client, nullptr, "SetRequirements", G_VARIANT_TYPE("(iibi)"), nullptr, "", &error);
+ dbus_test_dbus_mock_object_add_method (mock, obj_client, nullptr, "AddressStart", nullptr, nullptr, "", &error);
+ dbus_test_dbus_mock_object_add_method (mock, obj_client, "org.freedesktop.Geoclue", "AddReference", nullptr, nullptr, "", &error);
+ g_string_printf (gstr, "ret = (1385238033, {'timezone': '%s'}, (3, 0.0, 0.0))", timezone_1.c_str());
+ dbus_test_dbus_mock_object_add_method (mock, obj_client, "org.freedesktop.Geoclue.Address", "GetAddress", nullptr, G_VARIANT_TYPE("(ia{ss}(idd))"), gstr->str, &error);
+
+ dbus_test_service_add_task(service, DBUS_TEST_TASK(mock));
+ dbus_test_service_start_tasks(service);
+
+ bus = g_bus_get_sync (G_BUS_TYPE_SESSION, nullptr, nullptr);
+ g_dbus_connection_set_exit_on_close (bus, FALSE);
+ g_object_add_weak_pointer (G_OBJECT(bus), (gpointer*)&bus);
+
+ g_string_free (gstr, TRUE);
+ }
+
+ virtual void TearDown ()
+ {
+ g_clear_object (&mock);
+ g_clear_object (&service);
+ g_object_unref (bus);
+
+ unsigned int cleartry = 0;
+ while (bus != nullptr && cleartry < 10)
+ {
+ wait_msec (100);
+ cleartry++;
+ }
+
+ // I've looked and can't find where this extra ref is coming from.
+ // is there an unbalanced ref to the bus in the test harness?!
+ while (bus != NULL)
+ {
+ g_object_unref (bus);
+ wait_msec (1000);
+ }
+
+ super::TearDown ();
+ }
+
+private:
+
+ struct EmitAddressChangedData
+ {
+ DbusTestDbusMock * mock = nullptr;
+ DbusTestDbusMockObject * obj_client = nullptr;
+ std::string timezone;
+ EmitAddressChangedData(DbusTestDbusMock * mock_,
+ DbusTestDbusMockObject * obj_client_,
+ const std::string& timezone_): mock(mock_), obj_client(obj_client_), timezone(timezone_) {}
+ };
+
+ static gboolean emit_address_changed_idle (gpointer gdata)
+ {
+ auto data = static_cast<EmitAddressChangedData*>(gdata);
+ auto fmt = g_strdup_printf ("(1385238033, {'timezone': '%s'}, (3, 0.0, 0.0))", data->timezone.c_str());
+
+ GError * error = nullptr;
+ dbus_test_dbus_mock_object_emit_signal(data->mock, data->obj_client,
+ "org.freedesktop.Geoclue.Address",
+ "AddressChanged",
+ G_VARIANT_TYPE("(ia{ss}(idd))"),
+ g_variant_new_parsed (fmt),
+ &error);
+ if (error)
+ {
+ g_warning("%s: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+
+ g_free (fmt);
+ delete data;
+ return G_SOURCE_REMOVE;
+ }
+
+public:
+
+ void setGeoclueTimezoneOnIdle (const std::string& newZone)
+ {
+ g_timeout_add (50, emit_address_changed_idle, new EmitAddressChangedData(mock, obj_client, newZone.c_str()));
+ }
+
+};
+
diff --git a/tests/glib-fixture.h b/tests/glib-fixture.h
new file mode 100644
index 0000000..043b7e3
--- /dev/null
+++ b/tests/glib-fixture.h
@@ -0,0 +1,131 @@
+/*
+ * 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 <map>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+
+#include <gtest/gtest.h>
+
+class GlibFixture : public ::testing::Test
+{
+ private:
+
+ //GLogFunc realLogHandler;
+
+ protected:
+
+ std::map<GLogLevelFlags,int> logCounts;
+
+ void testLogCount (GLogLevelFlags log_level, int expected G_GNUC_UNUSED)
+ {
+#if 0
+ EXPECT_EQ (expected, logCounts[log_level]);
+#endif
+
+ logCounts.erase (log_level);
+ }
+
+ private:
+
+ static void default_log_handler (const gchar * log_domain,
+ GLogLevelFlags log_level,
+ const gchar * message,
+ gpointer self)
+ {
+ g_print ("%s - %d - %s\n", log_domain, (int)log_level, message);
+ static_cast<GlibFixture*>(self)->logCounts[log_level]++;
+ }
+
+ protected:
+
+ virtual void SetUp ()
+ {
+ loop = g_main_loop_new (NULL, FALSE);
+
+ //g_log_set_default_handler (default_log_handler, this);
+
+ // only use local, temporary settings
+ g_setenv ("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE);
+ g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
+ g_debug ("SCHEMA_DIR is %s", SCHEMA_DIR);
+ }
+
+ virtual void TearDown()
+ {
+#if 0
+ // confirm there aren't any unexpected log messages
+ EXPECT_EQ (0, logCounts[G_LOG_LEVEL_ERROR]);
+ EXPECT_EQ (0, logCounts[G_LOG_LEVEL_CRITICAL]);
+ EXPECT_EQ (0, logCounts[G_LOG_LEVEL_WARNING]);
+ EXPECT_EQ (0, logCounts[G_LOG_LEVEL_MESSAGE]);
+ EXPECT_EQ (0, logCounts[G_LOG_LEVEL_INFO]);
+#endif
+
+ // revert to glib's log handler
+ //g_log_set_default_handler (realLogHandler, this);
+
+ g_clear_pointer (&loop, g_main_loop_unref);
+ }
+
+ private:
+
+ static gboolean
+ wait_for_signal__timeout (gpointer name)
+ {
+ g_error ("%s: timed out waiting for signal '%s'", G_STRLOC, (char*)name);
+ return G_SOURCE_REMOVE;
+ }
+
+ static gboolean
+ wait_msec__timeout (gpointer loop)
+ {
+ g_main_loop_quit (static_cast<GMainLoop*>(loop));
+ return G_SOURCE_CONTINUE;
+ }
+
+ protected:
+
+ /* convenience func to loop while waiting for a GObject's signal */
+ void wait_for_signal (gpointer o, const gchar * signal, const int timeout_seconds=5)
+ {
+ // wait for the signal or for timeout, whichever comes first
+ const auto handler_id = g_signal_connect_swapped (o, signal,
+ G_CALLBACK(g_main_loop_quit),
+ loop);
+ const auto timeout_id = g_timeout_add_seconds (timeout_seconds,
+ wait_for_signal__timeout,
+ loop);
+ g_main_loop_run (loop);
+ g_source_remove (timeout_id);
+ g_signal_handler_disconnect (o, handler_id);
+ }
+
+ /* convenience func to loop for N msec */
+ void wait_msec (int msec=50)
+ {
+ const auto id = g_timeout_add (msec, wait_msec__timeout, loop);
+ g_main_loop_run (loop);
+ g_source_remove (id);
+ }
+
+ GMainLoop * loop;
+};
diff --git a/tests/test-core.cc b/tests/test-core.cc
new file mode 100644
index 0000000..7ed38a9
--- /dev/null
+++ b/tests/test-core.cc
@@ -0,0 +1,148 @@
+
+/*
+ * 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 <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#include <langinfo.h>
+#include <locale.h>
+
+#include <glib/gi18n.h>
+
+#include <core/connection.h>
+#include <core/signal.h>
+#include <core/property.h>
+
+#include "glib-fixture.h"
+
+/***
+****
+***/
+
+class CoreFixture: public GlibFixture
+{
+ private:
+
+ typedef GlibFixture super;
+
+ protected:
+
+ virtual void SetUp ()
+ {
+ super::SetUp ();
+ }
+
+ virtual void TearDown ()
+ {
+ super::TearDown ();
+ }
+};
+
+namespace
+{
+struct EventLoop
+{
+ typedef std::function<void()> Handler;
+
+ void stop()
+ {
+ stop_requested = true;
+ }
+
+ void run()
+ {
+ while (!stop_requested)
+ {
+ std::unique_lock<std::mutex> ul(guard);
+ wait_condition.wait_for(
+ ul,
+ std::chrono::milliseconds{500},
+ [this]() { return handlers.size() > 0; });
+
+ std::cerr << "handlers.size() is " << handlers.size() << std::endl;
+ while (handlers.size() > 0)
+ {
+ std::cerr << "gaba begin" << std::endl;
+ handlers.front()();
+ std::cerr << "gaba end" << std::endl;
+ handlers.pop();
+ }
+ }
+ }
+
+ void dispatch(const Handler& h)
+ {
+std::cerr << "in dispatch" << std::endl;
+ std::lock_guard<std::mutex> lg(guard);
+ handlers.push(h);
+ }
+
+ bool stop_requested = false;
+ std::queue<Handler> handlers;
+ std::mutex guard;
+ std::condition_variable wait_condition;
+};
+}
+
+
+TEST_F (CoreFixture, HelloWorld)
+{
+ // We instantiate an event loop and run it on a different thread than the main one.
+ EventLoop dispatcher;
+ std::thread dispatcher_thread{[&dispatcher]() { dispatcher.run(); }};
+ std::thread::id dispatcher_thread_id = dispatcher_thread.get_id();
+
+ // The signal that we want to dispatch via the event loop.
+ core::Signal<int, double> s;
+
+ static const int expected_invocation_count = 10000;
+
+ // Setup the connection. For each invocation we check that the id of the
+ // thread the handler is being called upon equals the thread that the
+ // event loop is running upon.
+ auto connection = s.connect(
+ [&dispatcher, dispatcher_thread_id](int value, double d)
+ {
+ std::cerr << "this is the lambda" << std::endl;
+ EXPECT_EQ(dispatcher_thread_id,
+ std::this_thread::get_id());
+
+ std::cout << d << std::endl;
+
+ if (value == expected_invocation_count)
+ dispatcher.stop();
+ });
+
+ // Route the connection via the dispatcher
+ connection.dispatch_via(
+ std::bind(
+ &EventLoop::dispatch,
+ std::ref(dispatcher),
+ std::placeholders::_1));
+
+ // Invoke the signal from the main thread.
+ for (unsigned int i = 1; i <= expected_invocation_count; i++)
+ s(i, 42.);
+
+ if (dispatcher_thread.joinable())
+ dispatcher_thread.join();
+}
diff --git a/tests/test-skew.cc b/tests/test-skew.cc
new file mode 100644
index 0000000..90c0164
--- /dev/null
+++ b/tests/test-skew.cc
@@ -0,0 +1,209 @@
+/*
+ * 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 "glib-fixture.h"
+
+#include "Clock.h"
+#include "MockClock.h"
+
+/***
+****
+***/
+
+using unity::indicator::datetime::Clock;
+using unity::indicator::datetime::MockClock;
+using unity::indicator::datetime::SkewDetector;
+
+class SkewFixture: public GlibFixture
+{
+ private:
+
+ typedef GlibFixture super;
+
+ static void
+ on_bus_opened (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself)
+ {
+ auto self = static_cast<SkewFixture*>(gself);
+
+ GError * err = 0;
+ self->system_bus = g_bus_get_finish (res, &err);
+ g_assert_no_error (err);
+
+ g_main_loop_quit (self->loop);
+ }
+
+ static void
+ on_bus_closed (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself)
+ {
+ auto self = static_cast<SkewFixture*>(gself);
+
+ GError * err = 0;
+ g_dbus_connection_close_finish (self->system_bus, res, &err);
+ g_assert_no_error (err);
+
+ g_main_loop_quit (self->loop);
+ }
+
+ protected:
+
+ std::shared_ptr<Clock> mockClock;
+ GTestDBus * test_dbus;
+ GDBusConnection * system_bus;
+
+ virtual void SetUp ()
+ {
+ super::SetUp ();
+
+ // pull up a test dbus
+ test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
+ g_test_dbus_up (test_dbus);
+ const char * address = g_test_dbus_get_bus_address (test_dbus);
+ g_setenv ("DBUS_SYSTEM_BUS_ADDRESS", address, TRUE);
+ g_debug ("test_dbus's address is %s", address);
+
+ // wait for the GDBusConnection before returning
+ g_bus_get (G_BUS_TYPE_SYSTEM, nullptr, on_bus_opened, this);
+ g_main_loop_run (loop);
+
+ // create a clock
+ GDateTime * now = g_date_time_new_now_local ();
+ mockClock.reset (new MockClock (now));
+ g_date_time_unref (now);
+ }
+
+ virtual void TearDown ()
+ {
+ mockClock.reset();
+
+ // close the system bus
+ g_dbus_connection_close (system_bus, nullptr, on_bus_closed, this);
+ g_main_loop_run (loop);
+ g_clear_object (&system_bus);
+
+ // tear down the test dbus
+ g_test_dbus_down (test_dbus);
+ g_clear_object (&test_dbus);
+
+ super::TearDown ();
+ }
+
+ public:
+
+ void emitPrepareForSleep ()
+ {
+ g_dbus_connection_emit_signal (g_bus_get_sync (G_BUS_TYPE_SYSTEM, nullptr, nullptr),
+ NULL,
+ "/org/freedesktop/login1", // object path
+ "org.freedesktop.login1.Manager", // interface
+ "PrepareForSleep", // signal name
+ g_variant_new("(b)", FALSE),
+ NULL);
+ }
+};
+
+
+/**
+ * A simple "hello world" style test.
+ */
+TEST_F (SkewFixture, CanInstantiate)
+{
+ SkewDetector skew (std::dynamic_pointer_cast<Clock>(mockClock));
+ wait_msec (500); // wait for the bus to set up
+}
+
+
+/**
+ * Confirm that changing the clock's timezone triggers a skew event
+ */
+TEST_F (SkewFixture, ChangingTimezonesTriggersEvent)
+{
+ SkewDetector skew (std::dynamic_pointer_cast<Clock>(mockClock));
+ wait_msec (500); // wait for the bus to set up
+
+ bool skewed = false;
+ skew.skewDetected.connect([&skewed, this](){
+ skewed = true;
+ g_main_loop_quit(loop);
+ return G_SOURCE_REMOVE;
+ });
+
+ g_idle_add([](gpointer gclock){
+ GDateTime * arbitrary = g_date_time_new_local (2020, 10, 31, 18, 30, 59);
+ static_cast<MockClock*>(gclock)->setLocaltime (arbitrary);
+ g_date_time_unref (arbitrary);
+ return G_SOURCE_REMOVE;
+ }, mockClock.get());
+
+ wait_msec (1000);
+
+ EXPECT_TRUE (skewed);
+ GDateTime * expected = g_date_time_new_local (2020, 10, 31, 18, 30, 59);
+ GDateTime * actual = mockClock->localtime();
+ EXPECT_EQ (0, g_date_time_compare (expected, actual));
+ g_date_time_unref (actual);
+ g_date_time_unref (expected);
+}
+
+/**
+ * Confirm that a "PrepareForSleep" event wil trigger a skew event
+ */
+TEST_F (SkewFixture, PrepareForSleep)
+{
+ SkewDetector skew (std::dynamic_pointer_cast<Clock>(mockClock));
+ wait_msec (500); // wait for the bus to set up
+
+ bool skewed = false;
+ skew.skewDetected.connect([&skewed, this](){
+ skewed = true;
+ g_main_loop_quit(loop);
+ return G_SOURCE_REMOVE;
+ });
+
+ g_idle_add ([](gpointer gself){
+ static_cast<SkewFixture*>(gself)->emitPrepareForSleep();
+ return G_SOURCE_REMOVE;
+ }, this);
+
+ wait_msec (1000);
+ EXPECT_TRUE(skewed);
+}
+
+
+/**
+ * Confirm that normal time passing doesn't trigger a skew event.
+ * that idling changing the clock's time triggers a skew event
+ */
+TEST_F (SkewFixture, IdleDoesNotTriggerEvent)
+{
+ SkewDetector skew (std::dynamic_pointer_cast<Clock>(mockClock));
+ wait_msec (500); // wait for the bus to set up
+
+ bool skewed = false;
+ skew.skewDetected.connect([&skewed](){
+ skewed = true;
+ g_warn_if_reached();
+ //abort();
+ return G_SOURCE_REMOVE;
+ });
+
+ const unsigned int intervalSec = 4;
+ skew.intervalSec.set(intervalSec);
+ wait_msec (intervalSec * 2.5 * 1000);
+ EXPECT_FALSE (skewed);
+}
diff --git a/tests/test-timezones.cc b/tests/test-timezones.cc
new file mode 100644
index 0000000..cda53a6
--- /dev/null
+++ b/tests/test-timezones.cc
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * 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/>.
+ *
+ * Authors:
+ * Charles Kerr <charles.kerr@canonical.com>
+ */
+
+#include "geoclue-fixture.h"
+
+#include <datetime/timezones-live.h>
+
+#include <cstdio> // fopen()
+#include <unistd.h> // sync()
+
+using unity::indicator::datetime::LiveTimezones;
+
+typedef GeoclueFixture TimezonesFixture;
+
+#define TIMEZONE_FILE (SANDBOX "/timezone")
+
+namespace
+{
+ /* convenience func to set the timezone file */
+ void set_file (const std::string& text)
+ {
+ FILE * fp = fopen (TIMEZONE_FILE, "w+");
+ fprintf (fp, "%s\n", text.c_str());
+ fclose (fp);
+ sync ();
+ }
+}
+
+
+TEST_F (TimezonesFixture, ManagerTest)
+{
+ std::string timezone_file = "America/New_York";
+ std::string timezone_geo = "America/Denver";
+
+ set_file (timezone_file);
+ LiveTimezones z (TIMEZONE_FILE);
+ wait_msec (500); // wait for the bus to get set up
+ EXPECT_EQ (timezone_file, z.timezone.get());
+ std::set<std::string> zones = z.timezones.get();
+ EXPECT_EQ (1, zones.size());
+ EXPECT_EQ (1, zones.count(timezone_file));
+
+ bool zone_changed = false;
+ auto zone_connection = z.timezone.changed().connect([&zone_changed, this](const std::string&) {
+ zone_changed = true;
+ g_main_loop_quit (loop);
+ });
+
+ // start listening for a timezone change, then change the timezone
+ bool zones_changed = false;
+ auto zones_connection = z.timezones.changed().connect([&zones_changed, &zones, this](const std::set<std::string>& timezones) {
+ zones_changed = true;
+ zones = timezones;
+ g_main_loop_quit (loop);
+ });
+
+ g_idle_add ([](gpointer gz) {
+ auto az = static_cast<LiveTimezones*>(gz);
+ g_message ("geolocation was %d", (int)az->geolocationEnabled.get());
+ g_message ("turning geolocation on");
+ az->geolocationEnabled.set(true);
+ return G_SOURCE_REMOVE;
+ }, &z);
+
+ // turn on geoclue during the idle... this should add timezone_1 to the 'timezones' property
+ g_main_loop_run (loop);
+ EXPECT_TRUE (zones_changed);
+ EXPECT_EQ (timezone_file, z.timezone.get());
+ EXPECT_EQ (2, zones.size());
+ EXPECT_EQ (1, zones.count(timezone_file));
+ EXPECT_EQ (1, zones.count(timezone_geo));
+ zones_changed = false;
+
+ // now tweak the geoclue value... the geoclue-detected timezone should change,
+ // causing the 'timezones' property to change
+ zone_changed = false;
+ zones_changed = false;
+ timezone_geo = "America/Chicago";
+ setGeoclueTimezoneOnIdle (timezone_geo);
+ g_main_loop_run (loop);
+ EXPECT_FALSE (zone_changed);
+ EXPECT_TRUE (zones_changed);
+ EXPECT_EQ (timezone_file, z.timezone.get());
+ EXPECT_EQ (2, zones.size());
+ EXPECT_EQ (1, zones.count(timezone_file));
+ EXPECT_EQ (1, zones.count(timezone_geo));
+
+ // now set the file value... this should change both the primary property and set property
+ zone_changed = false;
+ zones_changed = false;
+ timezone_file = "America/Los_Angeles";
+ EXPECT_EQ (0, zones.count(timezone_file));
+ g_idle_add ([](gpointer str) {set_file(static_cast<const char*>(str)); return G_SOURCE_REMOVE;}, const_cast<char*>(timezone_file.c_str()));
+ g_main_loop_run (loop);
+ EXPECT_TRUE (zone_changed);
+ EXPECT_TRUE (zones_changed);
+ EXPECT_EQ (timezone_file, z.timezone.get());
+ EXPECT_EQ (2, zones.size());
+ EXPECT_EQ (1, zones.count(timezone_file));
+ EXPECT_EQ (1, zones.count(timezone_geo));
+
+
+
+}
+
+