← Back to team overview

ayatana-commits team mailing list archive

[Merge] lp:~jjardon/indicator-datetime/timer-fix-837440 into lp:indicator-datetime

 

Javier Jardón has proposed merging lp:~jjardon/indicator-datetime/timer-fix-837440 into lp:indicator-datetime.

Requested reviews:
  Indicator Applet Developers (indicator-applet-developers)
Related bugs:
  Bug #837440 in Indicator Date and Time: "Use GnomeWallClock api to implement wall clocks"
  https://bugs.launchpad.net/indicator-datetime/+bug/837440

For more details, see:
https://code.launchpad.net/~jjardon/indicator-datetime/timer-fix-837440/+merge/77594
-- 
https://code.launchpad.net/~jjardon/indicator-datetime/timer-fix-837440/+merge/77594
Your team ayatana-commits is subscribed to branch lp:indicator-datetime.
=== modified file 'configure.ac'
--- configure.ac	2011-09-15 15:37:28 +0000
+++ configure.ac	2011-09-29 19:46:26 +0000
@@ -60,6 +60,7 @@
 DBUSMENUGLIB_REQUIRED_VERSION=0.1.1
 DBUSMENUGTK_REQUIRED_VERSION=0.3.94
 GIO_REQUIRED_VERSION=2.25.11
+GSETTINGS_DESKTOP_SCHEMAS_REQUIRED=3.1.4
 INDICATOR_DISPLAY_OBJECTS=0.2.2
 GEOCLUE_REQUIRED_VERSION=0.12.0
 ECAL_REQUIRED_VERSION=2.30
@@ -74,6 +75,7 @@
 AS_IF([test "x$with_gtk" = x3],
     [PKG_CHECK_MODULES(INDICATOR, indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION
                                   glib-2.0 >= $GLIB_REQUIRED_VERSION
+                                  gsettings-desktop-schemas >= $GSETTINGS_DESKTOP_SCHEMAS_REQUIRED
                                   dbusmenu-glib-0.4 >= $DBUSMENUGLIB_REQUIRED_VERSION
                                   dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION
                                   libido3-0.1 >= $INDICATOR_DISPLAY_OBJECTS)
@@ -89,6 +91,7 @@
 )
 
 PKG_CHECK_MODULES(SERVICE, indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION
+                           gsettings-desktop-schemas >= $GSETTINGS_DESKTOP_SCHEMAS_REQUIRED
                            glib-2.0 >= $GLIB_REQUIRED_VERSION
                            dbusmenu-glib-0.4 >= $DBUSMENUGLIB_REQUIRED_VERSION
                            dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2011-09-06 14:25:34 +0000
+++ src/Makefile.am	2011-09-29 19:46:26 +0000
@@ -8,6 +8,10 @@
 	datetime-interface.c \
 	datetime-interface.h \
 	gen-datetime-service.xml.c \
+	gnome-datetime-source.c \
+	gnome-datetime-source.h \
+	gnome-wall-clock.c \
+	gnome-wall-clock.h \
 	datetime-service.c \
 	utils.c \
 	utils.h \
@@ -27,6 +31,8 @@
 libdatetime_la_SOURCES = \
 	gen-datetime-service.xml.h \
 	dbus-shared.h \
+	gnome-wall-clock.c \
+	gnome-wall-clock.h \
 	settings-shared.h \
 	utils.c \
 	utils.h \

=== modified file 'src/datetime-service.c'
--- src/datetime-service.c	2011-09-15 15:30:55 +0000
+++ src/datetime-service.c	2011-09-29 19:46:26 +0000
@@ -50,6 +50,7 @@
 
 #include "datetime-interface.h"
 #include "dbus-shared.h"
+#include "gnome-wall-clock.h"
 #include "settings-shared.h"
 #include "utils.h"
 
@@ -57,7 +58,6 @@
 static void geo_create_client (GeoclueMaster * master, GeoclueMasterClient * client, gchar * path, GError * error, gpointer user_data);
 static gboolean update_appointment_menu_items (gpointer user_data);
 static gboolean update_timezone_menu_items(gpointer user_data);
-static void setup_timer (void);
 static void geo_client_invalid (GeoclueMasterClient * client, gpointer user_data);
 static void geo_address_change (GeoclueMasterClient * client, gchar * a, gchar * b, gchar * c, gchar * d, gpointer user_data);
 static gboolean get_greeter_mode (void);
@@ -1146,7 +1146,6 @@
 	update_current_timezone();
 	datetime_interface_update(DATETIME_INTERFACE(user_data));
 	update_datetime(NULL);
-	setup_timer();
 	return;
 }
 
@@ -1156,6 +1155,8 @@
 {
 	GFile * timezonefile = g_file_new_for_path(TIMEZONE_FILE);
 	GFileMonitor * monitor = g_file_monitor_file(timezonefile, G_FILE_MONITOR_NONE, NULL, NULL);
+	g_object_unref (timezonefile);
+
 	if (monitor != NULL) {
 		g_signal_connect(G_OBJECT(monitor), "changed", G_CALLBACK(timezone_changed), dbus);
 		g_debug("Monitoring timezone file: '" TIMEZONE_FILE "'");
@@ -1165,41 +1166,12 @@
 	return;
 }
 
-/* Source ID for the timer */
-static guint timer = 0;
-
-/* Execute at a given time, update and setup a new
-   timer to go again.  */
-static gboolean
-timer_func (gpointer user_data)
-{
-	timer = 0;
-	/* Reset up each time to reduce error */
-	setup_timer();
-	update_datetime(NULL);
-	return FALSE;
-}
-
-/* Sets up the time to launch the timer to update the
-   date in the datetime entry */
 static void
-setup_timer (void)
+on_clock_changed (GnomeWallClock *clock,
+                  GParamSpec     *pspec,
+                  gpointer        user_data)
 {
-	if (timer != 0) {
-		g_source_remove(timer);
-		timer = 0;
-	}
-
-	time_t t;
-	t = time(NULL);
-	struct tm * ltime = localtime(&t);
-
-	timer = g_timeout_add_seconds(((23 - ltime->tm_hour) * 60 * 60) +
-	                              ((59 - ltime->tm_min) * 60) +
-	                              ((60 - ltime->tm_sec)) + 60 /* one minute past */,
-	                              timer_func, NULL);
-
-	return;
+	update_datetime (NULL);
 }
 
 static void
@@ -1213,7 +1185,6 @@
 		if (!idle) {
 			datetime_interface_update(DATETIME_INTERFACE(user_data));
 			update_datetime(NULL);
-			setup_timer();
 		}
 	}
 	return;
@@ -1437,6 +1408,8 @@
 int
 main (int argc, char ** argv)
 {
+	GnomeWallClock *clock;
+
 	g_type_init();
 
 	/* Acknowledging the service init and setting up the interface */
@@ -1476,7 +1449,8 @@
 	build_timezone(dbus);
 
 	/* Setup the timer */
-	setup_timer();
+	clock = g_object_new (GNOME_TYPE_WALL_CLOCK, NULL);
+	g_signal_connect (clock, "notify::clock", G_CALLBACK (on_clock_changed), NULL);
 
 	/* And watch for system resumes */
 	g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,

=== added file 'src/gnome-datetime-source.c'
--- src/gnome-datetime-source.c	1970-01-01 00:00:00 +0000
+++ src/gnome-datetime-source.c	2011-09-29 19:46:26 +0000
@@ -0,0 +1,283 @@
+/* -*- mode: C; c-file-style: "linux"; indent-tabs-mode: t -*-
+ * gdatetime-source.c - copy&paste from https://bugzilla.gnome.org/show_bug.cgi?id=655129
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@xxxxxxxxxx>
+ */
+
+#include "config.h"
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include "gnome-datetime-source.h"
+
+#ifdef HAVE_TIMERFD
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <string.h>
+#endif
+
+typedef struct _GDateTimeSource GDateTimeSource;
+struct _GDateTimeSource
+{
+	GSource     source;
+
+	gint64      real_expiration;
+	gint64      wakeup_expiration;
+
+	gboolean    cancel_on_set : 1;
+	gboolean    initially_expired : 1;
+
+	GPollFD     pollfd;
+};
+
+static inline void
+g_datetime_source_reschedule (GDateTimeSource *datetime_source,
+			      gint64                from_monotonic)
+{
+	datetime_source->wakeup_expiration = from_monotonic + G_TIME_SPAN_SECOND;
+}
+
+static gboolean
+g_datetime_source_is_expired (GDateTimeSource *datetime_source)
+{
+	gint64 real_now;
+
+	real_now = g_get_real_time ();
+
+	if (datetime_source->initially_expired)
+		return TRUE;
+
+	if (datetime_source->real_expiration <= real_now)
+		return TRUE;
+
+	/* We can't really detect without system support when things change;
+	 * so just trigger every second.
+	 */
+	if (datetime_source->cancel_on_set)
+		return TRUE;
+
+	return FALSE;
+}
+
+/* In prepare, we're just checking the monotonic time against
+ * our projected wakeup.
+ */
+static gboolean
+g_datetime_source_prepare (GSource *source,
+			   gint    *timeout)
+{
+	GDateTimeSource *datetime_source = (GDateTimeSource*)source;
+	gint64 monotonic_now;
+
+#ifdef HAVE_TIMERFD
+	if (datetime_source->pollfd.fd != -1) {
+		*timeout = -1;
+		return datetime_source->initially_expired;  /* Should be TRUE at most one time, FALSE forever after */
+	}
+#endif
+
+	monotonic_now = g_source_get_time (source);
+
+	if (monotonic_now < datetime_source->wakeup_expiration) {
+		/* Round up to ensure that we don't try again too early */
+		*timeout = (datetime_source->wakeup_expiration - monotonic_now + 999) / 1000;
+		return FALSE;
+	}
+
+	*timeout = 0;
+	return g_datetime_source_is_expired (datetime_source);
+}
+
+/* In check, we're looking at the wall clock.
+ */
+static gboolean
+g_datetime_source_check (GSource  *source)
+{
+	GDateTimeSource *datetime_source = (GDateTimeSource*)source;
+
+#ifdef HAVE_TIMERFD
+	if (datetime_source->pollfd.fd != -1)
+		return datetime_source->pollfd.revents != 0;
+#endif
+
+	if (g_datetime_source_is_expired (datetime_source))
+		return TRUE;
+
+	g_datetime_source_reschedule (datetime_source, g_source_get_time (source));
+
+	return FALSE;
+}
+
+static gboolean
+g_datetime_source_dispatch (GSource    *source,
+			    GSourceFunc callback,
+			    gpointer    user_data)
+{
+	GDateTimeSource *datetime_source = (GDateTimeSource*)source;
+
+	datetime_source->initially_expired = FALSE;
+
+	if (!callback) {
+		g_warning ("Timeout source dispatched without callback\n"
+			   "You must call g_source_set_callback().");
+		return FALSE;
+	}
+
+	(callback) (user_data);
+
+	/* Always false as this source is documented to run once */
+	return FALSE;
+}
+
+static void
+g_datetime_source_finalize (GSource *source)
+{
+#ifdef HAVE_TIMERFD
+	GDateTimeSource *datetime_source = (GDateTimeSource*)source;
+	if (datetime_source->pollfd.fd != -1)
+		close (datetime_source->pollfd.fd);
+#endif
+}
+
+static GSourceFuncs g_datetime_source_funcs = {
+	g_datetime_source_prepare,
+	g_datetime_source_check,
+	g_datetime_source_dispatch,
+	g_datetime_source_finalize
+};
+
+#ifdef HAVE_TIMERFD
+static gboolean
+g_datetime_source_init_timerfd (GDateTimeSource *datetime_source,
+				gint64           expected_now_seconds,
+				gint64           unix_seconds)
+{
+	struct itimerspec its;
+	int settime_flags;
+
+	datetime_source->pollfd.fd = timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC);
+	if (datetime_source->pollfd.fd == -1)
+		return FALSE;
+
+	memset (&its, 0, sizeof (its));
+	its.it_value.tv_sec = (time_t) unix_seconds;
+
+	/* http://article.gmane.org/gmane.linux.kernel/1132138 */
+#ifndef TFD_TIMER_CANCEL_ON_SET
+#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
+#endif
+
+	settime_flags = TFD_TIMER_ABSTIME;
+	if (datetime_source->cancel_on_set)
+		settime_flags |= TFD_TIMER_CANCEL_ON_SET;
+
+	if (timerfd_settime (datetime_source->pollfd.fd, settime_flags, &its, NULL) < 0) {
+		close (datetime_source->pollfd.fd);
+		datetime_source->pollfd.fd = -1;
+		return FALSE;
+	}
+
+	/* Now we need to check that the clock didn't go backwards before we
+	 * had the timerfd set up.  See
+	 * https://bugzilla.gnome.org/show_bug.cgi?id=655129
+	 */
+	clock_gettime (CLOCK_REALTIME, &its.it_value);
+	if (its.it_value.tv_sec < expected_now_seconds)
+		datetime_source->initially_expired = TRUE;
+
+	datetime_source->pollfd.events = G_IO_IN;
+
+	g_source_add_poll ((GSource*) datetime_source, &datetime_source->pollfd);
+
+	return TRUE;
+}
+#endif
+
+/**
+ * _gnome_date_time_source_new:
+ * @now: The expected current time
+ * @expiry: Time to await
+ * @cancel_on_set: Also invoke callback if the system clock changes discontiguously
+ *
+ * This function is designed for programs that want to schedule an
+ * event based on real (wall clock) time, as returned by
+ * g_get_real_time().  For example, HOUR:MINUTE wall-clock displays
+ * and calendaring software.  The callback will be invoked when the
+ * specified wall clock time @expiry is reached.  This includes
+ * events such as the system clock being set past the given time.
+ *
+ * Compare versus g_timeout_source_new() which is defined to use
+ * monotonic time as returned by g_get_monotonic_time().
+ *
+ * The parameter @now is necessary to avoid a race condition in
+ * between getting the current time and calling this function.
+ *
+ * If @cancel_on_set is given, the callback will also be invoked at
+ * most a second after the system clock is changed.  This includes
+ * being set backwards or forwards, and system
+ * resume from suspend.  Not all operating systems allow detecting all
+ * relevant events efficiently - this function may cause the process
+ * to wake up once a second in those cases.
+ *
+ * A wall clock display should use @cancel_on_set; a calendaring
+ * program shouldn't need to.
+ *
+ * Note that the return value from the associated callback will be
+ * ignored; this is a one time watch.
+ *
+ * <note><para>This function currently does not detect time zone
+ * changes.  On Linux, your program should also monitor the
+ * <literal>/etc/timezone</literal> file using
+ * #GFileMonitor.</para></note>
+ *
+ * <example id="gdatetime-example-watch"><title>Clock example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; parse="text" href="../../../../glib/tests/glib-clock.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
+ *
+ * Return value: A newly-constructed #GSource
+ *
+ * Since: 2.30
+ **/
+GSource *
+_gnome_datetime_source_new (GDateTime  *now,
+			    GDateTime  *expiry,
+			    gboolean    cancel_on_set)
+{
+	GDateTimeSource *datetime_source;
+	gint64 unix_seconds;
+
+	unix_seconds = g_date_time_to_unix (expiry);
+
+	datetime_source = (GDateTimeSource*) g_source_new (&g_datetime_source_funcs, sizeof (GDateTimeSource));
+
+	datetime_source->cancel_on_set = cancel_on_set;
+
+#ifdef HAVE_TIMERFD
+	{
+		gint64 expected_now_seconds = g_date_time_to_unix (now);
+		if (g_datetime_source_init_timerfd (datetime_source, expected_now_seconds, unix_seconds))
+			return (GSource*)datetime_source;
+		/* Fall through to non-timerfd code */
+	}
+#endif
+
+	datetime_source->real_expiration = unix_seconds * 1000000;
+	g_datetime_source_reschedule (datetime_source, g_get_monotonic_time ());
+
+	return (GSource*)datetime_source;
+}
+

=== added file 'src/gnome-datetime-source.h'
--- src/gnome-datetime-source.h	1970-01-01 00:00:00 +0000
+++ src/gnome-datetime-source.h	2011-09-29 19:46:26 +0000
@@ -0,0 +1,34 @@
+/* gnome-rr.h
+ *
+ * Copyright 2011, Red Hat, Inc.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@xxxxxxxxxx>
+ */
+
+#ifndef GNOME_DATETIME_SOURCE_H
+#define GNOME_DATETIME_SOURCE_H
+
+#include <glib.h>
+
+GSource *_gnome_datetime_source_new (GDateTime *now,
+				     GDateTime *expiry,
+				     gboolean   cancel_on_set);
+
+#endif /* GNOME_DATETIME_SOURCE_H */

=== added file 'src/gnome-wall-clock.c'
--- src/gnome-wall-clock.c	1970-01-01 00:00:00 +0000
+++ src/gnome-wall-clock.c	2011-09-29 19:46:26 +0000
@@ -0,0 +1,247 @@
+/* -*- mode: C; c-file-style: "linux"; indent-tabs-mode: t -*-
+ * gnome-wall-clock.h - monitors TZ setting files and signals changes
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@xxxxxxxxxx>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "gnome-wall-clock.h"
+#include <gdesktop-enums.h>
+#include "gnome-datetime-source.h"
+
+struct _GnomeWallClockPrivate {
+	guint clock_update_id;
+
+	char *clock_string;
+
+	GFileMonitor *tz_monitor;
+	GSettings    *desktop_settings;
+};
+
+enum {
+	PROP_0,
+	PROP_CLOCK
+};
+
+G_DEFINE_TYPE (GnomeWallClock, gnome_wall_clock, G_TYPE_OBJECT);
+
+static gboolean update_clock (gpointer data);
+static void on_schema_change (GSettings *schema,
+                              const char *key,
+                              gpointer user_data);
+static void on_tz_changed (GFileMonitor *monitor,
+                           GFile        *file,
+                           GFile        *other_file,
+                           GFileMonitorEvent *event,
+                           gpointer      user_data);
+
+
+static void
+gnome_wall_clock_init (GnomeWallClock *self)
+{
+	GFile *tz;
+
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GNOME_TYPE_WALL_CLOCK, GnomeWallClockPrivate);
+
+	self->priv->clock_string = NULL;
+
+	tz = g_file_new_for_path ("/etc/localtime");
+	self->priv->tz_monitor = g_file_monitor_file (tz, 0, NULL, NULL);
+	g_object_unref (tz);
+
+	g_signal_connect (self->priv->tz_monitor, "changed", G_CALLBACK (on_tz_changed), self);
+
+	self->priv->desktop_settings = g_settings_new ("org.gnome.desktop.interface");
+	g_signal_connect (self->priv->desktop_settings, "changed", G_CALLBACK (on_schema_change), self);
+
+	update_clock (self);
+}
+
+static void
+gnome_wall_clock_dispose (GObject *object)
+{
+	GnomeWallClock *self = GNOME_WALL_CLOCK (object);
+
+	if (self->priv->clock_update_id) {
+		g_source_remove (self->priv->clock_update_id);
+		self->priv->clock_update_id = 0;
+	}
+
+	if (self->priv->tz_monitor != NULL) {
+		g_object_unref (self->priv->tz_monitor);
+		self->priv->tz_monitor = NULL;
+	}
+
+	if (self->priv->desktop_settings != NULL) {
+		g_object_unref (self->priv->desktop_settings);
+		self->priv->desktop_settings = NULL;
+	}
+
+	G_OBJECT_CLASS (gnome_wall_clock_parent_class)->dispose (object);
+}
+
+static void
+gnome_wall_clock_finalize (GObject *object)
+{
+	GnomeWallClock *self = GNOME_WALL_CLOCK (object);
+
+	g_free (self->priv->clock_string);
+
+	G_OBJECT_CLASS (gnome_wall_clock_parent_class)->finalize (object);
+}
+
+static void
+gnome_wall_clock_get_property (GObject    *gobject,
+			       guint       prop_id,
+			       GValue     *value,
+			       GParamSpec *pspec)
+{
+	GnomeWallClock *self = GNOME_WALL_CLOCK (gobject);
+
+	switch (prop_id)
+	{
+	case PROP_CLOCK:
+		g_value_set_string (value, self->priv->clock_string);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gnome_wall_clock_class_init (GnomeWallClockClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	gobject_class->get_property = gnome_wall_clock_get_property;
+	gobject_class->dispose = gnome_wall_clock_dispose;
+	gobject_class->finalize = gnome_wall_clock_finalize;
+
+	/**
+	 * GnomeWallClock:clock:
+	 *
+	 * A formatted string representing the current clock display.
+	 */
+	g_object_class_install_property (gobject_class,
+					 PROP_CLOCK,
+					 g_param_spec_string ("clock",
+							      "",
+							      "",
+							      NULL,
+							      G_PARAM_READABLE));
+
+
+	g_type_class_add_private (gobject_class, sizeof (GnomeWallClockPrivate));
+}
+
+static gboolean
+update_clock (gpointer data)
+{
+	GnomeWallClock   *self = data;
+	GDesktopClockFormat clock_format;
+	const char *format_string;
+	gboolean show_date;
+	gboolean show_seconds;
+	GSource *source;
+	GDateTime *now;
+	GDateTime *expiry;
+
+	clock_format = g_settings_get_enum (self->priv->desktop_settings, "clock-format");
+	show_date = g_settings_get_boolean (self->priv->desktop_settings, "clock-show-date");
+	show_seconds = g_settings_get_boolean (self->priv->desktop_settings, "clock-show-seconds");
+
+	now = g_date_time_new_now_local ();
+	if (show_seconds)
+		expiry = g_date_time_add_seconds (now, 1);
+	else
+		expiry = g_date_time_add_seconds (now, 60 - g_date_time_get_second (now));
+
+	if (self->priv->clock_update_id)
+		g_source_remove (self->priv->clock_update_id);
+
+	source = _gnome_datetime_source_new (now, expiry, TRUE);
+	g_source_set_priority (source, G_PRIORITY_HIGH);
+	g_source_set_callback (source, update_clock, self, NULL);
+	self->priv->clock_update_id = g_source_attach (source, NULL);
+	g_source_unref (source);
+
+	if (clock_format == G_DESKTOP_CLOCK_FORMAT_24H) {
+		if (show_date)
+			/* Translators: This is the time format with date used
+			   in 24-hour mode. */
+			format_string = show_seconds ? _("%a %b %e, %R:%S")
+				: _("%a %b %e, %R");
+		else
+			/* Translators: This is the time format without date used
+			   in 24-hour mode. */
+			format_string = show_seconds ? _("%a %R:%S")
+				: _("%a %R");
+	} else {
+		if (show_date)
+			/* Translators: This is a time format with date used
+			   for AM/PM. */
+			format_string = show_seconds ? _("%a %b %e, %l:%M:%S %p")
+				: _("%a %b %e, %l:%M %p");
+		else
+			/* Translators: This is a time format without date used
+			   for AM/PM. */
+			format_string = show_seconds ? _("%a %l:%M:%S %p")
+				: _("%a %l:%M %p");
+	}
+
+	g_free (self->priv->clock_string);
+	self->priv->clock_string = g_date_time_format (now, format_string);
+
+	g_date_time_unref (now);
+	g_date_time_unref (expiry);
+
+	g_object_notify ((GObject*)self, "clock");
+
+	return FALSE;
+}
+
+static void
+on_schema_change (GSettings *schema,
+                  const char *key,
+                  gpointer user_data)
+{
+	update_clock (user_data);
+}
+
+static void
+on_tz_changed (GFileMonitor      *monitor,
+               GFile             *file,
+               GFile             *other_file,
+               GFileMonitorEvent *event,
+               gpointer           user_data)
+{
+	update_clock (user_data);
+}
+
+const char *
+gnome_wall_clock_get_clock (GnomeWallClock *clock)
+{
+	return clock->priv->clock_string;
+}

=== added file 'src/gnome-wall-clock.h'
--- src/gnome-wall-clock.h	1970-01-01 00:00:00 +0000
+++ src/gnome-wall-clock.h	2011-09-29 19:46:26 +0000
@@ -0,0 +1,62 @@
+/* gnome-tz-monitor.h - fade window background between two surfaces
+
+   Copyright 2008, Red Hat, Inc.
+   Copyright 2011, Red Hat, Inc.
+
+   This file is part of the Gnome Library.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Colin Walters <walters@xxxxxxxxxx>
+*/
+
+#ifndef __GNOME_WALL_CLOCK_H__
+#define __GNOME_WALL_CLOCK_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GNOME_TYPE_WALL_CLOCK            (gnome_wall_clock_get_type ())
+#define GNOME_WALL_CLOCK(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_WALL_CLOCK, GnomeWallClock))
+#define GNOME_WALL_CLOCK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GNOME_TYPE_WALL_CLOCK, GnomeWallClockClass))
+#define GNOME_IS_WALL_CLOCK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_WALL_CLOCK))
+#define GNOME_IS_WALL_CLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GNOME_TYPE_WALL_CLOCK))
+#define GNOME_WALL_CLOCK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GNOME_TYPE_WALL_CLOCK, GnomeWallClockClass))
+
+typedef struct _GnomeWallClockPrivate GnomeWallClockPrivate;
+typedef struct _GnomeWallClock GnomeWallClock;
+typedef struct _GnomeWallClockClass GnomeWallClockClass;
+
+struct _GnomeWallClock
+{
+	GObject parent_object;
+
+	GnomeWallClockPrivate *priv;
+};
+
+struct _GnomeWallClockClass
+{
+	GObjectClass parent_class;
+};
+
+GType             gnome_wall_clock_get_type      (void);
+
+const char *      gnome_wall_clock_get_clock     (GnomeWallClock *clock);
+
+G_END_DECLS
+
+#endif

=== modified file 'src/indicator-datetime.c'
--- src/indicator-datetime.c	2011-09-21 20:19:53 +0000
+++ src/indicator-datetime.c	2011-09-29 19:46:26 +0000
@@ -48,6 +48,7 @@
 #include "utils.h"
 #include "dbus-shared.h"
 #include "settings-shared.h"
+#include "gnome-wall-clock.h"
 
 
 #define INDICATOR_DATETIME_TYPE            (indicator_datetime_get_type ())
@@ -72,7 +73,6 @@
 
 struct _IndicatorDatetimePrivate {
 	GtkLabel * label;
-	guint timer;
 
 	gchar * time_string;
 
@@ -101,8 +101,11 @@
 	GList * timezone_items;
 
 	GSettings * settings;
+	GSettings * gnome_settings;
 
 	GtkSizeGroup * indicator_right_group;
+
+	GnomeWallClock *clock;
 };
 
 /* Enum for the properties so that they can be quickly
@@ -166,7 +169,7 @@
 static gchar * generate_format_string_now (IndicatorDatetime * self);
 static void update_label                  (IndicatorDatetime * io, GDateTime ** datetime);
 static void guess_label_size              (IndicatorDatetime * self);
-static void setup_timer                   (IndicatorDatetime * self, GDateTime * datetime);
+static void on_clock_changed              (GnomeWallClock *clock, GParamSpec *pspec, gpointer user_data);
 static void update_time                   (IndicatorDatetime * self);
 static void receive_signal                (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name, GVariant * parameters, gpointer user_data);
 static void service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data);
@@ -293,7 +296,6 @@
                                                   IndicatorDatetimePrivate);
 
 	self->priv->label = NULL;
-	self->priv->timer = 0;
 
 	self->priv->idle_measure = 0;
 	self->priv->max_width = 0;
@@ -362,6 +364,11 @@
 		g_warning("Unable to get settings for '" SETTINGS_INTERFACE "'");
 	}
 
+	self->priv->gnome_settings = g_settings_new ("org.gnome.desktop.interface");
+
+	self->priv->clock = g_object_new (GNOME_TYPE_WALL_CLOCK, NULL);
+	g_signal_connect (self->priv->clock, "notify::clock", G_CALLBACK (on_clock_changed), self);
+
 	self->priv->sm = indicator_service_manager_new_version(SERVICE_NAME, SERVICE_VERSION);
 	self->priv->indicator_right_group = GTK_SIZE_GROUP(gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL));
 
@@ -433,9 +440,9 @@
 		self->priv->label = NULL;
 	}
 
-	if (self->priv->timer != 0) {
-		g_source_remove(self->priv->timer);
-		self->priv->timer = 0;
+	if (self->priv->clock != NULL) {
+		g_object_unref (self->priv->clock);
+		self->priv->clock = NULL;
 	}
 
 	if (self->priv->idle_measure != 0) {
@@ -562,7 +569,7 @@
 		if (newval != self->priv->time_mode) {
 			update = TRUE;
 			self->priv->time_mode = newval;
-			setup_timer(self, NULL);			
+			update_time (self);
 		}
 		break;
 	}
@@ -571,8 +578,11 @@
 			self->priv->show_seconds = !self->priv->show_seconds;
 			if (self->priv->time_mode != SETTINGS_TIME_CUSTOM) {
 				update = TRUE;
-				setup_timer(self, NULL);
+				update_time (self);
 			}
+			g_settings_set_boolean (self->priv->gnome_settings,
+			                        "clock-show-seconds",
+			                        self->priv->show_seconds);
 		}
 		break;
 	}
@@ -606,8 +616,11 @@
 			self->priv->custom_show_seconds = (time_mask & STRFTIME_MASK_SECONDS);
 			if (self->priv->time_mode == SETTINGS_TIME_CUSTOM) {
 				update = TRUE;
-				setup_timer(self, NULL);
+				update_time (self);
 			}
+			g_settings_set_boolean (self->priv->gnome_settings,
+			                        "clock-show-seconds",
+			                        self->priv->show_seconds);
 		}
 		break;
 	}
@@ -831,12 +844,21 @@
 	update_label(self, &dt);
 	timezone_update_all_labels(self);
 	if (dt != NULL) {
-		setup_timer(self, dt);
 		g_date_time_unref(dt);
   }
 	return;
 }
 
+static void
+on_clock_changed (GnomeWallClock *clock,
+                  GParamSpec     *pspec,
+                  gpointer        user_data)
+{
+  IndicatorDatetime *self = INDICATOR_DATETIME (user_data);
+
+  update_time (self);
+}
+
 /* Receives all signals from the service, routed to the appropriate functions */
 static void
 receive_signal (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name,
@@ -851,54 +873,6 @@
 	return;
 }
 
-/* Runs every minute and updates the time */
-gboolean
-timer_func (gpointer user_data)
-{
-	IndicatorDatetime * self = INDICATOR_DATETIME(user_data);
-	self->priv->timer = 0;
-	GDateTime * dt = NULL;
-	update_label(self, &dt);
-	timezone_update_all_labels(self);
-	if (dt != NULL) {
-		setup_timer(self, dt);
-		g_date_time_unref(dt);
-  }
-	return FALSE;
-}
-
-/* Configure the timer to run the next time through */
-static void
-setup_timer (IndicatorDatetime * self, GDateTime * datetime)
-{
-	gboolean unref = FALSE;
-
-	if (self->priv->timer != 0) {
-		g_source_remove(self->priv->timer);
-		self->priv->timer = 0;
-	}
-	
-	if (self->priv->show_seconds ||
-		(self->priv->time_mode == SETTINGS_TIME_CUSTOM && self->priv->custom_show_seconds)) {
-		self->priv->timer = g_timeout_add_full(G_PRIORITY_HIGH, 999, timer_func, self, NULL);
-	} else {
-		if (datetime == NULL) {
-			datetime = g_date_time_new_now_local();
-			unref = TRUE;
-		}
-
-		/* Plus 2 so we're just after the minute, don't want to be early. */
-		gint seconds = (gint)g_date_time_get_seconds(datetime);
-		self->priv->timer = g_timeout_add_seconds(60 - seconds + 2, timer_func, self);
-
-		if (unref) {
-			g_date_time_unref(datetime);
-		}
-	}
-
-	return;
-}
-
 /* Does a quick meausre of how big the string is in
    pixels with a Pango layout */
 static gint
@@ -1521,10 +1495,6 @@
 		gtk_widget_set_visible(GTK_WIDGET (self->priv->label), self->priv->show_clock);
 	}
 
-	if (self->priv->timer == 0) {
-		setup_timer(self, NULL);
-	}
-
 	return self->priv->label;
 }