diff options
author | Matthias Clasen <mclasen@redhat.com> | 2014-03-29 13:40:08 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2014-03-29 13:40:08 -0400 |
commit | 870bde59a238520488c0a179b2bac3a4d500eb63 (patch) | |
tree | a5a484eec798efa76e41a378e0177e48cfec1a95 | |
parent | a272de5eba5a12dedc5490178c22129088503d3c (diff) | |
download | gtk+-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.c | 154 | ||||
-rw-r--r-- | gtk/gtkswitch.h | 7 |
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__ */ |