[Xfce4-commits] <xfce4-panel:master> Clock plugin: proper timezone support and refactoring.

Andrzej noreply at xfce.org
Sun Mar 3 12:02:02 CET 2013


Updating branch refs/heads/master
         to 1e4d05c8ad33e2a03d95d9215df576bcf5b2cb06 (commit)
       from 6a34f8151ea55dc732ddb857d5c708cd96de2a10 (commit)

commit 1e4d05c8ad33e2a03d95d9215df576bcf5b2cb06
Author: Andrzej <ndrwrdck at gmail.com>
Date:   Sat Feb 23 02:07:59 2013 +0000

    Clock plugin: proper timezone support and refactoring.
    
    Regression testing appreciated.
    
    Switched to GDateTime and GTimeZone API - they do not use global
    variables, so it is possible to have several clock plugins set to
    different time zones.
    
    Bonus: utf-8 support and localization.
    
    The change required a rather deep refactoring. Added a new class
    abstracting time operations, which can be accessed from either the plugin
    or clock widgets. Previous design worked only because the time functions
    did not need a local state (e.g. a timezone).

 plugins/clock/Makefile.am     |    4 +
 plugins/clock/clock-analog.c  |   50 +++--
 plugins/clock/clock-analog.h  |    2 +-
 plugins/clock/clock-binary.c  |   60 ++++---
 plugins/clock/clock-binary.h  |    2 +-
 plugins/clock/clock-digital.c |   45 +++--
 plugins/clock/clock-digital.h |    2 +-
 plugins/clock/clock-fuzzy.c   |   45 +++--
 plugins/clock/clock-fuzzy.h   |    2 +-
 plugins/clock/clock-lcd.c     |   64 ++++---
 plugins/clock/clock-lcd.h     |    2 +-
 plugins/clock/clock-time.c    |  422 +++++++++++++++++++++++++++++++++++++++++
 plugins/clock/clock-time.h    |   65 +++++++
 plugins/clock/clock.c         |  362 ++++-------------------------------
 plugins/clock/clock.h         |   16 --
 15 files changed, 688 insertions(+), 455 deletions(-)

diff --git a/plugins/clock/Makefile.am b/plugins/clock/Makefile.am
index 1878115..9ecb8f8 100644
--- a/plugins/clock/Makefile.am
+++ b/plugins/clock/Makefile.am
@@ -16,6 +16,8 @@ libclock_la_SOURCES = \
 	$(libclock_built_sources) \
 	clock.c \
 	clock.h \
+	clock-time.c \
+	clock-time.h \
 	clock-analog.c \
 	clock-analog.h \
 	clock-binary.c \
@@ -28,6 +30,7 @@ libclock_la_SOURCES = \
 	clock-lcd.h
 
 libclock_la_CFLAGS = \
+	$(GLIB_CFLAGS) \
 	$(GTK_CFLAGS) \
 	$(LIBXFCE4UTIL_CFLAGS) \
 	$(CAIRO_CFLAGS) \
@@ -46,6 +49,7 @@ libclock_la_LDFLAGS =	 \
 libclock_la_LIBADD = \
 	$(top_builddir)/libxfce4panel/libxfce4panel-$(LIBXFCE4PANEL_VERSION_API).la \
 	$(top_builddir)/common/libpanel-common.la \
+	$(GLIB_LIBS) \
 	$(GTK_LIBS) \
 	$(CAIRO_LIBS) \
 	$(LIBXFCE4UTIL_LIBS) \
diff --git a/plugins/clock/clock-analog.c b/plugins/clock/clock-analog.c
index 63a8394..2e96a09 100644
--- a/plugins/clock/clock-analog.c
+++ b/plugins/clock/clock-analog.c
@@ -23,14 +23,12 @@
 #ifdef HAVE_MATH_H
 #include <math.h>
 #endif
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
 
 #include <gtk/gtk.h>
 #include <cairo/cairo.h>
 
 #include "clock.h"
+#include "clock-time.h"
 #include "clock-analog.h"
 
 #define CLOCK_SCALE 0.1
@@ -61,7 +59,9 @@ static void      xfce_clock_analog_draw_pointer  (cairo_t              *cr,
                                                   gdouble               angle,
                                                   gdouble               scale,
                                                   gboolean              line);
-static gboolean  xfce_clock_analog_update        (gpointer              user_data);
+static gboolean  xfce_clock_analog_update        (XfceClockAnalog      *analog,
+                                                  ClockTime            *time);
+
 
 
 
@@ -82,9 +82,10 @@ struct _XfceClockAnalog
 {
   GtkImage __parent__;
 
-  ClockPluginTimeout *timeout;
+  ClockTimeTimeout   *timeout;
 
   guint               show_seconds : 1;
+  ClockTime          *time;
 };
 
 
@@ -136,9 +137,6 @@ static void
 xfce_clock_analog_init (XfceClockAnalog *analog)
 {
   analog->show_seconds = FALSE;
-  analog->timeout = clock_plugin_timeout_new (CLOCK_INTERVAL_MINUTE,
-                                              xfce_clock_analog_update,
-                                              analog);
 }
 
 
@@ -166,9 +164,9 @@ xfce_clock_analog_set_property (GObject      *object,
     }
 
   /* reschedule the timeout and redraw */
-  clock_plugin_timeout_set_interval (analog->timeout,
+  clock_time_timeout_set_interval (analog->timeout,
       analog->show_seconds ? CLOCK_INTERVAL_SECOND : CLOCK_INTERVAL_MINUTE);
-  xfce_clock_analog_update (analog);
+  xfce_clock_analog_update (analog, analog->time);
 }
 
 
@@ -203,7 +201,7 @@ static void
 xfce_clock_analog_finalize (GObject *object)
 {
   /* stop the timeout */
-  clock_plugin_timeout_free (XFCE_CLOCK_ANALOG (object)->timeout);
+  clock_time_timeout_free (XFCE_CLOCK_ANALOG (object)->timeout);
 
   (*G_OBJECT_CLASS (xfce_clock_analog_parent_class)->finalize) (object);
 }
@@ -218,7 +216,7 @@ xfce_clock_analog_expose_event (GtkWidget      *widget,
   gdouble          xc, yc;
   gdouble          angle, radius;
   cairo_t         *cr;
-  struct tm        tm;
+  GDateTime       *time;
 
   panel_return_val_if_fail (XFCE_CLOCK_IS_ANALOG (analog), FALSE);
 
@@ -241,7 +239,7 @@ xfce_clock_analog_expose_event (GtkWidget      *widget,
       cairo_clip (cr);
 
       /* get the local time */
-      clock_plugin_get_localtime (&tm);
+      time = clock_time_get_time (analog->time);
 
       /* set the line properties */
       cairo_set_line_width (cr, 1);
@@ -253,19 +251,20 @@ xfce_clock_analog_expose_event (GtkWidget      *widget,
       if (analog->show_seconds)
         {
           /* second pointer */
-          angle = TICKS_TO_RADIANS (tm.tm_sec);
+          angle = TICKS_TO_RADIANS (g_date_time_get_second (time));
           xfce_clock_analog_draw_pointer (cr, xc, yc, radius, angle, 0.7, TRUE);
         }
 
       /* minute pointer */
-      angle = TICKS_TO_RADIANS (tm.tm_min);
+      angle = TICKS_TO_RADIANS (g_date_time_get_minute (time));
       xfce_clock_analog_draw_pointer (cr, xc, yc, radius, angle, 0.8, FALSE);
 
       /* hour pointer */
-      angle = HOURS_TO_RADIANS (tm.tm_hour, tm.tm_min);
+      angle = HOURS_TO_RADIANS (g_date_time_get_hour (time), g_date_time_get_minute (time));
       xfce_clock_analog_draw_pointer (cr, xc, yc, radius, angle, 0.5, FALSE);
 
       /* cleanup */
+      g_date_time_unref (time);
       cairo_destroy (cr);
     }
 
@@ -347,11 +346,13 @@ xfce_clock_analog_draw_pointer (cairo_t *cr,
 
 
 static gboolean
-xfce_clock_analog_update (gpointer user_data)
+xfce_clock_analog_update (XfceClockAnalog *analog,
+                          ClockTime       *time)
 {
-  GtkWidget *widget = GTK_WIDGET (user_data);
+  GtkWidget *widget = GTK_WIDGET (analog);
 
-  panel_return_val_if_fail (XFCE_CLOCK_IS_ANALOG (user_data), FALSE);
+  panel_return_val_if_fail (XFCE_CLOCK_IS_ANALOG (analog), FALSE);
+  panel_return_val_if_fail (XFCE_IS_CLOCK_TIME (time), FALSE);
 
   /* update if the widget if visible */
   if (G_LIKELY (GTK_WIDGET_VISIBLE (widget)))
@@ -363,7 +364,14 @@ xfce_clock_analog_update (gpointer user_data)
 
 
 GtkWidget *
-xfce_clock_analog_new (void)
+xfce_clock_analog_new (ClockTime *time)
 {
-  return g_object_new (XFCE_CLOCK_TYPE_ANALOG, NULL);
+  XfceClockAnalog *analog = g_object_new (XFCE_CLOCK_TYPE_ANALOG, NULL);
+
+  analog->time = time;
+  analog->timeout = clock_time_timeout_new (CLOCK_INTERVAL_MINUTE,
+                                            analog->time,
+                                            G_CALLBACK (xfce_clock_analog_update), analog);
+
+  return GTK_WIDGET (analog);
 }
diff --git a/plugins/clock/clock-analog.h b/plugins/clock/clock-analog.h
index a03e6a2..8e70497 100644
--- a/plugins/clock/clock-analog.h
+++ b/plugins/clock/clock-analog.h
@@ -35,7 +35,7 @@ GType      xfce_clock_analog_get_type      (void) G_GNUC_CONST;
 
 void       xfce_clock_analog_register_type (XfcePanelTypeModule *type_module);
 
-GtkWidget *xfce_clock_analog_new           (void) G_GNUC_MALLOC;
+GtkWidget *xfce_clock_analog_new           (ClockTime           *time) G_GNUC_MALLOC;
 
 G_END_DECLS
 
diff --git a/plugins/clock/clock-binary.c b/plugins/clock/clock-binary.c
index c6d26ce..4751c51 100644
--- a/plugins/clock/clock-binary.c
+++ b/plugins/clock/clock-binary.c
@@ -20,9 +20,6 @@
 #include <config.h>
 #endif
 
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
 #ifdef HAVE_MATH_H
 #include <math.h>
 #endif
@@ -31,6 +28,7 @@
 #include <cairo/cairo.h>
 
 #include "clock.h"
+#include "clock-time.h"
 #include "clock-binary.h"
 
 
@@ -46,7 +44,9 @@ static void      xfce_clock_binary_get_property  (GObject              *object,
 static void      xfce_clock_binary_finalize      (GObject              *object);
 static gboolean  xfce_clock_binary_expose_event  (GtkWidget            *widget,
                                                   GdkEventExpose       *event);
-static gboolean  xfce_clock_binary_update        (gpointer              user_data);
+static gboolean  xfce_clock_binary_update        (XfceClockBinary      *binary,
+                                                  ClockTime            *time);
+
 
 
 
@@ -70,12 +70,14 @@ struct _XfceClockBinary
 {
   GtkImage  __parent__;
 
-  ClockPluginTimeout *timeout;
+  ClockTimeTimeout *timeout;
 
   guint     show_seconds : 1;
   guint     true_binary : 1;
   guint     show_inactive : 1;
   guint     show_grid : 1;
+
+  ClockTime *time;
 };
 
 
@@ -152,9 +154,6 @@ xfce_clock_binary_init (XfceClockBinary *binary)
   binary->show_inactive = TRUE;
   binary->show_grid = FALSE;
 
-  binary->timeout = clock_plugin_timeout_new (CLOCK_INTERVAL_MINUTE,
-                                              xfce_clock_binary_update,
-                                              binary);
 }
 
 
@@ -196,7 +195,7 @@ xfce_clock_binary_set_property (GObject      *object,
     }
 
   /* reschedule the timeout and resize */
-  clock_plugin_timeout_set_interval (binary->timeout,
+  clock_time_timeout_set_interval (binary->timeout,
       binary->show_seconds ? CLOCK_INTERVAL_SECOND : CLOCK_INTERVAL_MINUTE);
   gtk_widget_queue_resize (GTK_WIDGET (binary));
 }
@@ -250,7 +249,7 @@ static void
 xfce_clock_binary_finalize (GObject *object)
 {
   /* stop the timeout */
-  clock_plugin_timeout_free (XFCE_CLOCK_BINARY (object)->timeout);
+  clock_time_timeout_free (XFCE_CLOCK_BINARY (object)->timeout);
 
   (*G_OBJECT_CLASS (xfce_clock_binary_parent_class)->finalize) (object);
 }
@@ -263,7 +262,7 @@ xfce_clock_binary_expose_event_true_binary (XfceClockBinary *binary,
                                             GtkAllocation   *alloc)
 {
   GdkColor    *active, *inactive;
-  struct tm    tm;
+  GDateTime   *time;
   gint         row, rows;
   static gint  binary_table[] = { 32, 16, 8, 4, 2, 1 };
   gint         col, cols = G_N_ELEMENTS (binary_table);
@@ -283,7 +282,7 @@ xfce_clock_binary_expose_event_true_binary (XfceClockBinary *binary,
       active = &(GTK_WIDGET (binary)->style->dark[GTK_STATE_SELECTED]);
     }
 
-  clock_plugin_get_localtime (&tm);
+  time = clock_time_get_time (binary->time);
 
   /* init sizes */
   remain_h = alloc->height;
@@ -294,11 +293,11 @@ xfce_clock_binary_expose_event_true_binary (XfceClockBinary *binary,
     {
       /* get the time this row represents */
       if (row == 0)
-        ticks = tm.tm_hour;
+        ticks = g_date_time_get_hour (time);
       else if (row == 1)
-        ticks = tm.tm_min;
+        ticks = g_date_time_get_minute (time);
       else
-        ticks = tm.tm_sec;
+        ticks = g_date_time_get_second (time);
 
       /* reset sizes */
       remain_w = alloc->width;
@@ -336,6 +335,8 @@ xfce_clock_binary_expose_event_true_binary (XfceClockBinary *binary,
       /* advance offset */
       offset_y += h;
     }
+
+  g_date_time_unref (time);
 }
 
 
@@ -347,7 +348,7 @@ xfce_clock_binary_expose_event_binary (XfceClockBinary *binary,
 {
   GdkColor    *active, *inactive;
   static gint  binary_table[] = { 80, 40, 20, 10, 8, 4, 2, 1 };
-  struct tm    tm;
+  GDateTime   *time;
   gint         row, rows = G_N_ELEMENTS (binary_table) / 2;
   gint         col, cols;
   gint         digit;
@@ -367,7 +368,7 @@ xfce_clock_binary_expose_event_binary (XfceClockBinary *binary,
       active = &(GTK_WIDGET (binary)->style->dark[GTK_STATE_SELECTED]);
     }
 
-  clock_plugin_get_localtime (&tm);
+  time = clock_time_get_time (binary->time);
 
   remain_w = alloc->width;
   offset_x = alloc->x;
@@ -378,11 +379,11 @@ xfce_clock_binary_expose_event_binary (XfceClockBinary *binary,
     {
       /* get the time this row represents */
       if (col == 0)
-        ticks = tm.tm_hour;
+        ticks = g_date_time_get_hour (time);
       else if (col == 2)
-        ticks = tm.tm_min;
+        ticks = g_date_time_get_minute (time);
       else if (col == 4)
-        ticks = tm.tm_sec;
+        ticks = g_date_time_get_second (time);
 
       /* reset sizes */
       remain_h = alloc->height;
@@ -518,11 +519,12 @@ xfce_clock_binary_expose_event (GtkWidget      *widget,
 
 
 static gboolean
-xfce_clock_binary_update (gpointer user_data)
+xfce_clock_binary_update (XfceClockBinary     *binary,
+                          ClockTime           *time)
 {
-  GtkWidget *widget = GTK_WIDGET (user_data);
+  GtkWidget *widget = GTK_WIDGET (binary);
 
-  panel_return_val_if_fail (XFCE_CLOCK_IS_BINARY (user_data), FALSE);
+  panel_return_val_if_fail (XFCE_CLOCK_IS_BINARY (binary), FALSE);
 
   /* update if the widget if visible */
   if (G_LIKELY (GTK_WIDGET_VISIBLE (widget)))
@@ -534,7 +536,15 @@ xfce_clock_binary_update (gpointer user_data)
 
 
 GtkWidget *
-xfce_clock_binary_new (void)
+xfce_clock_binary_new (ClockTime *time)
 {
-  return g_object_new (XFCE_CLOCK_TYPE_BINARY, NULL);
+  XfceClockBinary *binary = g_object_new (XFCE_CLOCK_TYPE_BINARY, NULL);
+
+  binary->time = time;
+  binary->timeout = clock_time_timeout_new (CLOCK_INTERVAL_MINUTE,
+                                            binary->time,
+                                            G_CALLBACK (xfce_clock_binary_update), binary);
+
+  return GTK_WIDGET (binary);
 }
+
diff --git a/plugins/clock/clock-binary.h b/plugins/clock/clock-binary.h
index aa8b416..53d4368 100644
--- a/plugins/clock/clock-binary.h
+++ b/plugins/clock/clock-binary.h
@@ -35,7 +35,7 @@ GType      xfce_clock_binary_get_type      (void) G_GNUC_CONST;
 
 void       xfce_clock_binary_register_type (XfcePanelTypeModule *type_module);
 
-GtkWidget *xfce_clock_binary_new           (void) G_GNUC_MALLOC;
+GtkWidget *xfce_clock_binary_new           (ClockTime           *time) G_GNUC_MALLOC;
 
 G_END_DECLS
 
diff --git a/plugins/clock/clock-digital.c b/plugins/clock/clock-digital.c
index 03eec54..c293ed2 100644
--- a/plugins/clock/clock-digital.c
+++ b/plugins/clock/clock-digital.c
@@ -20,13 +20,10 @@
 #include <config.h>
 #endif
 
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
-
 #include <gtk/gtk.h>
 
 #include "clock.h"
+#include "clock-time.h"
 #include "clock-digital.h"
 
 
@@ -40,7 +37,9 @@ static void     xfce_clock_digital_get_property (GObject               *object,
                                                  GValue                *value,
                                                  GParamSpec            *pspec);
 static void     xfce_clock_digital_finalize     (GObject               *object);
-static gboolean xfce_clock_digital_update       (gpointer               user_data);
+static gboolean xfce_clock_digital_update       (XfceClockDigital      *digital,
+                                                 ClockTime             *time);
+
 
 
 
@@ -61,7 +60,8 @@ struct _XfceClockDigital
 {
   GtkLabel __parent__;
 
-  ClockPluginTimeout *timeout;
+  ClockTime          *time;
+  ClockTimeTimeout   *timeout;
 
   gchar *format;
 };
@@ -111,9 +111,6 @@ static void
 xfce_clock_digital_init (XfceClockDigital *digital)
 {
   digital->format = g_strdup (DEFAULT_DIGITAL_FORMAT);
-  digital->timeout = clock_plugin_timeout_new (clock_plugin_interval_from_format (digital->format),
-                                               xfce_clock_digital_update,
-                                               digital);
 
   gtk_label_set_justify (GTK_LABEL (digital), GTK_JUSTIFY_CENTER);
 }
@@ -147,9 +144,9 @@ xfce_clock_digital_set_property (GObject      *object,
     }
 
   /* reschedule the timeout and redraw */
-  clock_plugin_timeout_set_interval (digital->timeout,
-      clock_plugin_interval_from_format (digital->format));
-  xfce_clock_digital_update (digital);
+  clock_time_timeout_set_interval (digital->timeout,
+      clock_time_interval_from_format (digital->format));
+  xfce_clock_digital_update (digital, digital->time);
 }
 
 
@@ -186,7 +183,7 @@ xfce_clock_digital_finalize (GObject *object)
   XfceClockDigital *digital = XFCE_CLOCK_DIGITAL (object);
 
   /* stop the timeout */
-  clock_plugin_timeout_free (digital->timeout);
+  clock_time_timeout_free (digital->timeout);
 
   g_free (digital->format);
 
@@ -196,19 +193,16 @@ xfce_clock_digital_finalize (GObject *object)
 
 
 static gboolean
-xfce_clock_digital_update (gpointer user_data)
+xfce_clock_digital_update (XfceClockDigital *digital,
+                           ClockTime        *time)
 {
-  XfceClockDigital *digital = XFCE_CLOCK_DIGITAL (user_data);
   gchar            *string;
-  struct tm         tm;
 
   panel_return_val_if_fail (XFCE_CLOCK_IS_DIGITAL (digital), FALSE);
-
-  /* get the local time */
-  clock_plugin_get_localtime (&tm);
+  panel_return_val_if_fail (XFCE_IS_CLOCK_TIME (time), FALSE);
 
   /* set time string */
-  string = clock_plugin_strdup_strftime (digital->format, &tm);
+  string = clock_time_strdup_strftime (digital->time, digital->format);
   gtk_label_set_markup (GTK_LABEL (digital), string);
   g_free (string);
 
@@ -218,7 +212,14 @@ xfce_clock_digital_update (gpointer user_data)
 
 
 GtkWidget *
-xfce_clock_digital_new (void)
+xfce_clock_digital_new (ClockTime *time)
 {
-  return g_object_new (XFCE_CLOCK_TYPE_DIGITAL, NULL);
+  XfceClockDigital *digital = g_object_new (XFCE_CLOCK_TYPE_DIGITAL, NULL);
+
+  digital->time = time;
+  digital->timeout = clock_time_timeout_new (clock_time_interval_from_format (digital->format),
+                                             digital->time,
+                                             G_CALLBACK (xfce_clock_digital_update), digital);
+
+  return GTK_WIDGET (digital);
 }
diff --git a/plugins/clock/clock-digital.h b/plugins/clock/clock-digital.h
index 02ba782..f8d4771 100644
--- a/plugins/clock/clock-digital.h
+++ b/plugins/clock/clock-digital.h
@@ -37,7 +37,7 @@ GType      xfce_clock_digital_get_type      (void) G_GNUC_CONST;
 
 void       xfce_clock_digital_register_type (XfcePanelTypeModule *type_module);
 
-GtkWidget *xfce_clock_digital_new           (void) G_GNUC_MALLOC;
+GtkWidget *xfce_clock_digital_new           (ClockTime           *time) G_GNUC_MALLOC;
 
 G_END_DECLS
 
diff --git a/plugins/clock/clock-fuzzy.c b/plugins/clock/clock-fuzzy.c
index 358ee6f..7b0aa41 100644
--- a/plugins/clock/clock-fuzzy.c
+++ b/plugins/clock/clock-fuzzy.c
@@ -20,9 +20,6 @@
 #include <config.h>
 #endif
 
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
@@ -31,6 +28,7 @@
 #include <exo/exo.h>
 
 #include "clock.h"
+#include "clock-time.h"
 #include "clock-fuzzy.h"
 
 
@@ -44,7 +42,9 @@ static void     xfce_clock_fuzzy_get_property (GObject               *object,
                                                GValue                *value,
                                                GParamSpec            *pspec);
 static void     xfce_clock_fuzzy_finalize     (GObject               *object);
-static gboolean xfce_clock_fuzzy_update       (gpointer               user_data);
+static gboolean xfce_clock_fuzzy_update       (XfceClockFuzzy        *fuzzy,
+                                               ClockTime             *time);
+
 
 
 
@@ -76,9 +76,11 @@ struct _XfceClockFuzzy
 {
   GtkLabel __parent__;
 
-  ClockPluginTimeout *timeout;
+  ClockTimeTimeout   *timeout;
 
   guint               fuzziness;
+
+  ClockTime          *time;
 };
 
 static const gchar *i18n_day_sectors[] =
@@ -194,9 +196,6 @@ static void
 xfce_clock_fuzzy_init (XfceClockFuzzy *fuzzy)
 {
   fuzzy->fuzziness = FUZZINESS_DEFAULT;
-  fuzzy->timeout = clock_plugin_timeout_new (CLOCK_INTERVAL_MINUTE,
-                                             xfce_clock_fuzzy_update,
-                                             fuzzy);
 
   gtk_label_set_justify (GTK_LABEL (fuzzy), GTK_JUSTIFY_CENTER);
 }
@@ -225,7 +224,7 @@ xfce_clock_fuzzy_set_property (GObject      *object,
       if (G_LIKELY (fuzzy->fuzziness != fuzziness))
         {
           fuzzy->fuzziness = fuzziness;
-          xfce_clock_fuzzy_update (fuzzy);
+          xfce_clock_fuzzy_update (fuzzy, fuzzy->time);
         }
       break;
 
@@ -267,7 +266,7 @@ static void
 xfce_clock_fuzzy_finalize (GObject *object)
 {
   /* stop the timeout */
-  clock_plugin_timeout_free (XFCE_CLOCK_FUZZY (object)->timeout);
+  clock_time_timeout_free (XFCE_CLOCK_FUZZY (object)->timeout);
 
   (*G_OBJECT_CLASS (xfce_clock_fuzzy_parent_class)->finalize) (object);
 }
@@ -275,10 +274,10 @@ xfce_clock_fuzzy_finalize (GObject *object)
 
 
 static gboolean
-xfce_clock_fuzzy_update (gpointer user_data)
+xfce_clock_fuzzy_update (XfceClockFuzzy *fuzzy,
+                         ClockTime      *time)
 {
-  XfceClockFuzzy *fuzzy = XFCE_CLOCK_FUZZY (user_data);
-  struct tm       tm;
+  GDateTime      *date_time;
   gint            sector;
   gint            minute, hour;
   gchar          *string;
@@ -289,14 +288,14 @@ xfce_clock_fuzzy_update (gpointer user_data)
   panel_return_val_if_fail (XFCE_CLOCK_IS_FUZZY (fuzzy), FALSE);
 
   /* get the local time */
-  clock_plugin_get_localtime (&tm);
+  date_time = clock_time_get_time (fuzzy->time);
 
   if (fuzzy->fuzziness == FUZZINESS_5_MINS
       || fuzzy->fuzziness == FUZZINESS_15_MINS)
     {
       /* set the time */
-      minute = tm.tm_min;
-      hour = tm.tm_hour;
+      minute = g_date_time_get_minute (date_time);
+      hour = g_date_time_get_hour (date_time);
       sector = 0;
 
       /* get the hour sector */
@@ -343,8 +342,9 @@ xfce_clock_fuzzy_update (gpointer user_data)
     }
   else /* FUZZINESS_DAY */
     {
-      gtk_label_set_text (GTK_LABEL (fuzzy), _(i18n_day_sectors[tm.tm_hour / 3]));
+      gtk_label_set_text (GTK_LABEL (fuzzy), _(i18n_day_sectors[g_date_time_get_hour (date_time) / 3]));
     }
+  g_date_time_unref (date_time);
 
   return TRUE;
 }
@@ -353,7 +353,14 @@ xfce_clock_fuzzy_update (gpointer user_data)
 
 
 GtkWidget *
-xfce_clock_fuzzy_new (void)
+xfce_clock_fuzzy_new (ClockTime *time)
 {
-  return g_object_new (XFCE_CLOCK_TYPE_FUZZY, NULL);
+  XfceClockFuzzy *fuzzy = g_object_new (XFCE_CLOCK_TYPE_FUZZY, NULL);
+
+  fuzzy->time = time;
+  fuzzy->timeout = clock_time_timeout_new (CLOCK_INTERVAL_MINUTE,
+                                           fuzzy->time,
+                                           G_CALLBACK (xfce_clock_fuzzy_update), fuzzy);
+
+  return GTK_WIDGET (fuzzy);
 }
diff --git a/plugins/clock/clock-fuzzy.h b/plugins/clock/clock-fuzzy.h
index 0b92095..2fb71de 100644
--- a/plugins/clock/clock-fuzzy.h
+++ b/plugins/clock/clock-fuzzy.h
@@ -35,7 +35,7 @@ GType      xfce_clock_fuzzy_get_type      (void) G_GNUC_CONST;
 
 void       xfce_clock_fuzzy_register_type (XfcePanelTypeModule *type_module);
 
-GtkWidget *xfce_clock_fuzzy_new           (void) G_GNUC_MALLOC;
+GtkWidget *xfce_clock_fuzzy_new           (ClockTime           *time) G_GNUC_MALLOC;
 
 G_END_DECLS
 
diff --git a/plugins/clock/clock-lcd.c b/plugins/clock/clock-lcd.c
index b618cf6..84e74e6 100644
--- a/plugins/clock/clock-lcd.c
+++ b/plugins/clock/clock-lcd.c
@@ -28,6 +28,7 @@
 #include <cairo/cairo.h>
 
 #include "clock.h"
+#include "clock-time.h"
 #include "clock-lcd.h"
 
 #define RELATIVE_SPACE (0.10)
@@ -57,7 +58,9 @@ static gdouble   xfce_clock_lcd_draw_digit   (cairo_t           *cr,
                                               gdouble            size,
                                               gdouble            offset_x,
                                               gdouble            offset_y);
-static gboolean  xfce_clock_lcd_update       (gpointer           user_data);
+static gboolean  xfce_clock_lcd_update       (XfceClockLcd      *lcd,
+                                              ClockTime         *time);
+
 
 
 
@@ -81,12 +84,14 @@ struct _XfceClockLcd
 {
   GtkImage __parent__;
 
-  ClockPluginTimeout *timeout;
+  ClockTimeTimeout   *timeout;
 
   guint               show_seconds : 1;
   guint               show_military : 1; /* 24-hour clock */
   guint               show_meridiem : 1; /* am/pm */
   guint               flash_separators : 1;
+
+  ClockTime          *time;
 };
 
 typedef struct
@@ -169,9 +174,6 @@ xfce_clock_lcd_init (XfceClockLcd *lcd)
   lcd->show_meridiem = FALSE;
   lcd->show_military = TRUE;
   lcd->flash_separators = FALSE;
-  lcd->timeout = clock_plugin_timeout_new (CLOCK_INTERVAL_MINUTE,
-                                           xfce_clock_lcd_update,
-                                           lcd);
 }
 
 
@@ -215,7 +217,7 @@ xfce_clock_lcd_set_property (GObject      *object,
 
   /* reschedule the timeout and resize */
   show_seconds = lcd->show_seconds || lcd->flash_separators;
-  clock_plugin_timeout_set_interval (lcd->timeout,
+  clock_time_timeout_set_interval (lcd->timeout,
       show_seconds ? CLOCK_INTERVAL_SECOND : CLOCK_INTERVAL_MINUTE);
   gtk_widget_queue_resize (GTK_WIDGET (lcd));
 }
@@ -266,7 +268,7 @@ static void
 xfce_clock_lcd_finalize (GObject *object)
 {
   /* stop the timeout */
-  clock_plugin_timeout_free (XFCE_CLOCK_LCD (object)->timeout);
+  clock_time_timeout_free (XFCE_CLOCK_LCD (object)->timeout);
 
   (*G_OBJECT_CLASS (xfce_clock_lcd_parent_class)->finalize) (object);
 }
@@ -283,7 +285,7 @@ xfce_clock_lcd_expose_event (GtkWidget      *widget,
   gint          ticks, i;
   gdouble       size;
   gdouble       ratio;
-  struct tm     tm;
+  GDateTime    *time;
 
   panel_return_val_if_fail (XFCE_CLOCK_IS_LCD (lcd), FALSE);
 
@@ -315,10 +317,10 @@ xfce_clock_lcd_expose_event (GtkWidget      *widget,
       cairo_set_line_width (cr, MAX (size * 0.05, 1.5));
 
       /* get the local time */
-      clock_plugin_get_localtime (&tm);
+      time = clock_time_get_time (lcd->time);
 
       /* draw the hours */
-      ticks = tm.tm_hour;
+      ticks = g_date_time_get_hour (time);
 
       /* convert 24h clock to 12h clock */
       if (!lcd->show_military && ticks > 12)
@@ -331,8 +333,8 @@ xfce_clock_lcd_expose_event (GtkWidget      *widget,
        * because we might miss the exact second (due to slightly delayed
        * timeout) we queue a resize the first 3 seconds or anything in
        * the first minute */
-      if ((ticks == 10 || ticks == 0) && tm.tm_min == 0
-          && (!lcd->show_seconds || tm.tm_sec < 3))
+      if ((ticks == 10 || ticks == 0) && g_date_time_get_minute (time) == 0
+          && (!lcd->show_seconds || g_date_time_get_second (time) < 3))
         g_object_notify (G_OBJECT (lcd), "size-ratio");
 
       if (ticks >= 10)
@@ -350,7 +352,7 @@ xfce_clock_lcd_expose_event (GtkWidget      *widget,
           if (i == 0)
             {
               /* get the minutes */
-              ticks = tm.tm_min;
+              ticks = g_date_time_get_minute (time);
             }
           else
             {
@@ -359,11 +361,11 @@ xfce_clock_lcd_expose_event (GtkWidget      *widget,
                 break;
 
               /* get the seconds */
-              ticks = tm.tm_sec;
+              ticks = g_date_time_get_second (time);
             }
 
           /* draw the dots */
-          if (lcd->flash_separators && (tm.tm_sec % 2) == 1)
+          if (lcd->flash_separators && (g_date_time_get_second (time) % 2) == 1)
             offset_x += size * RELATIVE_SPACE * 2;
           else
             offset_x = xfce_clock_lcd_draw_dots (cr, size, offset_x, offset_y);
@@ -378,13 +380,14 @@ xfce_clock_lcd_expose_event (GtkWidget      *widget,
       if (lcd->show_meridiem)
         {
           /* am or pm? */
-          ticks = tm.tm_hour >= 12 ? 11 : 10;
+          ticks = g_date_time_get_hour (time) >= 12 ? 11 : 10;
 
           /* draw the digit */
           offset_x = xfce_clock_lcd_draw_digit (cr, ticks, size, offset_x, offset_y);
         }
 
       /* drop the pushed group */
+      g_date_time_unref (time);
       cairo_pop_group_to_source (cr);
       cairo_paint (cr);
       cairo_destroy (cr);
@@ -398,17 +401,18 @@ xfce_clock_lcd_expose_event (GtkWidget      *widget,
 static gdouble
 xfce_clock_lcd_get_ratio (XfceClockLcd *lcd)
 {
-  gdouble   ratio;
-  gint      ticks;
-  struct tm tm;
+  gdouble    ratio;
+  gint       ticks;
+  GDateTime *time;
 
   /* get the local time */
-  clock_plugin_get_localtime (&tm);
+  time = clock_time_get_time (lcd->time);
 
   /* 8:8(space)8 */
   ratio = (3 * RELATIVE_DIGIT) + RELATIVE_DOTS + RELATIVE_SPACE;
 
-  ticks = tm.tm_hour;
+  ticks = g_date_time_get_hour (time);
+  g_date_time_unref (time);
 
   if (!lcd->show_military && ticks > 12)
     ticks -= 12;
@@ -579,11 +583,12 @@ xfce_clock_lcd_draw_digit (cairo_t *cr,
 
 
 static gboolean
-xfce_clock_lcd_update (gpointer user_data)
+xfce_clock_lcd_update (XfceClockLcd *lcd,
+                       ClockTime    *time)
 {
-  GtkWidget *widget = GTK_WIDGET (user_data);
+  GtkWidget *widget = GTK_WIDGET (lcd);
 
-  panel_return_val_if_fail (XFCE_CLOCK_IS_LCD (user_data), FALSE);
+  panel_return_val_if_fail (XFCE_CLOCK_IS_LCD (lcd), FALSE);
 
   /* update if the widget if visible */
   if (G_LIKELY (GTK_WIDGET_VISIBLE (widget)))
@@ -595,7 +600,14 @@ xfce_clock_lcd_update (gpointer user_data)
 
 
 GtkWidget *
-xfce_clock_lcd_new (void)
+xfce_clock_lcd_new (ClockTime *time)
 {
-  return g_object_new (XFCE_CLOCK_TYPE_LCD, NULL);
+  XfceClockLcd *lcd = g_object_new (XFCE_CLOCK_TYPE_LCD, NULL);
+
+  lcd->time = time;
+  lcd->timeout = clock_time_timeout_new (CLOCK_INTERVAL_MINUTE,
+                                         lcd->time,
+                                         G_CALLBACK (xfce_clock_lcd_update), lcd);
+
+  return GTK_WIDGET (lcd);
 }
diff --git a/plugins/clock/clock-lcd.h b/plugins/clock/clock-lcd.h
index 2850b9b..46d01e0 100644
--- a/plugins/clock/clock-lcd.h
+++ b/plugins/clock/clock-lcd.h
@@ -35,7 +35,7 @@ GType      xfce_clock_lcd_get_type      (void) G_GNUC_CONST;
 
 void       xfce_clock_lcd_register_type (XfcePanelTypeModule *type_module);
 
-GtkWidget *xfce_clock_lcd_new           (void) G_GNUC_MALLOC;
+GtkWidget *xfce_clock_lcd_new           (ClockTime           *time) G_GNUC_MALLOC;
 
 G_END_DECLS
 
diff --git a/plugins/clock/clock-time.c b/plugins/clock/clock-time.c
new file mode 100644
index 0000000..df7cd6b
--- /dev/null
+++ b/plugins/clock/clock-time.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2013      Andrzej <ndrwrdck at gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include <glib.h>
+#include <exo/exo.h>
+
+#include "clock-time.h"
+#include "clock.h"
+
+static void                 clock_time_finalize       (GObject          *object);
+static void                 clock_time_get_property   (GObject          *object,
+                                                       guint             prop_id,
+                                                       GValue           *value,
+                                                       GParamSpec       *pspec);
+static void                 clock_time_set_property   (GObject          *object,
+                                                       guint             prop_id,
+                                                       const GValue     *value,
+                                                       GParamSpec       *pspec);
+
+
+
+#define DEFAULT_TIMEZONE ""
+
+enum
+{
+  PROP_0,
+  PROP_TIMEZONE
+};
+
+struct _ClockTimeClass
+{
+  GObjectClass        __parent__;
+};
+
+struct _ClockTime
+{
+  GObject             __parent__;
+
+  gchar              *timezone_name;
+  GTimeZone          *timezone;
+};
+
+struct _ClockTimeTimeout
+{
+  guint       interval;
+  guint       timeout_id;
+  guint       restart : 1;
+  ClockTime  *time;
+  guint       time_changed_id;
+};
+
+enum
+{
+  TIME_CHANGED,
+  LAST_SIGNAL
+};
+
+static guint clock_time_signals[LAST_SIGNAL] = { 0, };
+
+
+G_DEFINE_TYPE (ClockTime, clock_time, G_TYPE_OBJECT)
+
+
+
+static void
+clock_time_class_init (ClockTimeClass *klass)
+{
+  GObjectClass      *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = clock_time_finalize;
+  gobject_class->get_property = clock_time_get_property;
+  gobject_class->set_property = clock_time_set_property;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_TIMEZONE,
+                                   g_param_spec_string ("timezone",
+                                                        NULL, NULL,
+                                                        DEFAULT_TIMEZONE,
+                                                        EXO_PARAM_READWRITE));
+
+  clock_time_signals[TIME_CHANGED] =
+    g_signal_new (g_intern_static_string ("time-changed"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+}
+
+
+
+static void
+clock_time_init (ClockTime *time)
+{
+  time->timezone_name = g_strdup (DEFAULT_TIMEZONE);
+  time->timezone = g_time_zone_new_local ();
+}
+
+
+
+static void
+clock_time_finalize (GObject *object)
+{
+  ClockTime *time = XFCE_CLOCK_TIME (object);
+
+  g_free (time->timezone_name);
+
+  g_time_zone_unref (time->timezone);
+
+  G_OBJECT_CLASS (clock_time_parent_class)->finalize (object);
+}
+
+
+
+static void
+clock_time_get_property (GObject    *object,
+                         guint       prop_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
+{
+  ClockTime *time = XFCE_CLOCK_TIME (object);
+
+  switch (prop_id)
+    {
+    case PROP_TIMEZONE:
+      g_value_set_string (value, time->timezone_name);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+
+static void
+clock_time_set_property (GObject      *object,
+                         guint         prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+  ClockTime     *time = XFCE_CLOCK_TIME (object);
+  const gchar   *str_value;
+
+  switch (prop_id)
+    {
+    case PROP_TIMEZONE:
+      str_value = g_value_get_string (value);
+      if (g_strcmp0 (time->timezone_name, str_value) != 0)
+        {
+          g_free (time->timezone_name);
+          g_time_zone_unref (time->timezone);
+          if (str_value == NULL || g_strcmp0 (str_value, "") == 0)
+            {
+              time->timezone_name = g_strdup (DEFAULT_TIMEZONE);
+              time->timezone = g_time_zone_new_local ();
+            }
+          else
+            {
+              time->timezone_name = g_strdup (str_value);
+              time->timezone = g_time_zone_new (str_value);
+            }
+
+          g_signal_emit (G_OBJECT (time), clock_time_signals[TIME_CHANGED], 0);
+        }
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+
+GDateTime *
+clock_time_get_time (ClockTime *time)
+{
+  GDateTime *date_time;
+
+  panel_return_val_if_fail (XFCE_IS_CLOCK_TIME (time), NULL);
+
+  if (time->timezone != NULL)
+    date_time = g_date_time_new_now (time->timezone);
+  else
+    date_time = g_date_time_new_now_local ();
+
+  return date_time;
+}
+
+
+
+gchar *
+clock_time_strdup_strftime (ClockTime       *time,
+                            const gchar     *format)
+{
+  GDateTime *date_time;
+  gchar     *str;
+
+  panel_return_val_if_fail (XFCE_IS_CLOCK_TIME (time), NULL);
+
+  date_time = clock_time_get_time (time);
+  str = g_date_time_format (date_time, format);
+
+  g_date_time_unref (date_time);
+
+  return str;
+}
+
+
+
+guint
+clock_time_interval_from_format (const gchar *format)
+{
+  const gchar *p;
+
+  if (G_UNLIKELY (exo_str_is_empty (format)))
+      return CLOCK_INTERVAL_MINUTE;
+
+  for (p = format; *p != '\0'; ++p)
+    {
+      if (p[0] == '%' && p[1] != '\0')
+        {
+          switch (*++p)
+            {
+            case 'c':
+            case 'N':
+            case 'r':
+            case 's':
+            case 'S':
+            case 'T':
+            case 'X':
+              return CLOCK_INTERVAL_SECOND;
+            }
+        }
+    }
+
+  return CLOCK_INTERVAL_MINUTE;
+}
+
+
+
+static gboolean
+clock_time_timeout_running (gpointer user_data)
+{
+  ClockTimeTimeout *timeout = user_data;
+  GDateTime        *time;
+
+  g_signal_emit (G_OBJECT (timeout->time), clock_time_signals[TIME_CHANGED], 0);
+
+  /* check if the timeout still runs in time if updating once a minute */
+  if (timeout->interval == CLOCK_INTERVAL_MINUTE)
+    {
+      /* sync again when we don't run on time */
+      time = clock_time_get_time (timeout->time);
+      timeout->restart = (g_date_time_get_second (time) != 0);
+    }
+
+  return !timeout->restart;
+}
+
+
+
+static void
+clock_time_timeout_destroyed (gpointer user_data)
+{
+  ClockTimeTimeout *timeout = user_data;
+
+  timeout->timeout_id = 0;
+
+  if (G_UNLIKELY (timeout->restart))
+    clock_time_timeout_set_interval (timeout, timeout->interval);
+}
+
+
+
+static gboolean
+clock_time_timeout_sync (gpointer user_data)
+{
+  ClockTimeTimeout *timeout = user_data;
+
+  g_signal_emit (G_OBJECT (timeout->time), clock_time_signals[TIME_CHANGED], 0);
+
+  /* start the real timeout */
+  timeout->timeout_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, timeout->interval,
+                                                    clock_time_timeout_running, timeout,
+                                                    clock_time_timeout_destroyed);
+
+  /* stop the sync timeout */
+  return FALSE;
+}
+
+
+
+ClockTimeTimeout *
+clock_time_timeout_new (guint       interval,
+                        ClockTime  *time,
+                        GCallback   c_handler,
+                        gpointer    gobject)
+{
+  ClockTimeTimeout *timeout;
+
+  panel_return_val_if_fail (XFCE_IS_CLOCK_TIME (time), NULL);
+
+  panel_return_val_if_fail (interval > 0, NULL);
+
+  timeout = g_slice_new0 (ClockTimeTimeout);
+  timeout->interval = 0;
+  timeout->timeout_id = 0;
+  timeout->restart = FALSE;
+  timeout->time = time;
+
+  timeout->time_changed_id =
+    g_signal_connect_swapped (G_OBJECT (time), "time-changed",
+                              c_handler, gobject);
+
+  g_object_ref (G_OBJECT (timeout->time));
+
+  clock_time_timeout_set_interval (timeout, interval);
+
+  return timeout;
+}
+
+
+
+void
+clock_time_timeout_set_interval (ClockTimeTimeout *timeout,
+                                 guint             interval)
+{
+  GDateTime *time;
+  guint      next_interval;
+  gboolean   restart = timeout->restart;
+
+  panel_return_if_fail (timeout != NULL);
+  panel_return_if_fail (interval > 0);
+
+  /* leave if nothing changed and we're not restarting */
+  if (!restart && timeout->interval == interval)
+    return;
+  timeout->interval = interval;
+  timeout->restart = FALSE;
+
+  /* stop running timeout */
+  if (G_LIKELY (timeout->timeout_id != 0))
+    g_source_remove (timeout->timeout_id);
+  timeout->timeout_id = 0;
+
+  /* run function when not restarting */
+  if (!restart)
+    g_signal_emit (G_OBJECT (timeout->time), clock_time_signals[TIME_CHANGED], 0);
+
+  /* get the seconds to the next internal */
+  if (interval == CLOCK_INTERVAL_MINUTE)
+    {
+      time = clock_time_get_time (timeout->time);
+      next_interval = 60 - g_date_time_get_second (time);
+    }
+  else
+    {
+      next_interval = 0;
+    }
+
+  if (next_interval > 0)
+    {
+      /* start the sync timeout */
+      timeout->timeout_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, next_interval,
+                                                        clock_time_timeout_sync,
+                                                        timeout, NULL);
+    }
+  else
+    {
+      /* directly start running the normal timeout */
+      timeout->timeout_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, interval,
+                                                        clock_time_timeout_running, timeout,
+                                                        clock_time_timeout_destroyed);
+    }
+}
+
+
+
+void
+clock_time_timeout_free (ClockTimeTimeout *timeout)
+{
+  panel_return_if_fail (timeout != NULL);
+
+  timeout->restart = FALSE;
+
+  if (timeout->time != NULL && timeout->time_changed_id != 0)
+    g_signal_handler_disconnect (timeout->time, timeout->time_changed_id);
+
+  g_object_unref (G_OBJECT (timeout->time));
+
+  if (G_LIKELY (timeout->timeout_id != 0))
+    g_source_remove (timeout->timeout_id);
+  g_slice_free (ClockTimeTimeout, timeout);
+}
+
+
+
+ClockTime *
+clock_time_new (void)
+{
+  return g_object_new (XFCE_TYPE_CLOCK_TIME, NULL);
+}
diff --git a/plugins/clock/clock-time.h b/plugins/clock/clock-time.h
new file mode 100644
index 0000000..83745d1
--- /dev/null
+++ b/plugins/clock/clock-time.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013      Andrzej <ndrwrdck at gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __CLOCK_TIME_H__
+#define __CLOCK_TIME_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define CLOCK_INTERVAL_SECOND (1)
+#define CLOCK_INTERVAL_MINUTE (60)
+
+typedef struct _ClockTime          ClockTime;
+typedef struct _ClockTimeClass     ClockTimeClass;
+typedef struct _ClockTimeTimeout   ClockTimeTimeout;
+
+#define XFCE_TYPE_CLOCK_TIME              (clock_time_get_type ())
+#define XFCE_CLOCK_TIME(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_CLOCK_TIME, ClockTime))
+#define XFCE_CLOCK_TIME_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_CLOCK_TIME, ClockTimeClass))
+#define XFCE_IS_CLOCK_TIME(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFCE_TYPE_CLOCK_TIME))
+#define XFCE_IS_CLOCK_TIME_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_CLOCK_TIME))
+#define XFCE_CLOCK_TIME_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_CLOCK_TIME, ClockTimeClass))
+
+
+
+GType               clock_time_get_type               (void) G_GNUC_CONST;
+
+ClockTime          *clock_time_new                    (void);
+
+ClockTimeTimeout   *clock_time_timeout_new            (guint                interval,
+                                                       ClockTime           *time,
+                                                       GCallback            c_handler,
+                                                       gpointer             gobject);
+
+void                clock_time_timeout_set_interval   (ClockTimeTimeout    *timeout,
+                                                       guint                interval);
+
+void                clock_time_timeout_free           (ClockTimeTimeout    *timeout);
+
+GDateTime          *clock_time_get_time               (ClockTime           *time);
+
+gchar              *clock_time_strdup_strftime        (ClockTime           *time,
+                                                       const gchar         *format);
+
+guint               clock_time_interval_from_format   (const gchar         *format);
+
+G_END_DECLS
+
+#endif /* !__CLOCK_TIME_H__ */
diff --git a/plugins/clock/clock.c b/plugins/clock/clock.c
index 10993d5..227d79b 100644
--- a/plugins/clock/clock.c
+++ b/plugins/clock/clock.c
@@ -21,9 +21,6 @@
 #include <config.h>
 #endif
 
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
 #ifdef HAVE_MATH_H
 #include <math.h>
 #endif
@@ -38,6 +35,7 @@
 #include <common/panel-utils.h>
 
 #include "clock.h"
+#include "clock-time.h"
 #include "clock-analog.h"
 #include "clock-binary.h"
 #include "clock-digital.h"
@@ -46,8 +44,6 @@
 #include "clock-dialog_ui.h"
 
 #define DEFAULT_TOOLTIP_FORMAT "%A %d %B %Y"
-#define DEFAULT_TIMEZONE ""
-
 
 
 static void     clock_plugin_get_property              (GObject               *object,
@@ -85,10 +81,6 @@ static gboolean clock_plugin_calendar_key_press_event  (GtkWidget             *c
 static void     clock_plugin_popup_calendar            (ClockPlugin           *plugin);
 static void     clock_plugin_hide_calendar             (ClockPlugin           *plugin);
 static gboolean clock_plugin_tooltip                   (gpointer               user_data);
-static gboolean clock_plugin_timeout_running           (gpointer               user_data);
-static void     clock_plugin_timeout_destroyed         (gpointer               user_data);
-static gboolean clock_plugin_timeout_sync              (gpointer               user_data);
-static void     clock_plugin_set_timezone              (ClockPlugin           *plugin);
 
 
 
@@ -98,8 +90,7 @@ enum
   PROP_MODE,
   PROP_TOOLTIP_FORMAT,
   PROP_COMMAND,
-  PROP_ROTATE_VERTICALLY,
-  PROP_TIMEZONE
+  PROP_ROTATE_VERTICALLY
 };
 
 typedef enum
@@ -137,18 +128,9 @@ struct _ClockPlugin
   guint               rotate_vertically : 1;
 
   gchar              *tooltip_format;
-  ClockPluginTimeout *tooltip_timeout;
+  ClockTimeTimeout   *tooltip_timeout;
 
-  gchar              *timezone;
-};
-
-struct _ClockPluginTimeout
-{
-  guint       interval;
-  GSourceFunc function;
-  gpointer    data;
-  guint       timeout_id;
-  guint       restart : 1;
+  ClockTime          *time;
 };
 
 typedef struct
@@ -241,13 +223,6 @@ clock_plugin_class_init (ClockPluginClass *klass)
                                    g_param_spec_string ("command",
                                                         NULL, NULL, NULL,
                                                         EXO_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-                                   PROP_TIMEZONE,
-                                   g_param_spec_string ("timezone",
-                                                        NULL, NULL,
-                                                        DEFAULT_TIMEZONE,
-                                                        EXO_PARAM_READWRITE));
 }
 
 
@@ -261,9 +236,7 @@ clock_plugin_init (ClockPlugin *plugin)
   plugin->tooltip_timeout = NULL;
   plugin->command = NULL;
   plugin->rotate_vertically = TRUE;
-  plugin->timezone = g_strdup (DEFAULT_TIMEZONE);
-
-  clock_plugin_set_timezone (plugin);
+  plugin->time = clock_time_new ();
 
   plugin->button = xfce_panel_create_toggle_button ();
   /* xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button); */
@@ -309,10 +282,6 @@ clock_plugin_get_property (GObject    *object,
       g_value_set_boolean (value, plugin->rotate_vertically);
       break;
 
-    case PROP_TIMEZONE:
-      g_value_set_string (value, plugin->timezone);
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -364,12 +333,6 @@ clock_plugin_set_property (GObject      *object,
         }
       break;
 
-    case PROP_TIMEZONE:
-      g_free (plugin->timezone);
-      plugin->timezone = g_value_dup_string (value);
-      clock_plugin_set_timezone (plugin);
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -378,24 +341,6 @@ clock_plugin_set_property (GObject      *object,
 
 
 
-static void
-clock_plugin_set_timezone (ClockPlugin *plugin)
-{
-  if (plugin->timezone == NULL || g_strcmp0 (plugin->timezone, "") == 0)
-    g_unsetenv ("TZ");
-  else
-    g_setenv ("TZ", plugin->timezone, TRUE);
-
-  tzset();
-
-  /* rather expensive way of notifying the clock widget of timezone change */
-  if (plugin->clock != NULL)
-    clock_plugin_set_mode (plugin);
-}
-
-
-
-
 static gboolean
 clock_plugin_leave_notify_event (GtkWidget        *widget,
                                  GdkEventCrossing *event,
@@ -404,7 +349,7 @@ clock_plugin_leave_notify_event (GtkWidget        *widget,
   /* stop a running tooltip timeout when we leave the widget */
   if (plugin->tooltip_timeout != NULL)
     {
-      clock_plugin_timeout_free (plugin->tooltip_timeout);
+      clock_time_timeout_free (plugin->tooltip_timeout);
       plugin->tooltip_timeout = NULL;
     }
 
@@ -423,8 +368,9 @@ clock_plugin_enter_notify_event (GtkWidget        *widget,
   /* start the tooltip timeout if needed */
   if (plugin->tooltip_timeout == NULL)
     {
-      interval = clock_plugin_interval_from_format (plugin->tooltip_format);
-      plugin->tooltip_timeout = clock_plugin_timeout_new (interval, clock_plugin_tooltip, plugin);
+      interval = clock_time_interval_from_format (plugin->tooltip_format);
+      plugin->tooltip_timeout = clock_time_timeout_new (interval, plugin->time,
+                                                        G_CALLBACK (clock_plugin_tooltip), plugin);
     }
 
   return FALSE;
@@ -486,10 +432,15 @@ clock_plugin_construct (XfcePanelPlugin *panel_plugin)
     { "tooltip-format", G_TYPE_STRING },
     { "command", G_TYPE_STRING },
     { "rotate-vertically", G_TYPE_BOOLEAN },
-    { "timezone", G_TYPE_STRING },
     { NULL }
   };
 
+  const PanelProperty  time_properties[] =
+    {
+      { "timezone", G_TYPE_STRING },
+      { NULL }
+    };
+
   /* show configure */
   xfce_panel_plugin_menu_show_configure (panel_plugin);
 
@@ -498,6 +449,10 @@ clock_plugin_construct (XfcePanelPlugin *panel_plugin)
                          xfce_panel_plugin_get_property_base (panel_plugin),
                          properties, FALSE);
 
+  panel_properties_bind (NULL, G_OBJECT (plugin->time),
+                         xfce_panel_plugin_get_property_base (panel_plugin),
+                         time_properties, FALSE);
+
   /* make sure a mode is set */
   if (plugin->mode == CLOCK_PLUGIN_MODE_DEFAULT)
     clock_plugin_set_mode (plugin);
@@ -511,7 +466,7 @@ clock_plugin_free_data (XfcePanelPlugin *panel_plugin)
   ClockPlugin *plugin = XFCE_CLOCK_PLUGIN (panel_plugin);
 
   if (plugin->tooltip_timeout != NULL)
-    clock_plugin_timeout_free (plugin->tooltip_timeout);
+    clock_time_timeout_free (plugin->tooltip_timeout);
 
   if (plugin->calendar_window != NULL)
     gtk_widget_destroy (plugin->calendar_window);
@@ -752,18 +707,19 @@ clock_plugin_configure_plugin_chooser_separator (GtkTreeModel *model,
 
 
 static void
-clock_plugin_configure_plugin_chooser_fill (GtkComboBox *combo,
+clock_plugin_configure_plugin_chooser_fill (ClockPlugin *plugin,
+                                            GtkComboBox *combo,
                                             GtkEntry    *entry,
                                             const gchar *formats[])
 {
   guint         i;
   GtkListStore *store;
   gchar        *preview;
-  struct tm     now;
   GtkTreeIter   iter;
   const gchar  *active_format;
   gboolean      has_active = FALSE;
 
+  panel_return_if_fail (XFCE_IS_CLOCK_PLUGIN (plugin));
   panel_return_if_fail (GTK_IS_COMBO_BOX (combo));
   panel_return_if_fail (GTK_IS_ENTRY (entry));
 
@@ -773,13 +729,11 @@ clock_plugin_configure_plugin_chooser_fill (GtkComboBox *combo,
   store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_STRING);
   gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
 
-  clock_plugin_get_localtime (&now);
-
   active_format = gtk_entry_get_text (entry);
 
   for (i = 0; formats[i] != NULL; i++)
     {
-      preview = clock_plugin_strdup_strftime (_(formats[i]), &now);
+      preview = clock_time_strdup_strftime (plugin->time, _(formats[i]));
       gtk_list_store_insert_with_values (store, &iter, i,
                                          COLUMN_FORMAT, _(formats[i]),
                                          COLUMN_TEXT, preview, -1);
@@ -856,13 +810,15 @@ clock_plugin_configure_plugin (XfcePanelPlugin *panel_plugin)
   exo_mutual_binding_new (G_OBJECT (plugin), "tooltip-format",
                           G_OBJECT (object), "text");
   combo = gtk_builder_get_object (builder, "tooltip-chooser");
-  clock_plugin_configure_plugin_chooser_fill (GTK_COMBO_BOX (combo),
+  clock_plugin_configure_plugin_chooser_fill (plugin,
+                                              GTK_COMBO_BOX (combo),
                                               GTK_ENTRY (object),
                                               tooltip_formats);
 
   object = gtk_builder_get_object (builder, "digital-format");
   combo = gtk_builder_get_object (builder, "digital-chooser");
-  clock_plugin_configure_plugin_chooser_fill (GTK_COMBO_BOX (combo),
+  clock_plugin_configure_plugin_chooser_fill (plugin,
+                                              GTK_COMBO_BOX (combo),
                                               GTK_ENTRY (object),
                                               digital_formats);
 
@@ -912,15 +868,16 @@ clock_plugin_set_mode (ClockPlugin *plugin)
 
   /* create a new clock */
   if (plugin->mode == CLOCK_PLUGIN_MODE_ANALOG)
-    plugin->clock = xfce_clock_analog_new ();
+    plugin->clock = xfce_clock_analog_new (plugin->time);
   else if (plugin->mode == CLOCK_PLUGIN_MODE_BINARY)
-    plugin->clock = xfce_clock_binary_new ();
+    plugin->clock = xfce_clock_binary_new (plugin->time);
   else if (plugin->mode == CLOCK_PLUGIN_MODE_DIGITAL)
-    plugin->clock = xfce_clock_digital_new ();
+    plugin->clock = xfce_clock_digital_new (plugin->time);
   else if (plugin->mode == CLOCK_PLUGIN_MODE_FUZZY)
-    plugin->clock = xfce_clock_fuzzy_new ();
+    plugin->clock = xfce_clock_fuzzy_new (plugin->time);
   else
-    plugin->clock = xfce_clock_lcd_new ();
+    plugin->clock = xfce_clock_lcd_new (plugin->time);
+
 
   if (plugin->rotate_vertically)
     {
@@ -966,16 +923,17 @@ static void
 clock_plugin_calendar_show_event (GtkWidget   *calendar_window,
                                   ClockPlugin *plugin)
 {
-  struct tm tm;
+  GDateTime *time;
 
   panel_return_if_fail (XFCE_IS_PANEL_PLUGIN (plugin));
 
   clock_plugin_reposition_calendar (plugin);
 
-  clock_plugin_get_localtime (&tm);
-  gtk_calendar_select_month (GTK_CALENDAR (plugin->calendar), tm.tm_mon,
-                             1900 + tm.tm_year);
-  gtk_calendar_select_day (GTK_CALENDAR (plugin->calendar), tm.tm_mday);
+  time = clock_time_get_time (plugin->time);
+  gtk_calendar_select_month (GTK_CALENDAR (plugin->calendar), g_date_time_get_month (time),
+                             g_date_time_get_year (time));
+  gtk_calendar_select_day (GTK_CALENDAR (plugin->calendar), g_date_time_get_day_of_month (time));
+  g_date_time_unref (time);
 }
 
 
@@ -1055,13 +1013,9 @@ clock_plugin_tooltip (gpointer user_data)
 {
   ClockPlugin *plugin = XFCE_CLOCK_PLUGIN (user_data);
   gchar       *string;
-  struct tm    tm;
-
-  /* get the local time */
-  clock_plugin_get_localtime (&tm);
 
   /* set the tooltip */
-  string = clock_plugin_strdup_strftime (plugin->tooltip_format, &tm);
+  string = clock_time_strdup_strftime (plugin->time, plugin->tooltip_format);
   gtk_widget_set_tooltip_markup (GTK_WIDGET (plugin), string);
   g_free (string);
 
@@ -1071,237 +1025,3 @@ clock_plugin_tooltip (gpointer user_data)
   /* keep the timeout running */
   return TRUE;
 }
-
-
-
-static gboolean
-clock_plugin_timeout_running (gpointer user_data)
-{
-  ClockPluginTimeout *timeout = user_data;
-  gboolean            result;
-  struct tm           tm;
-
-  GDK_THREADS_ENTER ();
-  result = (timeout->function) (timeout->data);
-  GDK_THREADS_LEAVE ();
-
-  /* check if the timeout still runs in time if updating once a minute */
-  if (result && timeout->interval == CLOCK_INTERVAL_MINUTE)
-    {
-      /* sync again when we don't run on time */
-      clock_plugin_get_localtime (&tm);
-      timeout->restart = tm.tm_sec != 0;
-    }
-
-  return result && !timeout->restart;
-}
-
-
-
-static void
-clock_plugin_timeout_destroyed (gpointer user_data)
-{
-  ClockPluginTimeout *timeout = user_data;
-
-  timeout->timeout_id = 0;
-
-  if (G_UNLIKELY (timeout->restart))
-    clock_plugin_timeout_set_interval (timeout, timeout->interval);
-}
-
-
-
-static gboolean
-clock_plugin_timeout_sync (gpointer user_data)
-{
-  ClockPluginTimeout *timeout = user_data;
-
-  /* run the user function */
-  if ((timeout->function) (timeout->data))
-    {
-      /* start the real timeout */
-      timeout->timeout_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, timeout->interval,
-                                                        clock_plugin_timeout_running, timeout,
-                                                        clock_plugin_timeout_destroyed);
-    }
-  else
-    {
-      timeout->timeout_id = 0;
-    }
-
-  /* stop the sync timeout */
-  return FALSE;
-}
-
-
-
-ClockPluginTimeout *
-clock_plugin_timeout_new (guint       interval,
-                          GSourceFunc function,
-                          gpointer    data)
-{
-  ClockPluginTimeout *timeout;
-
-  panel_return_val_if_fail (interval > 0, NULL);
-  panel_return_val_if_fail (function != NULL, NULL);
-
-  timeout = g_slice_new0 (ClockPluginTimeout);
-  timeout->interval = 0;
-  timeout->function = function;
-  timeout->data = data;
-  timeout->timeout_id = 0;
-  timeout->restart = FALSE;
-
-  clock_plugin_timeout_set_interval (timeout, interval);
-
-  return timeout;
-}
-
-
-
-void
-clock_plugin_timeout_set_interval (ClockPluginTimeout *timeout,
-                                   guint               interval)
-{
-  struct tm tm;
-  guint     next_interval;
-  gboolean  restart = timeout->restart;
-
-  panel_return_if_fail (timeout != NULL);
-  panel_return_if_fail (interval > 0);
-
-  /* leave if nothing changed and we're not restarting */
-  if (!restart && timeout->interval == interval)
-    return;
-  timeout->interval = interval;
-  timeout->restart = FALSE;
-
-  /* stop running timeout */
-  if (G_LIKELY (timeout->timeout_id != 0))
-    g_source_remove (timeout->timeout_id);
-  timeout->timeout_id = 0;
-
-  /* run function when not restarting, leave if it returns false */
-  if (!restart && !(timeout->function) (timeout->data))
-    return;
-
-  /* get the seconds to the next internal */
-  if (interval == CLOCK_INTERVAL_MINUTE)
-    {
-      clock_plugin_get_localtime (&tm);
-      next_interval = 60 - tm.tm_sec;
-    }
-  else
-    {
-      next_interval = 0;
-    }
-
-  if (next_interval > 0)
-    {
-      /* start the sync timeout */
-      timeout->timeout_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, next_interval,
-                                                        clock_plugin_timeout_sync,
-                                                        timeout, NULL);
-    }
-  else
-    {
-      /* directly start running the normal timeout */
-      timeout->timeout_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, interval,
-                                                        clock_plugin_timeout_running, timeout,
-                                                        clock_plugin_timeout_destroyed);
-    }
-}
-
-
-
-void
-clock_plugin_timeout_free (ClockPluginTimeout *timeout)
-{
-  panel_return_if_fail (timeout != NULL);
-
-  timeout->restart = FALSE;
-  if (G_LIKELY (timeout->timeout_id != 0))
-    g_source_remove (timeout->timeout_id);
-  g_slice_free (ClockPluginTimeout, timeout);
-}
-
-
-
-void
-clock_plugin_get_localtime (struct tm *tm)
-{
-  time_t now = time (NULL);
-
-#ifndef HAVE_LOCALTIME_R
-  struct tm *tmbuf;
-
-  tmbuf = localtime (&now);
-  *tm = *tmbuf;
-#else
-  localtime_r (&now, tm);
-#endif
-}
-
-
-
-gchar *
-clock_plugin_strdup_strftime (const gchar     *format,
-                              const struct tm *tm)
-{
-  gchar *converted, *result;
-  gsize  length;
-  gchar  buffer[1024];
-
-  /* leave when format is null */
-  if (G_UNLIKELY (exo_str_is_empty (format)))
-    return NULL;
-
-  /* convert to locale, because that's what strftime uses */
-  converted = g_locale_from_utf8 (format, -1, NULL, NULL, NULL);
-  if (G_UNLIKELY (converted == NULL))
-    return NULL;
-
-  /* parse the time string */
-  length = strftime (buffer, sizeof (buffer), converted, tm);
-  if (G_UNLIKELY (length == 0))
-    buffer[0] = '\0';
-
-  /* convert the string back to utf-8 */
-  result = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
-
-  /* cleanup */
-  g_free (converted);
-
-  return result;
-}
-
-
-
-guint
-clock_plugin_interval_from_format (const gchar *format)
-{
-  const gchar *p;
-
-  if (G_UNLIKELY (exo_str_is_empty (format)))
-      return CLOCK_INTERVAL_MINUTE;
-
-  for (p = format; *p != '\0'; ++p)
-    {
-      if (p[0] == '%' && p[1] != '\0')
-        {
-          switch (*++p)
-            {
-            case 'c':
-            case 'N':
-            case 'r':
-            case 's':
-            case 'S':
-            case 'T':
-            case 'X':
-              return CLOCK_INTERVAL_SECOND;
-            }
-        }
-    }
-
-  return CLOCK_INTERVAL_MINUTE;
-}
diff --git a/plugins/clock/clock.h b/plugins/clock/clock.h
index 2e27b81..937d274 100644
--- a/plugins/clock/clock.h
+++ b/plugins/clock/clock.h
@@ -46,22 +46,6 @@ GType               clock_plugin_get_type             (void) G_GNUC_CONST;
 
 void                clock_plugin_register_type        (XfcePanelTypeModule *type_module);
 
-ClockPluginTimeout *clock_plugin_timeout_new          (guint                interval,
-                                                       GSourceFunc          function,
-                                                       gpointer             data);
-
-void                clock_plugin_timeout_set_interval (ClockPluginTimeout  *timeout,
-                                                       guint                interval);
-
-void                clock_plugin_timeout_free         (ClockPluginTimeout  *timeout);
-
-void                clock_plugin_get_localtime        (struct tm           *tm);
-
-gchar              *clock_plugin_strdup_strftime      (const gchar         *format,
-                                                       const struct tm     *tm);
-
-guint               clock_plugin_interval_from_format (const gchar         *format);
-
 G_END_DECLS
 
 #endif /* !__CLOCK_H__ */


More information about the Xfce4-commits mailing list