From 1d60affa617ad4a18814382aefc0538fc74747cd Mon Sep 17 00:00:00 2001 From: Thomas Wood Date: Thu, 24 Jun 2010 15:20:45 +0100 Subject: [PATCH] datetime: use the SettingsDaemon dbus service to set the system time Use the org.gnome.SettingsDaemon.DateTimeMechanism interface to set the current system time. --- panels/datetime/Makefile.am | 4 +- panels/datetime/cc-datetime-panel.c | 51 +++++ panels/datetime/datetime.ui | 8 +- panels/datetime/set-timezone.c | 291 ++++++++++++++++++++++++++++ panels/datetime/set-timezone.h | 40 ++++ 5 files changed, 386 insertions(+), 8 deletions(-) create mode 100644 panels/datetime/set-timezone.c create mode 100644 panels/datetime/set-timezone.h diff --git a/panels/datetime/Makefile.am b/panels/datetime/Makefile.am index 63049d968..f297c5d46 100644 --- a/panels/datetime/Makefile.am +++ b/panels/datetime/Makefile.am @@ -59,7 +59,9 @@ libdate_time_la_SOURCES = \ cc-datetime-panel.c \ cc-datetime-panel.h \ cc-timezone-map.c \ - cc-timezone-map.h + cc-timezone-map.h \ + set-timezone.c \ + set-timezone.h libdate_time_la_LIBADD = $(PANEL_LIBS) libdate_time_la_LDFLAGS = $(PANEL_LDFLAGS) diff --git a/panels/datetime/cc-datetime-panel.c b/panels/datetime/cc-datetime-panel.c index fa18c918c..eb7d07042 100644 --- a/panels/datetime/cc-datetime-panel.c +++ b/panels/datetime/cc-datetime-panel.c @@ -22,6 +22,7 @@ #include "cc-datetime-panel.h" #include "cc-timezone-map.h" +#include "set-timezone.h" G_DEFINE_DYNAMIC_TYPE (CcDateTimePanel, cc_date_time_panel, CC_TYPE_PANEL) @@ -131,6 +132,51 @@ update_time (CcDateTimePanel *self) return FALSE; } +static void +cb (CcDateTimePanel *self, + GError *error) +{ + /* TODO: display any error in a user friendly way */ + if (error) + { + g_warning ("Could not set system time: %s", error->message); + } +} + +static void +apply_button_clicked_cb (GtkButton *button, + CcDateTimePanel *self) +{ + GtkWidget *widget; + CcDateTimePanelPrivate *priv = self->priv; + guint h, mon, s, y, min, d; + struct tm fulltime; + time_t unixtime; + + widget = (GtkWidget *) gtk_builder_get_object (priv->builder, "spin_hour"); + h = gtk_spin_button_get_value (GTK_SPIN_BUTTON (widget)); + widget = (GtkWidget *) gtk_builder_get_object (priv->builder, "spin_minute"); + min = gtk_spin_button_get_value (GTK_SPIN_BUTTON (widget)); + widget = (GtkWidget *) gtk_builder_get_object (priv->builder, "spin_second"); + s = gtk_spin_button_get_value (GTK_SPIN_BUTTON (widget)); + + widget = (GtkWidget *) gtk_builder_get_object (priv->builder, "calendar"); + gtk_calendar_get_date (GTK_CALENDAR (widget), &y, &mon, &d); + + fulltime.tm_sec = s; + fulltime.tm_min = min; + fulltime.tm_hour = h; + fulltime.tm_mday = d; + fulltime.tm_mon = mon; + fulltime.tm_year = y - 1900; + fulltime.tm_isdst = -1; + + + unixtime = mktime (&fulltime); + + set_system_time_async (unixtime, (GFunc) cb, self, NULL); + +} static void cc_date_time_panel_init (CcDateTimePanel *self) @@ -187,6 +233,11 @@ cc_date_time_panel_init (CcDateTimePanel *self) gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), ltime->tm_min); widget = (GtkWidget *) gtk_builder_get_object (priv->builder, "spin_second"); gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), ltime->tm_sec); + + g_signal_connect ((GtkWidget*) gtk_builder_get_object (priv->builder, "button_apply"), + "clicked", + G_CALLBACK (apply_button_clicked_cb), + self); } void diff --git a/panels/datetime/datetime.ui b/panels/datetime/datetime.ui index 9e0968185..ec80958dc 100644 --- a/panels/datetime/datetime.ui +++ b/panels/datetime/datetime.ui @@ -76,9 +76,9 @@ Keep date and time updated automatically - True True False + True True @@ -231,19 +231,13 @@ 23 1 - 10 - 10 60 1 - 10 - 10 60 1 - 10 - 10 diff --git a/panels/datetime/set-timezone.c b/panels/datetime/set-timezone.c new file mode 100644 index 000000000..91c80dd9d --- /dev/null +++ b/panels/datetime/set-timezone.c @@ -0,0 +1,291 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 David Zeuthen + * + * This program 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 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 General Public License for more details. + * + * You should have received a copy of the GNU 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. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "set-timezone.h" + + +static DBusGConnection * +get_system_bus (void) +{ + GError *error; + static DBusGConnection *bus = NULL; + + if (bus == NULL) { + error = NULL; + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (bus == NULL) { + g_warning ("Couldn't connect to system bus: %s", + error->message); + g_error_free (error); + } + } + + return bus; +} + +#define CACHE_VALIDITY_SEC 2 + +typedef void (*CanDoFunc) (gint value); + +static void +notify_can_do (DBusGProxy *proxy, + DBusGProxyCall *call, + void *user_data) +{ + CanDoFunc callback = user_data; + GError *error = NULL; + gint value; + + if (dbus_g_proxy_end_call (proxy, call, + &error, + G_TYPE_INT, &value, + G_TYPE_INVALID)) { + callback (value); + } +} + +static void +refresh_can_do (const gchar *action, CanDoFunc callback) +{ + DBusGConnection *bus; + DBusGProxy *proxy; + + bus = get_system_bus (); + if (bus == NULL) + return; + + proxy = dbus_g_proxy_new_for_name (bus, + "org.gnome.SettingsDaemon.DateTimeMechanism", + "/", + "org.gnome.SettingsDaemon.DateTimeMechanism"); + + dbus_g_proxy_begin_call_with_timeout (proxy, + action, + notify_can_do, + callback, NULL, + INT_MAX, + G_TYPE_INVALID); +} + +static gint settimezone_cache = 0; +static time_t settimezone_stamp = 0; + +static void +update_can_settimezone (gint res) +{ + settimezone_cache = res; + time (&settimezone_stamp); +} + +gint +can_set_system_timezone (void) +{ + time_t now; + + time (&now); + if (ABS (now - settimezone_stamp) > CACHE_VALIDITY_SEC) { + refresh_can_do ("CanSetTimezone", update_can_settimezone); + settimezone_stamp = now; + } + + return settimezone_cache; +} + +static gint settime_cache = 0; +static time_t settime_stamp = 0; + +static void +update_can_settime (gint res) +{ + settime_cache = res; + time (&settime_stamp); +} + +gint +can_set_system_time (void) +{ + time_t now; + + time (&now); + if (ABS (now - settime_stamp) > CACHE_VALIDITY_SEC) { + refresh_can_do ("CanSetTime", update_can_settime); + settime_stamp = now; + } + + return settime_cache; +} + +typedef struct { + gint ref_count; + gchar *call; + gint64 time; + gchar *filename; + GFunc callback; + gpointer data; + GDestroyNotify notify; +} SetTimeCallbackData; + +static void +free_data (gpointer d) +{ + SetTimeCallbackData *data = d; + + data->ref_count--; + if (data->ref_count == 0) { + if (data->notify) + data->notify (data->data); + g_free (data->filename); + g_free (data); + } +} + +static void +set_time_notify (DBusGProxy *proxy, + DBusGProxyCall *call, + void *user_data) +{ + SetTimeCallbackData *data = user_data; + GError *error = NULL; + + if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) { + if (data->callback) + data->callback (data->data, NULL); + } + else { + if (error->domain == DBUS_GERROR && + error->code == DBUS_GERROR_NO_REPLY) { + /* these errors happen because dbus doesn't + * use monotonic clocks + */ + g_warning ("ignoring no-reply error when setting time"); + g_error_free (error); + if (data->callback) + data->callback (data->data, NULL); + } + else { + if (data->callback) + data->callback (data->data, error); + else + g_error_free (error); + } + } +} + +static void +set_time_async (SetTimeCallbackData *data) +{ + DBusGConnection *bus; + DBusGProxy *proxy; + + bus = get_system_bus (); + if (bus == NULL) + return; + + proxy = dbus_g_proxy_new_for_name (bus, + "org.gnome.SettingsDaemon.DateTimeMechanism", + "/", + "org.gnome.SettingsDaemon.DateTimeMechanism"); + + data->ref_count++; + if (strcmp (data->call, "SetTime") == 0) + dbus_g_proxy_begin_call_with_timeout (proxy, + "SetTime", + set_time_notify, + data, free_data, + INT_MAX, + /* parameters: */ + G_TYPE_INT64, data->time, + G_TYPE_INVALID, + /* return values: */ + G_TYPE_INVALID); + else + dbus_g_proxy_begin_call_with_timeout (proxy, + "SetTimezone", + set_time_notify, + data, free_data, + INT_MAX, + /* parameters: */ + G_TYPE_STRING, data->filename, + G_TYPE_INVALID, + /* return values: */ + G_TYPE_INVALID); +} + +void +set_system_time_async (gint64 time, + GFunc callback, + gpointer d, + GDestroyNotify notify) +{ + SetTimeCallbackData *data; + + if (time == -1) + return; + + data = g_new0 (SetTimeCallbackData, 1); + data->ref_count = 1; + data->call = "SetTime"; + data->time = time; + data->filename = NULL; + data->callback = callback; + data->data = d; + data->notify = notify; + + set_time_async (data); + free_data (data); +} + +void +set_system_timezone_async (const gchar *filename, + GFunc callback, + gpointer d, + GDestroyNotify notify) +{ + SetTimeCallbackData *data; + + if (filename == NULL) + return; + + data = g_new0 (SetTimeCallbackData, 1); + data->ref_count = 1; + data->call = "SetTimezone"; + data->time = -1; + data->filename = g_strdup (filename); + data->callback = callback; + data->data = d; + data->notify = notify; + + set_time_async (data); + free_data (data); +} diff --git a/panels/datetime/set-timezone.h b/panels/datetime/set-timezone.h new file mode 100644 index 000000000..5280b079d --- /dev/null +++ b/panels/datetime/set-timezone.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 David Zeuthen + * + * This program 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 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 General Public License for more details. + * + * You should have received a copy of the GNU 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. + * + */ + +#ifndef __SET_SYSTEM_TIMEZONE_H__ + +#include +#include + +gint can_set_system_timezone (void); + +gint can_set_system_time (void); + +void set_system_time_async (gint64 time, + GFunc callback, + gpointer data, + GDestroyNotify notify); + +void set_system_timezone_async (const gchar *filename, + GFunc callback, + gpointer data, + GDestroyNotify notify); + +#endif