summaryrefslogtreecommitdiff
path: root/applets/clock/set-timezone.c
diff options
context:
space:
mode:
Diffstat (limited to 'applets/clock/set-timezone.c')
-rw-r--r--applets/clock/set-timezone.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/applets/clock/set-timezone.c b/applets/clock/set-timezone.c
new file mode 100644
index 00000000..3b4f1e56
--- /dev/null
+++ b/applets/clock/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 <[email protected]>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#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.mate.SettingsDaemon.DateTimeMechanism",
+ "/",
+ "org.mate.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.mate.SettingsDaemon.DateTimeMechanism",
+ "/",
+ "org.mate.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);
+}