aboutsummaryrefslogtreecommitdiff
path: root/src/datetime-prefs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/datetime-prefs.c')
-rw-r--r--src/datetime-prefs.c176
1 files changed, 145 insertions, 31 deletions
diff --git a/src/datetime-prefs.c b/src/datetime-prefs.c
index e69d58b..5248911 100644
--- a/src/datetime-prefs.c
+++ b/src/datetime-prefs.c
@@ -30,6 +30,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <locale.h>
#include <langinfo.h>
#include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <unique/unique.h>
#include <polkitgtk/polkitgtk.h>
@@ -46,6 +47,11 @@ GDBusProxy * proxy = NULL;
GtkWidget * auto_radio = NULL;
GtkWidget * tz_entry = NULL;
CcTimezoneMap * tzmap = NULL;
+GtkWidget * time_spin = NULL;
+GtkWidget * date_spin = NULL;
+guint save_time_id = 0;
+gboolean user_edited_time = FALSE;
+gboolean changing_time = FALSE;
/* Turns the boolean property into a string gsettings */
static GVariant *
@@ -238,13 +244,60 @@ void proxy_ready (GObject *object, GAsyncResult *res, gpointer user_data)
NULL, tz_query_answered, NULL);
}
+static gboolean
+are_spinners_focused (void)
+{
+ // save_time_id means that we were in focus and haven't finished our save
+ // yet, so act like we are still focused.
+ return save_time_id || gtk_widget_has_focus (time_spin) || gtk_widget_has_focus (date_spin);
+}
+
+static gboolean
+save_time (gpointer user_data)
+{
+ if (user_edited_time) {
+ gdouble current_value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (date_spin));
+ g_dbus_proxy_call (proxy, "SetTime", g_variant_new ("(x)", (guint64)current_value),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, dbus_set_answered, "time");
+ }
+ user_edited_time = FALSE;
+ save_time_id = 0;
+ return FALSE;
+}
+
+static gboolean
+spin_focus_in (void)
+{
+ if (save_time_id > 0) {
+ g_source_remove (save_time_id);
+ save_time_id = 0;
+ }
+ return FALSE;
+}
+
+static gboolean
+spin_focus_out (void)
+{
+ /* We want to only save when both spinners are unfocused. But it's difficult
+ to tell who is about to get focus during a focus-out. So we set an idle
+ callback to save the time if we don't focus in to another spinner by that
+ time. */
+ if (save_time_id == 0) {
+ save_time_id = g_idle_add ((GSourceFunc)save_time, NULL);
+ }
+ return FALSE;
+}
+
static int
-input_time_text (GtkWidget * spinner, gdouble *value, gpointer user_data)
+input_time_text (GtkWidget * spinner, gdouble * value, gpointer user_data)
{
gboolean is_time = (gboolean)GPOINTER_TO_INT (g_object_get_data (G_OBJECT (spinner), "is-time"));
const gchar * text = gtk_entry_get_text (GTK_ENTRY (spinner));
- GDateTime * now = g_date_time_new_now_local ();
+ gdouble current_value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (spinner));
+ *value = current_value;
+
+ GDateTime * now = g_date_time_new_from_unix_local (current_value);
gint year, month, day, hour, minute, second;
year = g_date_time_get_year (now);
month = g_date_time_get_month (now);
@@ -315,10 +368,13 @@ input_time_text (GtkWidget * spinner, gdouble *value, gpointer user_data)
return TRUE;
}
- GDateTime * datetime = g_date_time_new_local (year, month, day, hour, minute, second);
-
- g_dbus_proxy_call (proxy, "SetTime", g_variant_new ("(x)", g_date_time_to_unix (datetime)),
- G_DBUS_CALL_FLAGS_NONE, -1, NULL, dbus_set_answered, "time");
+ gboolean prev_changing = changing_time;
+ changing_time = TRUE;
+ GDateTime * new_time = g_date_time_new_local (year, month, day, hour, minute, second);
+ *value = g_date_time_to_unix (new_time);
+ user_edited_time = TRUE;
+ g_date_time_unref (new_time);
+ changing_time = prev_changing;
return TRUE;
}
@@ -326,12 +382,6 @@ input_time_text (GtkWidget * spinner, gdouble *value, gpointer user_data)
static gboolean
format_time_text (GtkWidget * spinner, gpointer user_data)
{
- if (gtk_widget_has_focus (spinner)) {
- /* Don't do anything if we have focus, user is likely editing us */
- return TRUE;
- }
-
- GDateTime * datetime = (GDateTime *)g_object_get_data (G_OBJECT (spinner), "datetime");
gboolean is_time = (gboolean)GPOINTER_TO_INT (g_object_get_data (G_OBJECT (spinner), "is-time"));
const gchar * format;
@@ -346,39 +396,71 @@ format_time_text (GtkWidget * spinner, gpointer user_data)
format = "%Y-%m-%d";
}
+ GDateTime * datetime = g_date_time_new_from_unix_local (gtk_spin_button_get_value (GTK_SPIN_BUTTON (spinner)));
gchar * formatted = g_date_time_format (datetime, format);
gtk_entry_set_text (GTK_ENTRY (spinner), formatted);
+ g_date_time_unref (datetime);
return TRUE;
}
+static void
+spin_copy_value (GtkSpinButton * spinner, GtkSpinButton * other)
+{
+ if (gtk_spin_button_get_value (spinner) != gtk_spin_button_get_value (other)) {
+ gtk_spin_button_set_value (other, gtk_spin_button_get_value (spinner));
+ }
+ if (!changing_time) { /* Means user pressed spin buttons */
+ user_edited_time = TRUE;
+ }
+}
+
static gboolean
-update_spinner (GtkWidget * spinner)
+update_spinners (void)
{
/* Add datetime object to spinner, which will hold the real time value, rather
- then using the value of the spinner itself. */
- GDateTime * datetime = g_date_time_new_now_local ();
- g_object_set_data_full (G_OBJECT (spinner), "datetime", datetime, (GDestroyNotify)g_date_time_unref);
-
- format_time_text (spinner, NULL);
-
+ then using the value of the spinner itself. And don't update while user is
+ editing. */
+ if (!are_spinners_focused ()) {
+ gboolean prev_changing = changing_time;
+ changing_time = TRUE;
+ GDateTime * now = g_date_time_new_now_local ();
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (time_spin), (gdouble)g_date_time_to_unix (now));
+ /* will be copied to other spin button */
+ g_date_time_unref (now);
+ changing_time = prev_changing;
+ }
return TRUE;
}
static void
-setup_time_spinner (GtkWidget * spinner, GtkWidget * other, gboolean is_time)
+setup_time_spinners (GtkWidget * time, GtkWidget * date)
{
- /* Set up spinner to have reasonable behavior */
- gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner), FALSE);
- g_signal_connect (spinner, "input", G_CALLBACK (input_time_text), other);
- g_signal_connect (spinner, "output", G_CALLBACK (format_time_text), other);
- g_object_set_data (G_OBJECT (spinner), "is-time", GINT_TO_POINTER (is_time));
+ g_signal_connect (time, "input", G_CALLBACK (input_time_text), date);
+ g_signal_connect (date, "input", G_CALLBACK (input_time_text), time);
- /* 2 seconds is what the indicator itself uses */
- guint time_id = g_timeout_add_seconds (2, (GSourceFunc)update_spinner, spinner);
- g_signal_connect_swapped (spinner, "destroy", G_CALLBACK (g_source_remove), GINT_TO_POINTER (time_id));
+ g_signal_connect (time, "output", G_CALLBACK (format_time_text), date);
+ g_signal_connect (date, "output", G_CALLBACK (format_time_text), time);
+
+ g_signal_connect (time, "focus-in-event", G_CALLBACK (spin_focus_in), date);
+ g_signal_connect (date, "focus-in-event", G_CALLBACK (spin_focus_in), time);
- update_spinner (spinner);
+ g_signal_connect (time, "focus-out-event", G_CALLBACK (spin_focus_out), date);
+ g_signal_connect (date, "focus-out-event", G_CALLBACK (spin_focus_out), time);
+
+ g_signal_connect (time, "value-changed", G_CALLBACK (spin_copy_value), date);
+ g_signal_connect (date, "value-changed", G_CALLBACK (spin_copy_value), time);
+
+ g_object_set_data (G_OBJECT (time), "is-time", GINT_TO_POINTER (TRUE));
+ g_object_set_data (G_OBJECT (date), "is-time", GINT_TO_POINTER (FALSE));
+
+ time_spin = time;
+ date_spin = date;
+
+ /* 2 seconds is what the indicator itself uses */
+ guint time_id = g_timeout_add_seconds (2, (GSourceFunc)update_spinners, NULL);
+ g_signal_connect_swapped (time_spin, "destroy", G_CALLBACK (g_source_remove), GINT_TO_POINTER (time_id));
+ update_spinners ();
}
static void
@@ -426,6 +508,32 @@ timezone_selected (GtkEntryCompletion * widget, GtkTreeModel * model,
return FALSE; // Do normal action too
}
+static gboolean
+key_pressed (GtkWidget * widget, GdkEventKey * event, gpointer user_data)
+{
+ switch (event->keyval) {
+ case GDK_KEY_Escape:
+ gtk_widget_destroy (widget);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static GtkWidget *
+get_child_of_type (GtkContainer * parent, GType type)
+{
+ GList * children, * iter;
+
+ children = gtk_container_get_children (parent);
+ for (iter = children; iter; iter = iter->next) {
+ if (G_TYPE_CHECK_INSTANCE_TYPE (iter->data, type)) {
+ return GTK_WIDGET (iter->data);
+ }
+ }
+
+ return NULL;
+}
+
static GtkWidget *
create_dialog (void)
{
@@ -451,6 +559,11 @@ create_dialog (void)
polkit_lock_button_set_unlock_text (POLKIT_LOCK_BUTTON (polkit_button), _("Unlock to change these settings"));
polkit_lock_button_set_lock_text (POLKIT_LOCK_BUTTON (polkit_button), _("Lock to prevent further changes"));
gtk_box_pack_start (GTK_BOX (WIG ("timeDateBox")), polkit_button, FALSE, TRUE, 0);
+ /* Make sure border around button is visible */
+ GtkWidget * polkit_button_button = get_child_of_type (GTK_CONTAINER (polkit_button), GTK_TYPE_BUTTON);
+ if (polkit_button_button != NULL) {
+ gtk_button_set_relief (GTK_BUTTON (polkit_button_button), GTK_RELIEF_NORMAL);
+ }
/* Add map */
tzmap = cc_timezone_map_new ();
@@ -505,14 +618,14 @@ create_dialog (void)
gtk_widget_set_sensitive (WIG ("showEventsCheck"), (evo_path != NULL));
g_free (evo_path);
- setup_time_spinner (WIG ("timeSpinner"), WIG ("dateSpinner"), TRUE);
- setup_time_spinner (WIG ("dateSpinner"), WIG ("timeSpinner"), FALSE);
+ setup_time_spinners (WIG ("timeSpinner"), WIG ("dateSpinner"));
GtkWidget * dlg = WIG ("timeDateDialog");
auto_radio = WIG ("automaticTimeRadio");
tz_entry = WIG ("timezoneEntry");
g_signal_connect (WIG ("locationsButton"), "clicked", G_CALLBACK (show_locations), dlg);
+ g_signal_connect (dlg, "key-press-event", G_CALLBACK (key_pressed), NULL);
/* Grab proxy for settings daemon */
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL,
@@ -566,6 +679,7 @@ main (int argc, char ** argv)
gtk_widget_show_all (dlg);
g_signal_connect (dlg, "response", G_CALLBACK(gtk_main_quit), NULL);
+ g_signal_connect (dlg, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main ();
}