From 3b8833efe6ab21387b6f73b4a4ef757445801623 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 17 Dec 2013 22:10:18 -0600 Subject: add geoclue, glib test fixtures --- src/CMakeLists.txt | 50 ++-- src/clock-live.c | 278 --------------------- src/clock-live.h | 73 ------ src/clock.c | 110 --------- src/clock.h | 76 ------ src/dbus-shared.h | 24 -- src/formatter.cpp | 462 ++++++++++++++++++++++++++++++++++ src/planner-eds.c | 653 ------------------------------------------------- src/planner.c | 281 --------------------- src/service.h | 84 ------- src/settings-shared.h | 50 ---- src/timezone-file.c | 212 ---------------- src/timezone-file.h | 58 ----- src/timezone-geoclue.c | 227 ----------------- src/timezone-geoclue.h | 57 ----- src/timezone.c | 134 ---------- src/timezone.h | 72 ------ src/timezones-live.cpp | 69 ++++++ src/utils.c | 453 ---------------------------------- src/utils.cpp | 140 +++++++++++ src/utils.h | 66 ----- 21 files changed, 693 insertions(+), 2936 deletions(-) delete mode 100644 src/clock-live.c delete mode 100644 src/clock-live.h delete mode 100644 src/clock.c delete mode 100644 src/clock.h delete mode 100644 src/dbus-shared.h create mode 100644 src/formatter.cpp delete mode 100644 src/planner-eds.c delete mode 100644 src/planner.c delete mode 100644 src/service.h delete mode 100644 src/settings-shared.h delete mode 100644 src/timezone-file.c delete mode 100644 src/timezone-file.h delete mode 100644 src/timezone-geoclue.c delete mode 100644 src/timezone-geoclue.h delete mode 100644 src/timezone.c delete mode 100644 src/timezone.h create mode 100644 src/timezones-live.cpp delete mode 100644 src/utils.c create mode 100644 src/utils.cpp delete mode 100644 src/utils.h (limited to 'src') 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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include - -#include "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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef __INDICATOR_DATETIME_CLOCK_LIVE__H__ -#define __INDICATOR_DATETIME_CLOCK_LIVE__H__ - -#include /* parent class */ - -#include "clock.h" - -G_BEGIN_DECLS - -#define INDICATOR_TYPE_DATETIME_CLOCK_LIVE \ - (indicator_datetime_clock_live_get_type()) - -#define INDICATOR_DATETIME_CLOCK_LIVE(o) \ - (G_TYPE_CHECK_INSTANCE_CAST ((o), \ - INDICATOR_TYPE_DATETIME_CLOCK_LIVE, \ - IndicatorDatetimeClockLive)) - -#define INDICATOR_DATETIME_CLOCK_LIVE_GET_CLASS(o) \ - (G_TYPE_INSTANCE_GET_CLASS ((o), \ - INDICATOR_TYPE_DATETIME_CLOCK_LIVE, \ - IndicatorDatetimeClockLiveClass)) - -#define INDICATOR_IS_DATETIME_CLOCK_LIVE(o) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((o), \ - INDICATOR_TYPE_DATETIME_CLOCK_LIVE)) - -typedef struct _IndicatorDatetimeClockLive - IndicatorDatetimeClockLive; -typedef struct _IndicatorDatetimeClockLivePriv - IndicatorDatetimeClockLivePriv; -typedef struct _IndicatorDatetimeClockLiveClass - IndicatorDatetimeClockLiveClass; - -/** - * An IndicatorDatetimeClock which gives live clock times - * from timezones determined by geoclue and /etc/timezone - */ -struct _IndicatorDatetimeClockLive -{ - GObject parent_instance; - - IndicatorDatetimeClockLivePriv * priv; -}; - -struct _IndicatorDatetimeClockLiveClass -{ - GObjectClass parent_class; -}; - -IndicatorDatetimeClock * indicator_datetime_clock_live_new (void); - -G_END_DECLS - -#endif /* __INDICATOR_DATETIME_CLOCK_LIVE__H__ */ diff --git a/src/clock.c b/src/clock.c deleted file mode 100644 index 2c2fec2..0000000 --- a/src/clock.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2013 Canonical Ltd. - * - * Authors: - * Charles Kerr - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef __INDICATOR_DATETIME_CLOCK__H__ -#define __INDICATOR_DATETIME_CLOCK__H__ - -#include - -G_BEGIN_DECLS - -#define INDICATOR_TYPE_DATETIME_CLOCK \ - (indicator_datetime_clock_get_type ()) - -#define INDICATOR_DATETIME_CLOCK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ - INDICATOR_TYPE_DATETIME_CLOCK, \ - IndicatorDatetimeClock)) - -#define INDICATOR_IS_DATETIME_CLOCK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_TYPE_DATETIME_CLOCK)) - -#define INDICATOR_DATETIME_CLOCK_GET_INTERFACE(inst) \ - (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \ - INDICATOR_TYPE_DATETIME_CLOCK, \ - IndicatorDatetimeClockInterface)) - -typedef struct _IndicatorDatetimeClock - IndicatorDatetimeClock; - -typedef struct _IndicatorDatetimeClockInterface - IndicatorDatetimeClockInterface; - -struct _IndicatorDatetimeClockInterface -{ - GTypeInterface parent_iface; - - /* signals */ - void (*changed) (IndicatorDatetimeClock * self); - - /* virtual functions */ - 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 - -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 . -*/ - -#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 . + * + * Authors: + * Charles Kerr + */ + +#include + +#include + +#include +#include + +#include // setlocale() +#include // nl_langinfo() +#include // 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): + 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(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(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_; +}; + +/*** +**** +***/ + +Formatter::Formatter(const std::shared_ptr& 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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include -#include -#include - -#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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef __INDICATOR_DATETIME_SERVICE_H__ -#define __INDICATOR_DATETIME_SERVICE_H__ - -#include -#include - -#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 - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#ifndef __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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include /* 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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef __INDICATOR_DATETIME_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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include -#include - -#include "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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef __INDICATOR_DATETIME_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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "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 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef __INDICATOR_DATETIME_TIMEZONE__H__ -#define __INDICATOR_DATETIME_TIMEZONE__H__ - -#include -#include /* 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 . + * + * Authors: + * Charles Kerr + */ + +#include +#include + +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 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 - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#include -#include -#include -#include -#include -#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 + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see . +*/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* 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(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 - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#ifndef __DATETIME_UTILS_H__ -#define __DATETIME_UTILS_H__ - -#include -#include /* 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 -- cgit v1.2.3