1 /* GTK - The GIMP Toolkit
3 * Copyright (C) 2010 Intel Corporation
4 * Copyright (C) 2010 RedHat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 * Emmanuele Bassi <ebassi@linux.intel.com>
21 * Matthias Clasen <mclasen@redhat.com>
23 * Based on similar code from Mx.
28 * @Short_Description: A "light switch" style toggle
30 * @See_Also: #GtkToggleButton
32 * #GtkSwitch is a widget that has two states: on or off. The user can control
33 * which state should be active by clicking the empty area, or by dragging the
39 #include "gtkswitch.h"
41 #include "gtkactivatable.h"
43 #include "gtkprivate.h"
44 #include "gtktoggleaction.h"
45 #include "gtkwidget.h"
46 #include "gtkmarshalers.h"
47 #include "gtkapplicationprivate.h"
48 #include "gtkactionable.h"
49 #include "a11y/gtkswitchaccessible.h"
50 #include "gtkactionhelper.h"
54 #define DEFAULT_SLIDER_WIDTH (36)
55 #define DEFAULT_SLIDER_HEIGHT (22)
57 struct _GtkSwitchPrivate
59 GdkWindow *event_window;
61 GtkActionHelper *action_helper;
69 guint is_dragging : 1;
72 guint use_action_appearance : 1;
80 PROP_USE_ACTION_APPEARANCE,
92 static guint signals[LAST_SIGNAL] = { 0 };
94 static GParamSpec *switch_props[LAST_PROP] = { NULL, };
96 static void gtk_switch_actionable_iface_init (GtkActionableInterface *iface);
97 static void gtk_switch_activatable_interface_init (GtkActivatableIface *iface);
99 G_DEFINE_TYPE_WITH_CODE (GtkSwitch, gtk_switch, GTK_TYPE_WIDGET,
100 G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE,
101 gtk_switch_actionable_iface_init)
102 G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
103 gtk_switch_activatable_interface_init));
106 gtk_switch_button_press (GtkWidget *widget,
107 GdkEventButton *event)
109 GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
110 GtkAllocation allocation;
112 gtk_widget_get_allocation (widget, &allocation);
116 /* if the event occurred in the "off" area, then this
119 if (event->x <= allocation.width / 2)
121 priv->in_press = TRUE;
125 priv->offset = event->x - allocation.width / 2;
129 /* if the event occurred in the "on" area, then this
132 if (event->x >= allocation.width / 2)
134 priv->in_press = TRUE;
138 priv->offset = event->x;
141 priv->drag_start = event->x;
143 g_object_get (gtk_widget_get_settings (widget),
144 "gtk-dnd-drag-threshold", &priv->drag_threshold,
151 gtk_switch_motion (GtkWidget *widget,
152 GdkEventMotion *event)
154 GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
156 /* if this is a direct toggle we don't handle motion */
160 if (ABS (event->x - priv->drag_start) < priv->drag_threshold)
163 if (event->state & GDK_BUTTON1_MASK)
165 gint position = event->x - priv->offset;
166 GtkAllocation allocation;
167 GtkStyleContext *context;
170 gint width, focus_width, focus_pad;
172 gtk_widget_style_get (widget,
173 "focus-line-width", &focus_width,
174 "focus-padding", &focus_pad,
177 context = gtk_widget_get_style_context (widget);
178 state = gtk_widget_get_state_flags (widget);
180 gtk_style_context_save (context);
181 gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER);
182 gtk_style_context_get_padding (context, state, &padding);
183 gtk_style_context_restore (context);
185 gtk_widget_get_allocation (widget, &allocation);
187 width = allocation.width - 2 * (focus_width + focus_pad);
189 /* constrain the handle within the trough width */
190 if (position > (width / 2) - padding.right)
191 priv->handle_x = width / 2 - padding.right;
192 else if (position < padding.left)
195 priv->handle_x = position;
197 priv->is_dragging = TRUE;
199 /* we need to redraw the handle */
200 gtk_widget_queue_draw (widget);
209 gtk_switch_button_release (GtkWidget *widget,
210 GdkEventButton *event)
212 GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
213 GtkAllocation allocation;
215 gtk_widget_get_allocation (widget, &allocation);
217 /* dragged toggles have a "soft" grab, so we don't care whether we
218 * are in the switch or not when the button is released; we do care
219 * for direct toggles, instead
221 if (!priv->is_dragging && !priv->in_switch)
227 priv->in_press = FALSE;
228 gtk_switch_set_active (GTK_SWITCH (widget), !priv->is_active);
233 /* toggle the switch if the handle was clicked but a drag had not been
235 if (!priv->is_dragging && !priv->in_press)
237 gtk_switch_set_active (GTK_SWITCH (widget), !priv->is_active);
243 if (priv->is_dragging)
245 priv->is_dragging = FALSE;
247 /* if half the handle passed the middle of the switch, then we
248 * consider it to be on
250 if ((priv->handle_x + (allocation.width / 4)) >= (allocation.width / 2))
252 gtk_switch_set_active (GTK_SWITCH (widget), TRUE);
253 priv->handle_x = allocation.width / 2;
257 gtk_switch_set_active (GTK_SWITCH (widget), FALSE);
261 gtk_widget_queue_draw (widget);
270 gtk_switch_enter (GtkWidget *widget,
271 GdkEventCrossing *event)
273 GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
275 if (event->window == priv->event_window)
276 priv->in_switch = TRUE;
282 gtk_switch_leave (GtkWidget *widget,
283 GdkEventCrossing *event)
285 GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
287 if (event->window == priv->event_window)
288 priv->in_switch = FALSE;
294 gtk_switch_activate (GtkSwitch *sw)
296 GtkSwitchPrivate *priv = sw->priv;
298 gtk_switch_set_active (sw, !priv->is_active);
302 gtk_switch_get_preferred_width (GtkWidget *widget,
306 GtkStyleContext *context;
309 gint width, slider_width, focus_width, focus_pad;
311 PangoRectangle logical_rect;
313 context = gtk_widget_get_style_context (widget);
314 state = gtk_style_context_get_state (context);
316 gtk_style_context_save (context);
318 gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER);
319 gtk_style_context_get_padding (context, state, &padding);
321 width = padding.left + padding.right;
323 gtk_style_context_restore (context);
325 gtk_widget_style_get (widget,
326 "slider-width", &slider_width,
327 "focus-line-width", &focus_width,
328 "focus-padding", &focus_pad,
331 width += 2 * (focus_width + focus_pad);
333 /* Translators: if the "on" state label requires more than three
334 * glyphs then use MEDIUM VERTICAL BAR (U+2759) as the text for
337 layout = gtk_widget_create_pango_layout (widget, C_("switch", "ON"));
338 pango_layout_get_extents (layout, NULL, &logical_rect);
339 pango_extents_to_pixels (&logical_rect, NULL);
340 width += MAX (logical_rect.width, slider_width);
342 /* Translators: if the "off" state label requires more than three
343 * glyphs then use WHITE CIRCLE (U+25CB) as the text for the state
345 pango_layout_set_text (layout, C_("switch", "OFF"), -1);
346 pango_layout_get_extents (layout, NULL, &logical_rect);
347 pango_extents_to_pixels (&logical_rect, NULL);
348 width += MAX (logical_rect.width, slider_width);
350 g_object_unref (layout);
360 gtk_switch_get_preferred_height (GtkWidget *widget,
364 GtkStyleContext *context;
367 gint height, focus_width, focus_pad;
369 PangoRectangle logical_rect;
372 context = gtk_widget_get_style_context (widget);
373 state = gtk_style_context_get_state (context);
375 gtk_style_context_save (context);
377 gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER);
378 gtk_style_context_get_padding (context, state, &padding);
380 height = padding.top + padding.bottom;
382 gtk_style_context_restore (context);
384 gtk_widget_style_get (widget,
385 "focus-line-width", &focus_width,
386 "focus-padding", &focus_pad,
389 height += 2 * (focus_width + focus_pad);
391 str = g_strdup_printf ("%s%s",
393 C_("switch", "OFF"));
395 layout = gtk_widget_create_pango_layout (widget, str);
396 pango_layout_get_extents (layout, NULL, &logical_rect);
397 pango_extents_to_pixels (&logical_rect, NULL);
398 height += MAX (DEFAULT_SLIDER_HEIGHT, logical_rect.height);
400 g_object_unref (layout);
411 gtk_switch_size_allocate (GtkWidget *widget,
412 GtkAllocation *allocation)
414 GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
416 gtk_widget_set_allocation (widget, allocation);
418 if (gtk_widget_get_realized (widget))
419 gdk_window_move_resize (priv->event_window,
427 gtk_switch_realize (GtkWidget *widget)
429 GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
430 GdkWindow *parent_window;
431 GdkWindowAttr attributes;
432 gint attributes_mask;
433 GtkAllocation allocation;
435 gtk_widget_set_realized (widget, TRUE);
436 parent_window = gtk_widget_get_parent_window (widget);
437 gtk_widget_set_window (widget, parent_window);
438 g_object_ref (parent_window);
440 gtk_widget_get_allocation (widget, &allocation);
442 attributes.window_type = GDK_WINDOW_CHILD;
443 attributes.wclass = GDK_INPUT_ONLY;
444 attributes.x = allocation.x;
445 attributes.y = allocation.y;
446 attributes.width = allocation.width;
447 attributes.height = allocation.height;
448 attributes.event_mask = gtk_widget_get_events (widget);
449 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
450 GDK_BUTTON_RELEASE_MASK |
451 GDK_BUTTON1_MOTION_MASK |
452 GDK_POINTER_MOTION_HINT_MASK |
453 GDK_POINTER_MOTION_MASK |
454 GDK_ENTER_NOTIFY_MASK |
455 GDK_LEAVE_NOTIFY_MASK);
456 attributes_mask = GDK_WA_X | GDK_WA_Y;
458 priv->event_window = gdk_window_new (parent_window,
461 gdk_window_set_user_data (priv->event_window, widget);
465 gtk_switch_unrealize (GtkWidget *widget)
467 GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
469 if (priv->event_window != NULL)
471 gdk_window_set_user_data (priv->event_window, NULL);
472 gdk_window_destroy (priv->event_window);
473 priv->event_window = NULL;
476 GTK_WIDGET_CLASS (gtk_switch_parent_class)->unrealize (widget);
480 gtk_switch_map (GtkWidget *widget)
482 GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
484 GTK_WIDGET_CLASS (gtk_switch_parent_class)->map (widget);
486 if (priv->event_window)
487 gdk_window_show (priv->event_window);
491 gtk_switch_unmap (GtkWidget *widget)
493 GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
495 if (priv->event_window)
496 gdk_window_hide (priv->event_window);
498 GTK_WIDGET_CLASS (gtk_switch_parent_class)->unmap (widget);
502 gtk_switch_paint_handle (GtkWidget *widget,
506 GtkStyleContext *context = gtk_widget_get_style_context (widget);
508 gtk_style_context_save (context);
509 gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER);
511 gtk_render_slider (context, cr,
513 box->width, box->height,
514 GTK_ORIENTATION_HORIZONTAL);
516 gtk_style_context_restore (context);
520 gtk_switch_draw (GtkWidget *widget,
523 GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv;
524 GtkStyleContext *context;
527 PangoFontDescription *desc;
528 const PangoFontDescription *style_desc;
530 gint label_x, label_y;
533 gint focus_width, focus_pad;
534 gint x, y, width, height;
535 gint font_size, style_font_size;
537 gtk_widget_style_get (widget,
538 "focus-line-width", &focus_width,
539 "focus-padding", &focus_pad,
542 context = gtk_widget_get_style_context (widget);
543 state = gtk_widget_get_state_flags (widget);
545 gtk_style_context_save (context);
547 gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER);
549 gtk_style_context_get_padding (context, state, &padding);
551 gtk_style_context_restore (context);
555 width = gtk_widget_get_allocated_width (widget);
556 height = gtk_widget_get_allocated_height (widget);
558 if (gtk_widget_has_visible_focus (widget))
559 gtk_render_focus (context, cr, x, y, width, height);
561 x += focus_width + focus_pad;
562 y += focus_width + focus_pad;
563 width -= 2 * (focus_width + focus_pad);
564 height -= 2 * (focus_width + focus_pad);
566 gtk_style_context_save (context);
567 gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH);
569 gtk_render_background (context, cr, x, y, width, height);
570 gtk_render_frame (context, cr, x, y, width, height);
572 width -= padding.left + padding.right;
573 height -= padding.top + padding.bottom;
579 handle.width = width / 2;
580 handle.height = height;
582 /* Translators: if the "on" state label requires more than three
583 * glyphs then use MEDIUM VERTICAL BAR (U+2759) as the text for
586 layout = gtk_widget_create_pango_layout (widget, C_("switch", "ON"));
588 /* FIXME: this should be really done in the theme, but overriding font size
589 * from it doesn't currently work. So we have to hardcode this here and
590 * below for the "OFF" label.
592 desc = pango_font_description_new ();
594 style_desc = gtk_style_context_get_font (context, state);
595 style_font_size = pango_font_description_get_size (style_desc);
596 font_size = MAX (style_font_size - 1 * PANGO_SCALE, ceil (style_font_size * PANGO_SCALE_SMALL));
598 pango_font_description_set_size (desc, font_size);
600 pango_layout_set_font_description (layout, desc);
602 pango_layout_get_extents (layout, NULL, &rect);
603 pango_extents_to_pixels (&rect, NULL);
605 label_x = x + ((width / 2) - rect.width) / 2;
606 label_y = y + (height - rect.height) / 2;
608 gtk_render_layout (context, cr, label_x, label_y, layout);
610 g_object_unref (layout);
612 /* Translators: if the "off" state label requires more than three
613 * glyphs then use WHITE CIRCLE (U+25CB) as the text for the state
615 layout = gtk_widget_create_pango_layout (widget, C_("switch", "OFF"));
616 pango_layout_set_font_description (layout, desc);
618 pango_layout_get_extents (layout, NULL, &rect);
619 pango_extents_to_pixels (&rect, NULL);
621 label_x = x + (width / 2) + ((width / 2) - rect.width) / 2;
622 label_y = y + (height - rect.height) / 2;
624 gtk_render_layout (context, cr, label_x, label_y, layout);
626 g_object_unref (layout);
628 if (priv->is_dragging)
629 handle.x = x + priv->handle_x;
630 else if (priv->is_active)
631 handle.x = x + width - handle.width;
635 gtk_style_context_restore (context);
637 gtk_switch_paint_handle (widget, cr, &handle);
639 pango_font_description_free (desc);
645 gtk_switch_set_related_action (GtkSwitch *sw,
648 GtkSwitchPrivate *priv = sw->priv;
650 if (priv->action == action)
653 gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (sw), action);
655 priv->action = action;
659 gtk_switch_set_use_action_appearance (GtkSwitch *sw,
660 gboolean use_appearance)
662 GtkSwitchPrivate *priv = sw->priv;
664 if (priv->use_action_appearance != use_appearance)
666 priv->use_action_appearance = use_appearance;
668 gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (sw), priv->action);
673 gtk_switch_set_action_name (GtkActionable *actionable,
674 const gchar *action_name)
676 GtkSwitch *sw = GTK_SWITCH (actionable);
678 if (!sw->priv->action_helper)
679 sw->priv->action_helper = gtk_action_helper_new (actionable);
681 gtk_action_helper_set_action_name (sw->priv->action_helper, action_name);
685 gtk_switch_set_action_target_value (GtkActionable *actionable,
686 GVariant *action_target)
688 GtkSwitch *sw = GTK_SWITCH (actionable);
690 if (!sw->priv->action_helper)
691 sw->priv->action_helper = gtk_action_helper_new (actionable);
693 gtk_action_helper_set_action_target_value (sw->priv->action_helper, action_target);
697 gtk_switch_get_action_name (GtkActionable *actionable)
699 GtkSwitch *sw = GTK_SWITCH (actionable);
701 return gtk_action_helper_get_action_name (sw->priv->action_helper);
705 gtk_switch_get_action_target_value (GtkActionable *actionable)
707 GtkSwitch *sw = GTK_SWITCH (actionable);
709 return gtk_action_helper_get_action_target_value (sw->priv->action_helper);
713 gtk_switch_actionable_iface_init (GtkActionableInterface *iface)
715 iface->get_action_name = gtk_switch_get_action_name;
716 iface->set_action_name = gtk_switch_set_action_name;
717 iface->get_action_target_value = gtk_switch_get_action_target_value;
718 iface->set_action_target_value = gtk_switch_set_action_target_value;
722 gtk_switch_set_property (GObject *gobject,
727 GtkSwitch *sw = GTK_SWITCH (gobject);
732 gtk_switch_set_active (sw, g_value_get_boolean (value));
735 case PROP_RELATED_ACTION:
736 gtk_switch_set_related_action (sw, g_value_get_object (value));
739 case PROP_USE_ACTION_APPEARANCE:
740 gtk_switch_set_use_action_appearance (sw, g_value_get_boolean (value));
743 case PROP_ACTION_NAME:
744 gtk_switch_set_action_name (GTK_ACTIONABLE (sw), g_value_get_string (value));
747 case PROP_ACTION_TARGET:
748 gtk_switch_set_action_target_value (GTK_ACTIONABLE (sw), g_value_get_variant (value));
752 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
757 gtk_switch_get_property (GObject *gobject,
762 GtkSwitchPrivate *priv = GTK_SWITCH (gobject)->priv;
767 g_value_set_boolean (value, priv->is_active);
770 case PROP_RELATED_ACTION:
771 g_value_set_object (value, priv->action);
774 case PROP_USE_ACTION_APPEARANCE:
775 g_value_set_boolean (value, priv->use_action_appearance);
778 case PROP_ACTION_NAME:
779 g_value_set_string (value, gtk_action_helper_get_action_name (priv->action_helper));
782 case PROP_ACTION_TARGET:
783 g_value_set_variant (value, gtk_action_helper_get_action_target_value (priv->action_helper));
787 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
792 gtk_switch_dispose (GObject *object)
794 GtkSwitchPrivate *priv = GTK_SWITCH (object)->priv;
796 g_clear_object (&priv->action_helper);
800 gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (object), NULL);
804 G_OBJECT_CLASS (gtk_switch_parent_class)->dispose (object);
808 gtk_switch_class_init (GtkSwitchClass *klass)
810 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
811 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
812 gpointer activatable_iface;
814 g_type_class_add_private (klass, sizeof (GtkSwitchPrivate));
816 activatable_iface = g_type_default_interface_peek (GTK_TYPE_ACTIVATABLE);
817 switch_props[PROP_RELATED_ACTION] =
818 g_param_spec_override ("related-action",
819 g_object_interface_find_property (activatable_iface,
822 switch_props[PROP_USE_ACTION_APPEARANCE] =
823 g_param_spec_override ("use-action-appearance",
824 g_object_interface_find_property (activatable_iface,
825 "use-action-appearance"));
830 * Whether the #GtkSwitch widget is in its on or off state.
832 switch_props[PROP_ACTIVE] =
833 g_param_spec_boolean ("active",
835 P_("Whether the switch is on or off"),
837 GTK_PARAM_READWRITE);
839 gobject_class->set_property = gtk_switch_set_property;
840 gobject_class->get_property = gtk_switch_get_property;
841 gobject_class->dispose = gtk_switch_dispose;
843 g_object_class_install_properties (gobject_class, LAST_PROP, switch_props);
845 widget_class->get_preferred_width = gtk_switch_get_preferred_width;
846 widget_class->get_preferred_height = gtk_switch_get_preferred_height;
847 widget_class->size_allocate = gtk_switch_size_allocate;
848 widget_class->realize = gtk_switch_realize;
849 widget_class->unrealize = gtk_switch_unrealize;
850 widget_class->map = gtk_switch_map;
851 widget_class->unmap = gtk_switch_unmap;
852 widget_class->draw = gtk_switch_draw;
853 widget_class->button_press_event = gtk_switch_button_press;
854 widget_class->button_release_event = gtk_switch_button_release;
855 widget_class->motion_notify_event = gtk_switch_motion;
856 widget_class->enter_notify_event = gtk_switch_enter;
857 widget_class->leave_notify_event = gtk_switch_leave;
859 klass->activate = gtk_switch_activate;
862 * GtkSwitch:slider-width:
864 * The minimum width of the #GtkSwitch handle, in pixels.
866 gtk_widget_class_install_style_property (widget_class,
867 g_param_spec_int ("slider-width",
869 P_("The minimum width of the handle"),
870 DEFAULT_SLIDER_WIDTH, G_MAXINT,
871 DEFAULT_SLIDER_WIDTH,
872 GTK_PARAM_READABLE));
875 * GtkSwitch::activate:
876 * @widget: the object which received the signal.
878 * The ::activate signal on GtkSwitch is an action signal and
879 * emitting it causes the switch to animate.
880 * Applications should never connect to this signal, but use the
881 * notify::active signal.
884 g_signal_new (I_("activate"),
885 G_OBJECT_CLASS_TYPE (gobject_class),
886 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
887 G_STRUCT_OFFSET (GtkSwitchClass, activate),
889 _gtk_marshal_VOID__VOID,
891 widget_class->activate_signal = signals[ACTIVATE];
893 g_object_class_override_property (gobject_class, PROP_ACTION_NAME, "action-name");
894 g_object_class_override_property (gobject_class, PROP_ACTION_TARGET, "action-target");
896 gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SWITCH_ACCESSIBLE);
900 gtk_switch_init (GtkSwitch *self)
902 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTK_TYPE_SWITCH, GtkSwitchPrivate);
903 self->priv->use_action_appearance = TRUE;
904 gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
905 gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
911 * Creates a new #GtkSwitch widget.
913 * Return value: the newly created #GtkSwitch instance
918 gtk_switch_new (void)
920 return g_object_new (GTK_TYPE_SWITCH, NULL);
924 * gtk_switch_set_active:
926 * @is_active: %TRUE if @sw should be active, and %FALSE otherwise
928 * Changes the state of @sw to the desired one.
933 gtk_switch_set_active (GtkSwitch *sw,
936 GtkSwitchPrivate *priv;
938 g_return_if_fail (GTK_IS_SWITCH (sw));
940 is_active = !!is_active;
944 if (priv->is_active != is_active)
946 AtkObject *accessible;
948 priv->is_active = is_active;
950 g_object_notify_by_pspec (G_OBJECT (sw), switch_props[PROP_ACTIVE]);
952 if (priv->action_helper)
953 gtk_action_helper_activate (priv->action_helper);
956 gtk_action_activate (priv->action);
958 accessible = gtk_widget_get_accessible (GTK_WIDGET (sw));
959 atk_object_notify_state_change (accessible, ATK_STATE_CHECKED, priv->is_active);
962 gtk_widget_set_state_flags (GTK_WIDGET (sw), GTK_STATE_FLAG_ACTIVE, FALSE);
964 gtk_widget_unset_state_flags (GTK_WIDGET (sw), GTK_STATE_FLAG_ACTIVE);
966 gtk_widget_queue_draw (GTK_WIDGET (sw));
971 * gtk_switch_get_active:
974 * Gets whether the #GtkSwitch is in its "on" or "off" state.
976 * Return value: %TRUE if the #GtkSwitch is active, and %FALSE otherwise
981 gtk_switch_get_active (GtkSwitch *sw)
983 g_return_val_if_fail (GTK_IS_SWITCH (sw), FALSE);
985 return sw->priv->is_active;
989 gtk_switch_update (GtkActivatable *activatable,
991 const gchar *property_name)
993 if (strcmp (property_name, "visible") == 0)
995 if (gtk_action_is_visible (action))
996 gtk_widget_show (GTK_WIDGET (activatable));
998 gtk_widget_hide (GTK_WIDGET (activatable));
1000 else if (strcmp (property_name, "sensitive") == 0)
1002 gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
1004 else if (strcmp (property_name, "active") == 0)
1006 gtk_action_block_activate (action);
1007 gtk_switch_set_active (GTK_SWITCH (activatable), gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
1008 gtk_action_unblock_activate (action);
1013 gtk_switch_sync_action_properties (GtkActivatable *activatable,
1019 if (gtk_action_is_visible (action))
1020 gtk_widget_show (GTK_WIDGET (activatable));
1022 gtk_widget_hide (GTK_WIDGET (activatable));
1024 gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
1026 gtk_action_block_activate (action);
1027 gtk_switch_set_active (GTK_SWITCH (activatable), gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
1028 gtk_action_unblock_activate (action);
1032 gtk_switch_activatable_interface_init (GtkActivatableIface *iface)
1034 iface->update = gtk_switch_update;
1035 iface->sync_action_properties = gtk_switch_sync_action_properties;