summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2014-03-29 13:40:08 -0400
committerMatthias Clasen <mclasen@redhat.com>2014-03-29 13:40:08 -0400
commit870bde59a238520488c0a179b2bac3a4d500eb63 (patch)
treea5a484eec798efa76e41a378e0177e48cfec1a95
parenta272de5eba5a12dedc5490178c22129088503d3c (diff)
downloadgtk+-870bde59a238520488c0a179b2bac3a4d500eb63.tar.gz
switch: Add a delayed state capability
This commit makes it possible for GtkSwitch to indicate when the underlying state changes with a delay, causing the switch to temporarily go 'out of sync' with the underlying change. https://bugzilla.gnome.org/show_bug.cgi?id=725648
-rw-r--r--gtk/gtkswitch.c154
-rw-r--r--gtk/gtkswitch.h7
2 files changed, 149 insertions, 12 deletions
diff --git a/gtk/gtkswitch.c b/gtk/gtkswitch.c
index 354e9e514f..f60d2d7845 100644
--- a/gtk/gtkswitch.c
+++ b/gtk/gtkswitch.c
@@ -32,6 +32,9 @@
* #GtkSwitch is a widget that has two states: on or off. The user can control
* which state should be active by clicking the empty area, or by dragging the
* handle.
+ *
+ * GtkSwitch can also handle situations where the underlying state changes with
+ * a delay. See #GtkSwitch::set-state for details.
*/
#include "config.h"
@@ -64,6 +67,7 @@ struct _GtkSwitchPrivate
gint drag_start;
gint drag_threshold;
+ guint state : 1;
guint is_active : 1;
guint is_dragging : 1;
guint in_press : 1;
@@ -75,6 +79,7 @@ enum
{
PROP_0,
PROP_ACTIVE,
+ PROP_STATE,
PROP_RELATED_ACTION,
PROP_USE_ACTION_APPEARANCE,
LAST_PROP,
@@ -85,6 +90,7 @@ enum
enum
{
ACTIVATE,
+ SET_STATE,
LAST_SIGNAL
};
@@ -729,6 +735,10 @@ gtk_switch_set_property (GObject *gobject,
gtk_switch_set_active (sw, g_value_get_boolean (value));
break;
+ case PROP_STATE:
+ gtk_switch_set_state (sw, g_value_get_boolean (value));
+ break;
+
case PROP_RELATED_ACTION:
gtk_switch_set_related_action (sw, g_value_get_object (value));
break;
@@ -764,6 +774,10 @@ gtk_switch_get_property (GObject *gobject,
g_value_set_boolean (value, priv->is_active);
break;
+ case PROP_STATE:
+ g_value_set_boolean (value, priv->state);
+ break;
+
case PROP_RELATED_ACTION:
g_value_set_object (value, priv->action);
break;
@@ -803,6 +817,22 @@ gtk_switch_dispose (GObject *object)
G_OBJECT_CLASS (gtk_switch_parent_class)->dispose (object);
}
+static gboolean
+set_state (GtkSwitch *sw, gboolean state)
+{
+ if (sw->priv->action_helper)
+ gtk_action_helper_activate (sw->priv->action_helper);
+
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+ if (sw->priv->action)
+ gtk_action_activate (sw->priv->action);
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+
+ gtk_switch_set_state (sw, state);
+
+ return TRUE;
+}
+
static void
gtk_switch_class_init (GtkSwitchClass *klass)
{
@@ -836,6 +866,21 @@ gtk_switch_class_init (GtkSwitchClass *klass)
FALSE,
GTK_PARAM_READWRITE);
+ /**
+ * GtkSwitch:state:
+ *
+ * The backend state that is controlled by the switch.
+ * See #GtkSwitch::set-state for details.
+ *
+ * Since: 3.14
+ */
+ switch_props[PROP_STATE] =
+ g_param_spec_boolean ("state",
+ P_("State"),
+ P_("The backend state"),
+ FALSE,
+ GTK_PARAM_READWRITE);
+
gobject_class->set_property = gtk_switch_set_property;
gobject_class->get_property = gtk_switch_get_property;
gobject_class->dispose = gtk_switch_dispose;
@@ -857,6 +902,7 @@ gtk_switch_class_init (GtkSwitchClass *klass)
widget_class->leave_notify_event = gtk_switch_leave;
klass->activate = gtk_switch_activate;
+ klass->set_state = set_state;
/**
* GtkSwitch:slider-width:
@@ -890,6 +936,38 @@ gtk_switch_class_init (GtkSwitchClass *klass)
G_TYPE_NONE, 0);
widget_class->activate_signal = signals[ACTIVATE];
+ /**
+ * GtkSwitch::set-state:
+ * @widget: the object on which the signal was emitted
+ *
+ * The ::set-state signal on GtkSwitch is emitted to change the underlying
+ * state. It is emitted when the user changes the switch position. The
+ * default handler keeps the state in sync with the #GtkState:active
+ * property.
+ *
+ * To implement delayed state change, applications can connect to this signal,
+ * initiate the change of the underlying state, and call gtk_switch_set_state()
+ * when the underlying state change is complete. The signal handler should
+ * return %TRUE to prevent the default handler from running.
+ *
+ * Visually, the underlying state is represented by the trough color of
+ * the switch, while the #GtkSwitch:active property is represented by the
+ * position of the switch.
+ *
+ * Returns: %TRUE to stop the signal emission
+ *
+ * Since: 3.14
+ */
+ signals[SET_STATE] =
+ g_signal_new (I_("set-state"),
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkSwitchClass, set_state),
+ _gtk_boolean_handled_accumulator, NULL,
+ _gtk_marshal_BOOLEAN__BOOLEAN,
+ G_TYPE_BOOLEAN, 1,
+ G_TYPE_BOOLEAN);
+
g_object_class_override_property (gobject_class, PROP_ACTION_NAME, "action-name");
g_object_class_override_property (gobject_class, PROP_ACTION_TARGET, "action-target");
@@ -945,27 +1023,17 @@ gtk_switch_set_active (GtkSwitch *sw,
if (priv->is_active != is_active)
{
AtkObject *accessible;
+ gboolean handled;
priv->is_active = is_active;
g_object_notify_by_pspec (G_OBJECT (sw), switch_props[PROP_ACTIVE]);
- if (priv->action_helper)
- gtk_action_helper_activate (priv->action_helper);
-
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
- if (priv->action)
- gtk_action_activate (priv->action);
- G_GNUC_END_IGNORE_DEPRECATIONS;
+ g_signal_emit (sw, signals[SET_STATE], 0, is_active, &handled);
accessible = gtk_widget_get_accessible (GTK_WIDGET (sw));
atk_object_notify_state_change (accessible, ATK_STATE_CHECKED, priv->is_active);
- if (priv->is_active)
- gtk_widget_set_state_flags (GTK_WIDGET (sw), GTK_STATE_FLAG_ACTIVE, FALSE);
- else
- gtk_widget_unset_state_flags (GTK_WIDGET (sw), GTK_STATE_FLAG_ACTIVE);
-
gtk_widget_queue_draw (GTK_WIDGET (sw));
}
}
@@ -988,6 +1056,68 @@ gtk_switch_get_active (GtkSwitch *sw)
return sw->priv->is_active;
}
+/**
+ * gtk_switch_set_state:
+ * @sw: a #GtkSwitch
+ * @state: the new state
+ *
+ * Sets the underlying state of the #GtkSwitch.
+ *
+ * Normally, this is the same as #GtkSwitch:active, unless the switch
+ * is set up for delayed state changes. This function is typically
+ * called from a #GtkSwitch::set-state signal handler.
+ *
+ * See #GtkSwitch::set-state for details.
+ *
+ * Since: 3.14
+ */
+void
+gtk_switch_set_state (GtkSwitch *sw,
+ gboolean state)
+{
+ g_return_if_fail (GTK_IS_SWITCH (sw));
+
+ state = state != FALSE;
+
+ if (sw->priv->state == state)
+ return;
+
+ sw->priv->state = state;
+
+ /* This will be a no-op if we're switching the state in response
+ * to a UI change. We're setting active anyway, to catch 'spontaneous'
+ * state changes.
+ */
+ gtk_switch_set_active (sw, state);
+
+ if (state)
+ gtk_widget_set_state_flags (GTK_WIDGET (sw), GTK_STATE_FLAG_ACTIVE, FALSE);
+ else
+ gtk_widget_unset_state_flags (GTK_WIDGET (sw), GTK_STATE_FLAG_ACTIVE);
+
+ g_object_notify (G_OBJECT (sw), "state");
+
+ gtk_widget_queue_draw (GTK_WIDGET (sw));
+}
+
+/**
+ * gtk_switch_get_state:
+ * @sw: a #GtkSwitch
+ *
+ * Gets the underlying state of the #GtkSwitch.
+ *
+ * Returns: the underlying state
+ *
+ * Since: 3.14
+ */
+gboolean
+gtk_switch_get_state (GtkSwitch *sw)
+{
+ g_return_val_if_fail (GTK_IS_SWITCH (sw), FALSE);
+
+ return sw->priv->state;
+}
+
static void
gtk_switch_update (GtkActivatable *activatable,
GtkAction *action,
diff --git a/gtk/gtkswitch.h b/gtk/gtkswitch.h
index 70cfd970bd..76cb047369 100644
--- a/gtk/gtkswitch.h
+++ b/gtk/gtkswitch.h
@@ -72,6 +72,7 @@ struct _GtkSwitchClass
void (* activate) (GtkSwitch *sw);
+ gboolean (* set_state) (GtkSwitch *sw, gboolean state);
/*< private >*/
void (* _switch_padding_1) (void);
@@ -94,6 +95,12 @@ void gtk_switch_set_active (GtkSwitch *sw,
GDK_AVAILABLE_IN_ALL
gboolean gtk_switch_get_active (GtkSwitch *sw);
+GDK_AVAILABLE_IN_3_14
+void gtk_switch_set_state (GtkSwitch *sw,
+ gboolean state);
+GDK_AVAILABLE_IN_3_14
+gboolean gtk_switch_get_state (GtkSwitch *sw);
+
G_END_DECLS
#endif /* __GTK_SWITCH_H__ */