X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkswitch.c;h=dfcfedc4bd351664ebbe959f2ceb984646212547;hb=3c04597306a918317cb96d6c267fc73a798c04e4;hp=ce1402b071fe82f3502d8d8d45a07d48a42ec027;hpb=cb21085187d08eea561ccb1dc887bee4c6c66d32;p=~andy%2Fgtk diff --git a/gtk/gtkswitch.c b/gtk/gtkswitch.c index ce1402b07..dfcfedc4b 100644 --- a/gtk/gtkswitch.c +++ b/gtk/gtkswitch.c @@ -14,9 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . * * Author: * Emmanuele Bassi @@ -40,15 +38,18 @@ #include "gtkswitch.h" -#include - -#include "gtkaccessible.h" #include "gtkactivatable.h" #include "gtkintl.h" -#include "gtkstyle.h" #include "gtkprivate.h" #include "gtktoggleaction.h" #include "gtkwidget.h" +#include "gtkmarshalers.h" +#include "gtkapplicationprivate.h" +#include "gtkactionable.h" +#include "a11y/gtkswitchaccessible.h" +#include "gtkactionhelper.h" + +#include #define DEFAULT_SLIDER_WIDTH (36) #define DEFAULT_SLIDER_HEIGHT (22) @@ -57,6 +58,7 @@ struct _GtkSwitchPrivate { GdkWindow *event_window; GtkAction *action; + GtkActionHelper *action_helper; gint handle_x; gint offset; @@ -76,16 +78,27 @@ enum PROP_ACTIVE, PROP_RELATED_ACTION, PROP_USE_ACTION_APPEARANCE, - LAST_PROP + LAST_PROP, + PROP_ACTION_NAME, + PROP_ACTION_TARGET }; -static GParamSpec *switch_props[LAST_PROP] = { NULL, }; +enum +{ + ACTIVATE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; -static GType gtk_switch_accessible_factory_get_type (void); +static GParamSpec *switch_props[LAST_PROP] = { NULL, }; +static void gtk_switch_actionable_iface_init (GtkActionableInterface *iface); static void gtk_switch_activatable_interface_init (GtkActivatableIface *iface); G_DEFINE_TYPE_WITH_CODE (GtkSwitch, gtk_switch, GTK_TYPE_WIDGET, + G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, + gtk_switch_actionable_iface_init) G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE, gtk_switch_activatable_interface_init)); @@ -106,7 +119,7 @@ gtk_switch_button_press (GtkWidget *widget, if (event->x <= allocation.width / 2) { priv->in_press = TRUE; - return FALSE; + return TRUE; } priv->offset = event->x - allocation.width / 2; @@ -119,7 +132,7 @@ gtk_switch_button_press (GtkWidget *widget, if (event->x >= allocation.width / 2) { priv->in_press = TRUE; - return FALSE; + return TRUE; } priv->offset = event->x; @@ -131,7 +144,7 @@ gtk_switch_button_press (GtkWidget *widget, "gtk-dnd-drag-threshold", &priv->drag_threshold, NULL); - return FALSE; + return TRUE; } static gboolean @@ -154,17 +167,30 @@ gtk_switch_motion (GtkWidget *widget, GtkStyleContext *context; GtkStateFlags state; GtkBorder padding; + gint width, focus_width, focus_pad; + + gtk_widget_style_get (widget, + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + NULL); context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); + + gtk_style_context_save (context); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER); gtk_style_context_get_padding (context, state, &padding); + gtk_style_context_restore (context); + gtk_widget_get_allocation (widget, &allocation); + width = allocation.width - 2 * (focus_width + focus_pad); + /* constrain the handle within the trough width */ - if (position > (allocation.width / 2 - padding.right)) - priv->handle_x = allocation.width / 2 - padding.right; + if (position > (width / 2) - padding.right) + priv->handle_x = width / 2 - padding.right; else if (position < padding.left) - priv->handle_x = padding.left; + priv->handle_x = 0; else priv->handle_x = position; @@ -204,6 +230,15 @@ gtk_switch_button_release (GtkWidget *widget, return TRUE; } + /* toggle the switch if the handle was clicked but a drag had not been + * initiated */ + if (!priv->is_dragging && !priv->in_press) + { + gtk_switch_set_active (GTK_SWITCH (widget), !priv->is_active); + + return TRUE; + } + /* dragged toggle */ if (priv->is_dragging) { @@ -255,22 +290,12 @@ gtk_switch_leave (GtkWidget *widget, return FALSE; } -static gboolean -gtk_switch_key_release (GtkWidget *widget, - GdkEventKey *event) +static void +gtk_switch_activate (GtkSwitch *sw) { - GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv; - - if (event->keyval == GDK_KEY_Return || - event->keyval == GDK_KEY_KP_Enter || - event->keyval == GDK_KEY_ISO_Enter || - event->keyval == GDK_KEY_space || - event->keyval == GDK_KEY_KP_Space) - { - gtk_switch_set_active (GTK_SWITCH (widget), !priv->is_active); - } + GtkSwitchPrivate *priv = sw->priv; - return FALSE; + gtk_switch_set_active (sw, !priv->is_active); } static void @@ -286,11 +311,17 @@ gtk_switch_get_preferred_width (GtkWidget *widget, PangoRectangle logical_rect; context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); + state = gtk_style_context_get_state (context); + + gtk_style_context_save (context); + + gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER); gtk_style_context_get_padding (context, state, &padding); width = padding.left + padding.right; + gtk_style_context_restore (context); + gtk_widget_style_get (widget, "slider-width", &slider_width, "focus-line-width", &focus_width, @@ -339,11 +370,17 @@ gtk_switch_get_preferred_height (GtkWidget *widget, gchar *str; context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); + state = gtk_style_context_get_state (context); + + gtk_style_context_save (context); + + gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER); gtk_style_context_get_padding (context, state, &padding); height = padding.top + padding.bottom; + gtk_style_context_restore (context); + gtk_widget_style_get (widget, "focus-line-width", &focus_width, "focus-padding", &focus_pad, @@ -421,7 +458,7 @@ gtk_switch_realize (GtkWidget *widget) priv->event_window = gdk_window_new (parent_window, &attributes, attributes_mask); - gdk_window_set_user_data (priv->event_window, widget); + gtk_widget_register_window (widget, priv->event_window); } static void @@ -431,7 +468,7 @@ gtk_switch_unrealize (GtkWidget *widget) if (priv->event_window != NULL) { - gdk_window_set_user_data (priv->event_window, NULL); + gtk_widget_unregister_window (widget, priv->event_window); gdk_window_destroy (priv->event_window); priv->event_window = NULL; } @@ -467,12 +504,8 @@ gtk_switch_paint_handle (GtkWidget *widget, GdkRectangle *box) { GtkStyleContext *context = gtk_widget_get_style_context (widget); - GtkStateFlags state; - - state = gtk_widget_get_state_flags (widget); gtk_style_context_save (context); - gtk_style_context_set_state (context, state); gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER); gtk_render_slider (context, cr, @@ -493,8 +526,8 @@ gtk_switch_draw (GtkWidget *widget, PangoLayout *layout; PangoRectangle rect; gint label_x, label_y; - GtkStateFlags state; GtkBorder padding; + GtkStateFlags state; gint focus_width, focus_pad; gint x, y, width, height; @@ -506,51 +539,54 @@ gtk_switch_draw (GtkWidget *widget, context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); - if (priv->is_active) - state |= GTK_STATE_FLAG_ACTIVE; + gtk_style_context_save (context); + + gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER); gtk_style_context_get_padding (context, state, &padding); + gtk_style_context_restore (context); + x = 0; y = 0; width = gtk_widget_get_allocated_width (widget); height = gtk_widget_get_allocated_height (widget); - if (gtk_widget_has_focus (widget)) + if (gtk_widget_has_visible_focus (widget)) gtk_render_focus (context, cr, x, y, width, height); - gtk_style_context_save (context); - gtk_style_context_set_state (context, state); - x += focus_width + focus_pad; y += focus_width + focus_pad; width -= 2 * (focus_width + focus_pad); height -= 2 * (focus_width + focus_pad); + gtk_style_context_save (context); gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH); gtk_render_background (context, cr, x, y, width, height); gtk_render_frame (context, cr, x, y, width, height); - /* XXX the +1/-1 it's pixel wriggling after checking with the default - * theme and xmag - */ - handle.y = y + padding.top + 1; - handle.width = (width - padding.left - padding.right) / 2; - handle.height = (height - padding.top - padding.bottom) - 1; + width -= padding.left + padding.right; + height -= padding.top + padding.bottom; + + x += padding.left; + y += padding.top; + + handle.y = y; + handle.width = width / 2; + handle.height = height; /* Translators: if the "on" state label requires more than three * glyphs then use MEDIUM VERTICAL BAR (U+2759) as the text for * the state */ layout = gtk_widget_create_pango_layout (widget, C_("switch", "ON")); + pango_layout_get_extents (layout, NULL, &rect); pango_extents_to_pixels (&rect, NULL); - label_x = x + padding.left - + ((width / 2) - rect.width - padding.left - padding.right) / 2; - label_y = y + padding.top - + (height - rect.height - padding.top - padding.bottom) / 2; + label_x = x + ((width / 2) - rect.width) / 2; + label_y = y + (height - rect.height) / 2; gtk_render_layout (context, cr, label_x, label_y, layout); @@ -560,14 +596,12 @@ gtk_switch_draw (GtkWidget *widget, * glyphs then use WHITE CIRCLE (U+25CB) as the text for the state */ layout = gtk_widget_create_pango_layout (widget, C_("switch", "OFF")); + pango_layout_get_extents (layout, NULL, &rect); pango_extents_to_pixels (&rect, NULL); - label_x = x + padding.left - + (width / 2) - + ((width / 2) - rect.width - padding.left - padding.right) / 2; - label_y = y + padding.top - + (height - rect.height - padding.top - padding.bottom) / 2; + label_x = x + (width / 2) + ((width / 2) - rect.width) / 2; + label_y = y + (height - rect.height) / 2; gtk_render_layout (context, cr, label_x, label_y, layout); @@ -576,9 +610,9 @@ gtk_switch_draw (GtkWidget *widget, if (priv->is_dragging) handle.x = x + priv->handle_x; else if (priv->is_active) - handle.x = x + width - handle.width - padding.right; + handle.x = x + width - handle.width; else - handle.x = x + padding.left; + handle.x = x; gtk_style_context_restore (context); @@ -587,38 +621,6 @@ gtk_switch_draw (GtkWidget *widget, return FALSE; } -static AtkObject * -gtk_switch_get_accessible (GtkWidget *widget) -{ - static gboolean first_time = TRUE; - - if (G_UNLIKELY (first_time)) - { - AtkObjectFactory *factory; - AtkRegistry *registry; - GType derived_type; - GType derived_atk_type; - - /* Figure out whether accessibility is enabled by looking at the - * type of the accessible object which would be created for the - * parent type of GtkSwitch - */ - derived_type = g_type_parent (GTK_TYPE_SWITCH); - - registry = atk_get_default_registry (); - factory = atk_registry_get_factory (registry, derived_type); - derived_atk_type = atk_object_factory_get_accessible_type (factory); - if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) - atk_registry_set_factory_type (registry, - GTK_TYPE_SWITCH, - gtk_switch_accessible_factory_get_type ()); - - first_time = FALSE; - } - - return GTK_WIDGET_CLASS (gtk_switch_parent_class)->get_accessible (widget); -} - static void gtk_switch_set_related_action (GtkSwitch *sw, GtkAction *action) @@ -647,6 +649,55 @@ gtk_switch_set_use_action_appearance (GtkSwitch *sw, } } +static void +gtk_switch_set_action_name (GtkActionable *actionable, + const gchar *action_name) +{ + GtkSwitch *sw = GTK_SWITCH (actionable); + + if (!sw->priv->action_helper) + sw->priv->action_helper = gtk_action_helper_new (actionable); + + gtk_action_helper_set_action_name (sw->priv->action_helper, action_name); +} + +static void +gtk_switch_set_action_target_value (GtkActionable *actionable, + GVariant *action_target) +{ + GtkSwitch *sw = GTK_SWITCH (actionable); + + if (!sw->priv->action_helper) + sw->priv->action_helper = gtk_action_helper_new (actionable); + + gtk_action_helper_set_action_target_value (sw->priv->action_helper, action_target); +} + +static const gchar * +gtk_switch_get_action_name (GtkActionable *actionable) +{ + GtkSwitch *sw = GTK_SWITCH (actionable); + + return gtk_action_helper_get_action_name (sw->priv->action_helper); +} + +static GVariant * +gtk_switch_get_action_target_value (GtkActionable *actionable) +{ + GtkSwitch *sw = GTK_SWITCH (actionable); + + return gtk_action_helper_get_action_target_value (sw->priv->action_helper); +} + +static void +gtk_switch_actionable_iface_init (GtkActionableInterface *iface) +{ + iface->get_action_name = gtk_switch_get_action_name; + iface->set_action_name = gtk_switch_set_action_name; + iface->get_action_target_value = gtk_switch_get_action_target_value; + iface->set_action_target_value = gtk_switch_set_action_target_value; +} + static void gtk_switch_set_property (GObject *gobject, guint prop_id, @@ -669,6 +720,14 @@ gtk_switch_set_property (GObject *gobject, gtk_switch_set_use_action_appearance (sw, g_value_get_boolean (value)); break; + case PROP_ACTION_NAME: + gtk_switch_set_action_name (GTK_ACTIONABLE (sw), g_value_get_string (value)); + break; + + case PROP_ACTION_TARGET: + gtk_switch_set_action_target_value (GTK_ACTIONABLE (sw), g_value_get_variant (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } @@ -696,6 +755,14 @@ gtk_switch_get_property (GObject *gobject, g_value_set_boolean (value, priv->use_action_appearance); break; + case PROP_ACTION_NAME: + g_value_set_string (value, gtk_action_helper_get_action_name (priv->action_helper)); + break; + + case PROP_ACTION_TARGET: + g_value_set_variant (value, gtk_action_helper_get_action_target_value (priv->action_helper)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } @@ -706,6 +773,8 @@ gtk_switch_dispose (GObject *object) { GtkSwitchPrivate *priv = GTK_SWITCH (object)->priv; + g_clear_object (&priv->action_helper); + if (priv->action) { gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (object), NULL); @@ -766,8 +835,8 @@ gtk_switch_class_init (GtkSwitchClass *klass) widget_class->motion_notify_event = gtk_switch_motion; widget_class->enter_notify_event = gtk_switch_enter; widget_class->leave_notify_event = gtk_switch_leave; - widget_class->key_release_event = gtk_switch_key_release; - widget_class->get_accessible = gtk_switch_get_accessible; + + klass->activate = gtk_switch_activate; /** * GtkSwitch:slider-width: @@ -781,6 +850,30 @@ gtk_switch_class_init (GtkSwitchClass *klass) DEFAULT_SLIDER_WIDTH, G_MAXINT, DEFAULT_SLIDER_WIDTH, GTK_PARAM_READABLE)); + + /** + * GtkSwitch::activate: + * @widget: the object which received the signal. + * + * The ::activate signal on GtkSwitch is an action signal and + * emitting it causes the switch to animate. + * Applications should never connect to this signal, but use the + * notify::active signal. + */ + signals[ACTIVATE] = + g_signal_new (I_("activate"), + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkSwitchClass, activate), + NULL, NULL, + _gtk_marshal_VOID__VOID, + G_TYPE_NONE, 0); + widget_class->activate_signal = signals[ACTIVATE]; + + g_object_class_override_property (gobject_class, PROP_ACTION_NAME, "action-name"); + g_object_class_override_property (gobject_class, PROP_ACTION_TARGET, "action-target"); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SWITCH_ACCESSIBLE); } static void @@ -831,27 +924,24 @@ gtk_switch_set_active (GtkSwitch *sw, if (priv->is_active != is_active) { AtkObject *accessible; - GtkWidget *widget; - GtkStyleContext *context; - widget = GTK_WIDGET (sw); 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); + if (priv->action) gtk_action_activate (priv->action); accessible = gtk_widget_get_accessible (GTK_WIDGET (sw)); atk_object_notify_state_change (accessible, ATK_STATE_CHECKED, priv->is_active); - if (gtk_widget_get_realized (widget)) - { - context = gtk_widget_get_style_context (widget); - gtk_style_context_notify_state_change (context, - gtk_widget_get_window (widget), - NULL, GTK_STATE_ACTIVE, 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)); } @@ -924,92 +1014,3 @@ gtk_switch_activatable_interface_init (GtkActivatableIface *iface) iface->update = gtk_switch_update; iface->sync_action_properties = gtk_switch_sync_action_properties; } - -/* accessibility: object */ - -/* dummy typedefs */ -typedef struct _GtkSwitchAccessible GtkSwitchAccessible; -typedef struct _GtkSwitchAccessibleClass GtkSwitchAccessibleClass; - -ATK_DEFINE_TYPE (GtkSwitchAccessible, _gtk_switch_accessible, GTK_TYPE_WIDGET); - -static AtkStateSet * -gtk_switch_accessible_ref_state_set (AtkObject *accessible) -{ - AtkStateSet *state_set; - GtkWidget *widget; - - state_set = ATK_OBJECT_CLASS (_gtk_switch_accessible_parent_class)->ref_state_set (accessible); - - widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); - if (widget == NULL) - return state_set; - - if (gtk_switch_get_active (GTK_SWITCH (widget))) - atk_state_set_add_state (state_set, ATK_STATE_CHECKED); - - return state_set; -} - -static void -_gtk_switch_accessible_initialize (AtkObject *accessible, - gpointer widget) -{ - ATK_OBJECT_CLASS (_gtk_switch_accessible_parent_class)->initialize (accessible, widget); - - atk_object_set_role (accessible, ATK_ROLE_TOGGLE_BUTTON); - atk_object_set_name (accessible, C_("light switch widget", "Switch")); - atk_object_set_description (accessible, _("Switches between on and off states")); -} - -static void -_gtk_switch_accessible_class_init (GtkSwitchAccessibleClass *klass) -{ - AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); - - atk_class->initialize = _gtk_switch_accessible_initialize; - atk_class->ref_state_set = gtk_switch_accessible_ref_state_set; -} - -static void -_gtk_switch_accessible_init (GtkSwitchAccessible *self) -{ -} - -/* accessibility: factory */ - -typedef AtkObjectFactoryClass GtkSwitchAccessibleFactoryClass; -typedef AtkObjectFactory GtkSwitchAccessibleFactory; - -G_DEFINE_TYPE (GtkSwitchAccessibleFactory, - gtk_switch_accessible_factory, - ATK_TYPE_OBJECT_FACTORY); - -static GType -gtk_switch_accessible_factory_get_accessible_type (void) -{ - return _gtk_switch_accessible_get_type (); -} - -static AtkObject * -gtk_switch_accessible_factory_create_accessible (GObject *obj) -{ - AtkObject *accessible; - - accessible = g_object_new (_gtk_switch_accessible_get_type (), NULL); - atk_object_initialize (accessible, obj); - - return accessible; -} - -static void -gtk_switch_accessible_factory_class_init (AtkObjectFactoryClass *klass) -{ - klass->create_accessible = gtk_switch_accessible_factory_create_accessible; - klass->get_accessible_type = gtk_switch_accessible_factory_get_accessible_type; -} - -static void -gtk_switch_accessible_factory_init (AtkObjectFactory *factory) -{ -}