gnome-control-center/panels/datetime/cc-datetime-panel.c
Florian Müllner ee73a6cf2b datetime: Fix date sensitivity on permission changes
Setting the date manually should be disabled when using NTP, but
the "Network Time" setting is not taken into account when updating
sensitivities after permission changes. As a result, the date is
always editable after unlocking the panel - to fix, take the NTP
setting into account on permission changes.

https://bugzilla.gnome.org/show_bug.cgi?id=652240
2011-06-10 00:12:11 +02:00

1064 lines
32 KiB
C

/*
* Copyright (C) 2010 Intel, Inc
*
* 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.
*
* Author: Thomas Wood <thomas.wood@intel.com>
*
*/
#include "config.h"
#include "cc-datetime-panel.h"
#include <sys/time.h>
#include "cc-timezone-map.h"
#include "dtm.h"
#include "date-endian.h"
#include <gdesktop-enums.h>
#include <string.h>
#include <stdlib.h>
#include <libintl.h>
#include <polkit/polkit.h>
/* FIXME: This should be "Etc/GMT" instead */
#define DEFAULT_TZ "Europe/London"
#define GETTEXT_PACKAGE_TIMEZONES GETTEXT_PACKAGE "-timezones"
G_DEFINE_DYNAMIC_TYPE (CcDateTimePanel, cc_date_time_panel, CC_TYPE_PANEL)
#define DATE_TIME_PANEL_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_DATE_TIME_PANEL, CcDateTimePanelPrivate))
enum {
CITY_COL_CITY,
CITY_COL_REGION,
CITY_COL_CITY_TRANSLATED,
CITY_COL_REGION_TRANSLATED,
CITY_COL_ZONE,
CITY_NUM_COLS
};
enum {
REGION_COL_REGION,
REGION_COL_REGION_TRANSLATED,
REGION_NUM_COLS
};
#define W(x) (GtkWidget*) gtk_builder_get_object (priv->builder, x)
#define CLOCK_SCHEMA "org.gnome.desktop.interface"
#define CLOCK_FORMAT_KEY "clock-format"
struct _CcDateTimePanelPrivate
{
GtkBuilder *builder;
GtkWidget *map;
TzLocation *current_location;
GtkTreeModel *locations;
GtkTreeModelFilter *city_filter;
GDateTime *date;
GSettings *settings;
GDesktopClockFormat clock_format;
guint update_id;
DateTimeMechanism *dtm;
GCancellable *cancellable;
GPermission *permission;
};
static void update_time (CcDateTimePanel *self);
static void queue_clock_update (CcDateTimePanel *self);
static void
cc_date_time_panel_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
cc_date_time_panel_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
cc_date_time_panel_dispose (GObject *object)
{
CcDateTimePanelPrivate *priv = CC_DATE_TIME_PANEL (object)->priv;
if (priv->update_id != 0)
{
g_source_remove (priv->update_id);
priv->update_id = 0;
}
if (priv->builder)
{
g_object_unref (priv->builder);
priv->builder = NULL;
}
if (priv->settings)
{
g_object_unref (priv->settings);
priv->settings = NULL;
}
if (priv->date)
{
g_date_time_unref (priv->date);
priv->date = NULL;
}
if (priv->cancellable)
{
g_cancellable_cancel (priv->cancellable);
g_object_unref (priv->cancellable);
priv->cancellable = NULL;
}
if (priv->dtm)
{
g_object_unref (priv->dtm);
priv->dtm = NULL;
}
if (priv->permission)
{
g_object_unref (priv->permission);
priv->permission = NULL;
}
G_OBJECT_CLASS (cc_date_time_panel_parent_class)->dispose (object);
}
static GPermission *
cc_date_time_panel_get_permission (CcPanel *panel)
{
CcDateTimePanelPrivate *priv = CC_DATE_TIME_PANEL (panel)->priv;
return priv->permission;
}
static void
cc_date_time_panel_class_init (CcDateTimePanelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
g_type_class_add_private (klass, sizeof (CcDateTimePanelPrivate));
object_class->get_property = cc_date_time_panel_get_property;
object_class->set_property = cc_date_time_panel_set_property;
object_class->dispose = cc_date_time_panel_dispose;
panel_class->get_permission = cc_date_time_panel_get_permission;
}
static void
cc_date_time_panel_class_finalize (CcDateTimePanelClass *klass)
{
}
static void clock_settings_changed_cb (GSettings *settings,
gchar *key,
CcDateTimePanel *panel);
static void
change_clock_settings (GObject *gobject,
GParamSpec *pspec,
CcDateTimePanel *panel)
{
CcDateTimePanelPrivate *priv = panel->priv;
GDesktopClockFormat value;
g_signal_handlers_block_by_func (priv->settings, clock_settings_changed_cb,
panel);
if (gtk_switch_get_active (GTK_SWITCH (W ("24h_time_switch"))))
value = G_DESKTOP_CLOCK_FORMAT_24H;
else
value = G_DESKTOP_CLOCK_FORMAT_12H;
g_settings_set_enum (priv->settings, CLOCK_FORMAT_KEY, value);
priv->clock_format = value;
update_time (panel);
g_signal_handlers_unblock_by_func (priv->settings, clock_settings_changed_cb,
panel);
}
static void
clock_settings_changed_cb (GSettings *settings,
gchar *key,
CcDateTimePanel *panel)
{
CcDateTimePanelPrivate *priv = panel->priv;
GtkWidget *switch24h;
gboolean use_24_hour;
GDesktopClockFormat value;
value = g_settings_get_enum (settings, CLOCK_FORMAT_KEY);
priv->clock_format = value;
switch24h = W ("24h_time_switch");
use_24_hour = (value == G_DESKTOP_CLOCK_FORMAT_24H);
g_signal_handlers_block_by_func (switch24h, change_clock_settings, panel);
gtk_switch_set_active (GTK_SWITCH (switch24h), use_24_hour);
update_time (panel);
g_signal_handlers_unblock_by_func (switch24h, change_clock_settings, panel);
}
static void
update_time (CcDateTimePanel *self)
{
CcDateTimePanelPrivate *priv = self->priv;
char *label;
char *am_pm_widgets[] = {"ampm_up_button", "ampm_down_button", "ampm_label" };
guint i;
if (priv->clock_format == G_DESKTOP_CLOCK_FORMAT_24H)
{
/* Update the hours label */
label = g_date_time_format (priv->date, "%H");
gtk_label_set_text (GTK_LABEL (W("hours_label")), label);
g_free (label);
}
else
{
/* Update the hours label */
label = g_date_time_format (priv->date, "%I");
gtk_label_set_text (GTK_LABEL (W("hours_label")), label);
g_free (label);
/* Set AM/PM */
label = g_date_time_format (priv->date, "%p");
gtk_label_set_text (GTK_LABEL (W("ampm_label")), label);
g_free (label);
}
for (i = 0; i < G_N_ELEMENTS (am_pm_widgets); i++)
gtk_widget_set_visible (W(am_pm_widgets[i]),
priv->clock_format == G_DESKTOP_CLOCK_FORMAT_12H);
/* Update the minutes label */
label = g_date_time_format (priv->date, "%M");
gtk_label_set_text (GTK_LABEL (W("minutes_label")), label);
g_free (label);
}
static void
set_time_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
CcDateTimePanel *self = user_data;
GError *error;
error = NULL;
if (!date_time_mechanism_call_set_time_finish (self->priv->dtm,
res,
&error))
{
/* TODO: display any error in a user friendly way */
g_warning ("Could not set system time: %s", error->message);
g_error_free (error);
}
else
{
update_time (self);
}
}
static void
set_timezone_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
CcDateTimePanel *self = user_data;
GError *error;
error = NULL;
if (!date_time_mechanism_call_set_timezone_finish (self->priv->dtm,
res,
&error))
{
/* TODO: display any error in a user friendly way */
g_warning ("Could not set system timezone: %s", error->message);
g_error_free (error);
}
}
static void
set_using_ntp_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
CcDateTimePanel *self = user_data;
GError *error;
error = NULL;
if (!date_time_mechanism_call_set_using_ntp_finish (self->priv->dtm,
res,
&error))
{
/* TODO: display any error in a user friendly way */
g_warning ("Could not set system to use NTP: %s", error->message);
g_error_free (error);
}
}
static void
queue_set_datetime (CcDateTimePanel *self)
{
time_t unixtime;
/* for now just do it */
unixtime = g_date_time_to_unix (self->priv->date);
date_time_mechanism_call_set_time (self->priv->dtm,
unixtime,
self->priv->cancellable,
set_time_cb,
self);
}
static void
queue_set_ntp (CcDateTimePanel *self)
{
CcDateTimePanelPrivate *priv = self->priv;
gboolean using_ntp;
/* for now just do it */
using_ntp = gtk_switch_get_active (GTK_SWITCH (W("network_time_switch")));
date_time_mechanism_call_set_using_ntp (self->priv->dtm,
using_ntp,
self->priv->cancellable,
set_using_ntp_cb,
self);
}
static void
queue_set_timezone (CcDateTimePanel *self)
{
/* for now just do it */
if (self->priv->current_location)
{
date_time_mechanism_call_set_timezone (self->priv->dtm,
self->priv->current_location->zone,
self->priv->cancellable,
set_timezone_cb,
self);
}
}
static void
change_date (CcDateTimePanel *self)
{
CcDateTimePanelPrivate *priv = self->priv;
guint mon, y, d;
GDateTime *old_date;
old_date = priv->date;
mon = 1 + gtk_combo_box_get_active (GTK_COMBO_BOX (W ("month-combobox")));
y = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (W ("year-spinbutton")));
d = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (W ("day-spinbutton")));
priv->date = g_date_time_new_local (y, mon, d,
g_date_time_get_hour (old_date),
g_date_time_get_minute (old_date),
g_date_time_get_second (old_date));
g_date_time_unref (old_date);
queue_set_datetime (self);
}
static void
region_changed_cb (GtkComboBox *box,
CcDateTimePanel *self)
{
GtkTreeModelFilter *modelfilter;
modelfilter = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (self->priv->builder, "city-modelfilter"));
gtk_tree_model_filter_refilter (modelfilter);
}
static void
city_changed_cb (GtkComboBox *box,
CcDateTimePanel *self)
{
static gboolean inside = FALSE;
GtkTreeIter iter;
gchar *zone;
/* prevent re-entry from location changed callback */
if (inside)
return;
inside = TRUE;
if (gtk_combo_box_get_active_iter (box, &iter))
{
gtk_tree_model_get (gtk_combo_box_get_model (box), &iter,
CITY_COL_ZONE, &zone, -1);
cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), zone);
g_free (zone);
}
inside = FALSE;
}
static void
update_timezone (CcDateTimePanel *self)
{
CcDateTimePanelPrivate *priv = self->priv;
GtkWidget *widget;
gchar **split;
GtkTreeIter iter;
GtkTreeModel *model;
/* tz.c updates the local timezone, which means the spin buttons can be
* updated with the current time of the new location */
split = g_strsplit (priv->current_location->zone, "/", 2);
/* remove underscores */
g_strdelimit (split[1], "_", ' ');
/* update region combo */
widget = (GtkWidget *) gtk_builder_get_object (priv->builder,
"region_combobox");
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
gtk_tree_model_get_iter_first (model, &iter);
do
{
gchar *string;
gtk_tree_model_get (model, &iter, CITY_COL_CITY, &string, -1);
if (!g_strcmp0 (string, split[0]))
{
g_free (string);
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
break;
}
g_free (string);
}
while (gtk_tree_model_iter_next (model, &iter));
/* update city combo */
widget = (GtkWidget *) gtk_builder_get_object (priv->builder,
"city_combobox");
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
gtk_tree_model_filter_refilter ((GtkTreeModelFilter *) gtk_builder_get_object (priv->builder, "city-modelfilter"));
gtk_tree_model_get_iter_first (model, &iter);
do
{
gchar *string;
gtk_tree_model_get (model, &iter, CITY_COL_CITY, &string, -1);
if (!g_strcmp0 (string, split[1]))
{
g_free (string);
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
break;
}
g_free (string);
}
while (gtk_tree_model_iter_next (model, &iter));
g_strfreev (split);
}
static void
location_changed_cb (CcTimezoneMap *map,
TzLocation *location,
CcDateTimePanel *self)
{
CcDateTimePanelPrivate *priv = self->priv;
GtkWidget *region_combo, *city_combo;
g_debug ("location changed to %s/%s", location->country, location->zone);
self->priv->current_location = location;
/* Update the combo boxes */
region_combo = W("region_combobox");
city_combo = W("city_combobox");
g_signal_handlers_block_by_func (region_combo, region_changed_cb, self);
g_signal_handlers_block_by_func (city_combo, city_changed_cb, self);
update_timezone (self);
g_signal_handlers_unblock_by_func (region_combo, region_changed_cb, self);
g_signal_handlers_unblock_by_func (city_combo, city_changed_cb, self);
queue_set_timezone (self);
}
static void
get_timezone_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
CcDateTimePanel *self = user_data;
GtkWidget *widget;
gchar *timezone;
GError *error;
error = NULL;
if (!date_time_mechanism_call_get_timezone_finish (self->priv->dtm, &timezone, res, &error))
{
g_warning ("Could not get current timezone: %s", error->message);
g_error_free (error);
}
else
{
if (!cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), timezone))
{
g_warning ("Timezone '%s' is unhandled, setting %s as default", timezone, DEFAULT_TZ);
cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), DEFAULT_TZ);
}
self->priv->current_location = cc_timezone_map_get_location (CC_TIMEZONE_MAP (self->priv->map));
update_timezone (self);
}
/* now that the initial state is loaded set connect the signals */
widget = (GtkWidget*) gtk_builder_get_object (self->priv->builder,
"region_combobox");
g_signal_connect (widget, "changed", G_CALLBACK (region_changed_cb), self);
widget = (GtkWidget*) gtk_builder_get_object (self->priv->builder,
"city_combobox");
g_signal_connect (widget, "changed", G_CALLBACK (city_changed_cb), self);
g_signal_connect (self->priv->map, "location-changed",
G_CALLBACK (location_changed_cb), self);
g_free (timezone);
}
/* load region and city tree models */
struct get_region_data
{
GtkListStore *region_store;
GtkListStore *city_store;
GHashTable *table;
};
/* Slash look-alikes that might be used in translations */
#define TRANSLATION_SPLIT \
"\342\201\204" /* FRACTION SLASH */ \
"\342\210\225" /* DIVISION SLASH */ \
"\342\247\270" /* BIG SOLIDUS */ \
"\357\274\217" /* FULLWIDTH SOLIDUS */ \
"/"
static void
get_regions (TzLocation *loc,
struct get_region_data *data)
{
gchar *zone;
gchar **split;
gchar **split_translated;
gchar *translated_city;
zone = g_strdup (loc->zone);
g_strdelimit (zone, "_", ' ');
split = g_strsplit (zone, "/", 2);
g_free (zone);
/* Load the translation for it */
zone = g_strdup (dgettext (GETTEXT_PACKAGE_TIMEZONES, loc->zone));
g_strdelimit (zone, "_", ' ');
split_translated = g_regex_split_simple ("[\\x{2044}\\x{2215}\\x{29f8}\\x{ff0f}/]", zone, 0, 0);
g_free (zone);
if (!g_hash_table_lookup_extended (data->table, split[0], NULL, NULL))
{
g_hash_table_insert (data->table, g_strdup (split[0]),
GINT_TO_POINTER (1));
gtk_list_store_insert_with_values (data->region_store, NULL, 0,
REGION_COL_REGION, split[0],
REGION_COL_REGION_TRANSLATED, split_translated[0], -1);
}
/* g_regex_split_simple() splits too much for us, and would break
* America/Argentina/Buenos_Aires into 3 strings, so rejoin the city part */
translated_city = g_strjoinv ("/", split_translated + 1);
gtk_list_store_insert_with_values (data->city_store, NULL, 0,
CITY_COL_CITY, split[1],
CITY_COL_CITY_TRANSLATED, translated_city,
CITY_COL_REGION, split[0],
CITY_COL_REGION_TRANSLATED, split_translated[0],
CITY_COL_ZONE, loc->zone,
-1);
g_free (translated_city);
g_strfreev (split);
g_strfreev (split_translated);
}
static gboolean
city_model_filter_func (GtkTreeModel *model,
GtkTreeIter *iter,
GtkComboBox *combo)
{
GtkTreeModel *combo_model;
GtkTreeIter combo_iter;
gchar *active_region = NULL;
gchar *city_region = NULL;
gboolean result;
if (gtk_combo_box_get_active_iter (combo, &combo_iter) == FALSE)
return FALSE;
combo_model = gtk_combo_box_get_model (combo);
gtk_tree_model_get (combo_model, &combo_iter,
CITY_COL_CITY, &active_region, -1);
gtk_tree_model_get (model, iter,
CITY_COL_REGION, &city_region, -1);
if (g_strcmp0 (active_region, city_region) == 0)
result = TRUE;
else
result = FALSE;
g_free (city_region);
g_free (active_region);
return result;
}
static void
load_regions_model (GtkListStore *regions, GtkListStore *cities)
{
struct get_region_data data;
TzDB *db;
GHashTable *table;
db = tz_load_db ();
table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
data.table = table;
data.region_store = regions;
data.city_store = cities;
g_ptr_array_foreach (db->locations, (GFunc) get_regions, &data);
g_hash_table_destroy (table);
tz_db_free (db);
/* sort the models */
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (regions),
REGION_COL_REGION_TRANSLATED,
GTK_SORT_ASCENDING);
}
static void
update_widget_state_for_ntp (CcDateTimePanel *panel,
gboolean using_ntp)
{
CcDateTimePanelPrivate *priv = panel->priv;
gtk_widget_set_sensitive (W("table1"), !using_ntp);
gtk_widget_set_sensitive (W("table2"), !using_ntp);
}
static void
day_changed (GtkWidget *widget,
CcDateTimePanel *panel)
{
change_date (panel);
}
static void
month_year_changed (GtkWidget *widget,
CcDateTimePanel *panel)
{
CcDateTimePanelPrivate *priv = panel->priv;
guint mon, y;
guint num_days;
GtkAdjustment *adj;
GtkSpinButton *day_spin;
mon = 1 + gtk_combo_box_get_active (GTK_COMBO_BOX (W ("month-combobox")));
y = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (W ("year-spinbutton")));
/* Check the number of days in that month */
num_days = g_date_get_days_in_month (mon, y);
day_spin = GTK_SPIN_BUTTON (W("day-spinbutton"));
adj = GTK_ADJUSTMENT (gtk_spin_button_get_adjustment (day_spin));
gtk_adjustment_set_upper (adj, num_days + 1);
if (gtk_spin_button_get_value_as_int (day_spin) > num_days)
gtk_spin_button_set_value (day_spin, num_days);
change_date (panel);
}
static void
change_time (GtkButton *button,
CcDateTimePanel *panel)
{
CcDateTimePanelPrivate *priv = panel->priv;
const gchar *widget_name;
gint direction;
GDateTime *old_date;
old_date = priv->date;
widget_name = gtk_buildable_get_name (GTK_BUILDABLE (button));
if (strstr (widget_name, "up"))
direction = 1;
else
direction = -1;
if (widget_name[0] == 'h')
{
priv->date = g_date_time_add_hours (old_date, direction);
}
else if (widget_name[0] == 'm')
{
priv->date = g_date_time_add_minutes (old_date, direction);
}
else
{
int hour;
hour = g_date_time_get_hour (old_date);
if (hour >= 12)
priv->date = g_date_time_add_hours (old_date, -12);
else
priv->date = g_date_time_add_hours (old_date, 12);
}
g_date_time_unref (old_date);
update_time (panel);
queue_set_datetime (panel);
}
static void
change_ntp (GObject *gobject,
GParamSpec *pspec,
CcDateTimePanel *self)
{
update_widget_state_for_ntp (self, gtk_switch_get_active (GTK_SWITCH (gobject)));
queue_set_ntp (self);
}
static gboolean
update_time_timer (CcDateTimePanel *self)
{
g_date_time_unref (self->priv->date);
self->priv->date = g_date_time_new_now_local ();
update_time (self);
queue_clock_update (self);
return FALSE;
}
static void
queue_clock_update (CcDateTimePanel *self)
{
int timeouttime;
struct timeval tv;
gettimeofday (&tv, NULL);
timeouttime = (G_USEC_PER_SEC - tv.tv_usec) / 1000 + 1;
/* timeout of one minute if we don't care about the seconds */
timeouttime += 1000 * (59 - tv.tv_sec % 60);
self->priv->update_id = g_timeout_add (timeouttime, (GSourceFunc)update_time_timer, self);
}
static void
on_permission_changed (GPermission *permission,
GParamSpec *pspec,
gpointer data)
{
CcDateTimePanelPrivate *priv = CC_DATE_TIME_PANEL (data)->priv;
gboolean allowed, using_ntp;
allowed = g_permission_get_allowed (permission);
using_ntp = gtk_switch_get_active (GTK_SWITCH (W("network_time_switch")));
/* All the widgets but the lock button and the 24h setting */
gtk_widget_set_sensitive (W("map-vbox"), allowed);
gtk_widget_set_sensitive (W("hbox2"), allowed);
gtk_widget_set_sensitive (W("alignment2"), allowed);
gtk_widget_set_sensitive (W("table1"), allowed && !using_ntp);
}
static void
reorder_date_widget (DateEndianess endianess,
CcDateTimePanelPrivate *priv)
{
GtkWidget *month, *day, *year;
GtkBox *box;
if (endianess == DATE_ENDIANESS_MIDDLE)
return;
month = W ("month-combobox");
day = W ("day-spinbutton");
year = W("year-spinbutton");
box = GTK_BOX (W("table1"));
switch (endianess) {
case DATE_ENDIANESS_LITTLE:
gtk_box_reorder_child (box, month, 0);
gtk_box_reorder_child (box, day, 0);
gtk_box_reorder_child (box, year, -1);
break;
case DATE_ENDIANESS_BIG:
gtk_box_reorder_child (box, month, 0);
gtk_box_reorder_child (box, year, 0);
gtk_box_reorder_child (box, day, -1);
break;
case DATE_ENDIANESS_MIDDLE:
/* Let's please GCC */
g_assert_not_reached ();
break;
}
}
static void
cc_date_time_panel_init (CcDateTimePanel *self)
{
CcDateTimePanelPrivate *priv;
gchar *objects[] = { "datetime-panel", "region-liststore", "city-liststore",
"month-liststore", "city-modelfilter", "city-modelsort", NULL };
char *buttons[] = { "hour_up_button", "hour_down_button", "min_up_button",
"min_down_button", "ampm_up_button", "ampm_down_button" };
GtkWidget *widget;
GtkAdjustment *adjustment;
GError *err = NULL;
GtkTreeModelFilter *city_modelfilter;
GtkTreeModelSort *city_modelsort;
guint i, num_days;
gboolean using_ntp;
gboolean can_use_ntp;
int ret;
DateEndianess endianess;
GError *error;
priv = self->priv = DATE_TIME_PANEL_PRIVATE (self);
priv->cancellable = g_cancellable_new ();
error = NULL;
priv->dtm = date_time_mechanism_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
"org.gnome.SettingsDaemon.DateTimeMechanism",
"/",
priv->cancellable,
&error);
if (priv->dtm == NULL) {
g_warning ("could not get proxy for DateTimeMechanism: %s", error->message);
g_error_free (error);
}
priv->builder = gtk_builder_new ();
ret = gtk_builder_add_objects_from_file (priv->builder, DATADIR"/datetime.ui",
objects, &err);
if (ret == 0)
{
g_warning ("Could not load ui: %s", err ? err->message : "No reason");
if (err)
g_error_free (err);
return;
}
/* set up network time button */
error = NULL;
using_ntp = can_use_ntp = FALSE;
if (!date_time_mechanism_call_get_using_ntp_sync (priv->dtm,
&can_use_ntp,
&using_ntp,
priv->cancellable,
&error))
{
g_warning ("Failed to get using ntp: %s", error->message);
g_error_free (error);
}
gtk_switch_set_active (GTK_SWITCH (W("network_time_switch")), using_ntp);
update_widget_state_for_ntp (self, using_ntp);
g_signal_connect (W("network_time_switch"), "notify::active",
G_CALLBACK (change_ntp), self);
/* set up time editing widgets */
for (i = 0; i < G_N_ELEMENTS (buttons); i++)
{
g_signal_connect (W(buttons[i]), "clicked",
G_CALLBACK (change_time), self);
}
/* set up date editing widgets */
priv->date = g_date_time_new_now_local ();
endianess = date_endian_get_default (FALSE);
reorder_date_widget (endianess, priv);
/* Force the direction for the time, so that the time
* is presented correctly for RTL languages */
gtk_widget_set_direction (W("table2"), GTK_TEXT_DIR_LTR);
gtk_combo_box_set_active (GTK_COMBO_BOX (W ("month-combobox")),
g_date_time_get_month (priv->date) - 1);
g_signal_connect (G_OBJECT (W("month-combobox")), "changed",
G_CALLBACK (month_year_changed), self);
num_days = g_date_get_days_in_month (g_date_time_get_month (priv->date),
g_date_time_get_year (priv->date));
adjustment = (GtkAdjustment*) gtk_adjustment_new (g_date_time_get_day_of_month (priv->date), 1,
num_days + 1, 1, 10, 1);
gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (W ("day-spinbutton")),
adjustment);
g_signal_connect (G_OBJECT (W("day-spinbutton")), "value-changed",
G_CALLBACK (day_changed), self);
adjustment = (GtkAdjustment*) gtk_adjustment_new (g_date_time_get_year (priv->date),
G_MINDOUBLE, G_MAXDOUBLE, 1,
10, 1);
gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (W ("year-spinbutton")),
adjustment);
g_signal_connect (G_OBJECT (W("year-spinbutton")), "value-changed",
G_CALLBACK (month_year_changed), self);
/* set up timezone map */
priv->map = widget = (GtkWidget *) cc_timezone_map_new ();
gtk_widget_show (widget);
gtk_container_add (GTK_CONTAINER (gtk_builder_get_object (priv->builder,
"aspectmap")),
widget);
gtk_container_add (GTK_CONTAINER (self),
GTK_WIDGET (gtk_builder_get_object (priv->builder,
"datetime-panel")));
/* setup the time itself */
priv->settings = g_settings_new (CLOCK_SCHEMA);
clock_settings_changed_cb (priv->settings, CLOCK_FORMAT_KEY, self);
g_signal_connect (priv->settings, "changed::" CLOCK_FORMAT_KEY,
G_CALLBACK (clock_settings_changed_cb), self);
g_signal_connect (W("24h_time_switch"), "notify::active",
G_CALLBACK (change_clock_settings), self);
update_time (self);
priv->locations = (GtkTreeModel*) gtk_builder_get_object (priv->builder,
"region-liststore");
load_regions_model (GTK_LIST_STORE (priv->locations),
GTK_LIST_STORE (gtk_builder_get_object (priv->builder,
"city-liststore")));
city_modelfilter = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (priv->builder, "city-modelfilter"));
widget = (GtkWidget*) gtk_builder_get_object (priv->builder,
"region_combobox");
city_modelsort = GTK_TREE_MODEL_SORT (gtk_builder_get_object (priv->builder, "city-modelsort"));
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (city_modelsort), CITY_COL_CITY_TRANSLATED,
GTK_SORT_ASCENDING);
gtk_tree_model_filter_set_visible_func (city_modelfilter,
(GtkTreeModelFilterVisibleFunc) city_model_filter_func,
widget,
NULL);
/* After the initial setup, so we can be sure that
* the model is filled up */
date_time_mechanism_call_get_timezone (priv->dtm,
priv->cancellable,
get_timezone_cb,
self);
queue_clock_update (self);
/* add the lock button */
priv->permission = polkit_permission_new_sync ("org.gnome.settingsdaemon.datetimemechanism.configure", NULL, NULL, NULL);
if (priv->permission == NULL)
{
g_warning ("Your system does not have the '%s' PolicyKit files installed. Please check your installation",
"org.gnome.settingsdaemon.datetimemechanism.configure");
return;
}
g_signal_connect (priv->permission, "notify",
G_CALLBACK (on_permission_changed), self);
on_permission_changed (priv->permission, NULL, self);
}
void
cc_date_time_panel_register (GIOModule *module)
{
bind_textdomain_codeset (GETTEXT_PACKAGE_TIMEZONES, "UTF-8");
cc_date_time_panel_register_type (G_TYPE_MODULE (module));
g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
CC_TYPE_DATE_TIME_PANEL,
"datetime", 0);
}