X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkswitch.c;h=dfcfedc4bd351664ebbe959f2ceb984646212547;hb=32aa7f0582febb614c41e4130ad34ac44ef6efd2;hp=d69534c1ed69175ed44bb3be1e3c4514538a076c;hpb=46cc85fd7e0ff20c83254713f1092e7207c788f8;p=~andy%2Fgtk diff --git a/gtk/gtkswitch.c b/gtk/gtkswitch.c index d69534c1e..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 "gtkaccessibleprivate.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,7 +78,9 @@ enum PROP_ACTIVE, PROP_RELATED_ACTION, PROP_USE_ACTION_APPEARANCE, - LAST_PROP + LAST_PROP, + PROP_ACTION_NAME, + PROP_ACTION_TARGET }; enum @@ -89,11 +93,12 @@ static guint signals[LAST_SIGNAL] = { 0 }; static GParamSpec *switch_props[LAST_PROP] = { NULL, }; -static GType gtk_switch_accessible_factory_get_type (void); - +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)); @@ -114,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; @@ -127,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; @@ -139,7 +144,7 @@ gtk_switch_button_press (GtkWidget *widget, "gtk-dnd-drag-threshold", &priv->drag_threshold, NULL); - return FALSE; + return TRUE; } static gboolean @@ -162,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; @@ -293,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, @@ -346,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, @@ -428,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 @@ -438,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; } @@ -474,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, @@ -500,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; @@ -513,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); @@ -567,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); @@ -583,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); @@ -594,21 +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)) - { - _gtk_accessible_set_factory_type (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) @@ -637,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, @@ -659,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); } @@ -686,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); } @@ -696,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); @@ -756,7 +835,6 @@ 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->get_accessible = gtk_switch_get_accessible; klass->activate = gtk_switch_activate; @@ -792,6 +870,10 @@ gtk_switch_class_init (GtkSwitchClass *klass) 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 @@ -842,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)); } @@ -935,210 +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 */ - -typedef struct _GtkSwitchAccessible GtkSwitchAccessible; -typedef struct _GtkSwitchAccessibleClass GtkSwitchAccessibleClass; - -struct _GtkSwitchAccessible -{ - GtkAccessible object; - - gchar *description; - guint action_idle; -}; - -static void atk_action_interface_init (AtkActionIface *iface); - -ATK_DEFINE_TYPE_WITH_CODE (GtkSwitchAccessible, _gtk_switch_accessible, GTK_TYPE_SWITCH, - G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)) - -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_finalize (GObject *obj) -{ - GtkSwitchAccessible *accessible = (GtkSwitchAccessible *)obj; - - g_free (accessible->description); - - if (accessible->action_idle) - g_source_remove (accessible->action_idle); - - G_OBJECT_CLASS (_gtk_switch_accessible_parent_class)->finalize (obj); -} - -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) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); - - object_class->finalize = gtk_switch_accessible_finalize; - - 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) -{ - self->description = NULL; - self->action_idle = 0; -} - -/* accessibility: action interface */ - -static gint -gtk_switch_action_get_n_actions (AtkAction *action) -{ - return 1; -} - -static const gchar * -gtk_switch_action_get_name (AtkAction *action, - gint i) -{ - return "toggle"; -} - -static const gchar * -gtk_switch_action_get_description (AtkAction *action, - gint i) -{ - GtkSwitchAccessible *accessible = (GtkSwitchAccessible*)action; - - return accessible->description; -} - -static gboolean -gtk_switch_action_set_description (AtkAction *action, - gint i, - const gchar *description) -{ - GtkSwitchAccessible *accessible = (GtkSwitchAccessible*)action; - - g_free (accessible->description); - accessible->description = g_strdup (description); - - return TRUE; -} - -static gboolean -idle_do_action (gpointer data) -{ - GtkSwitchAccessible *accessible = data; - GtkWidget *widget; - GtkSwitch *sw; - - widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (data)); - sw = GTK_SWITCH (widget); - - accessible->action_idle = 0; - - if (widget == NULL || - !gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget)) - return FALSE; - - gtk_switch_set_active (sw, !gtk_switch_get_active (sw)); - - return FALSE; -} - -static gboolean -gtk_switch_action_do_action (AtkAction *action, - gint i) -{ - GtkSwitchAccessible *accessible; - GtkWidget *widget; - - widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action)); - if (widget == NULL) - return FALSE; - - if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget)) - return FALSE; - - accessible = (GtkSwitchAccessible *)action; - - if (!accessible->action_idle) - accessible->action_idle = gdk_threads_add_idle (idle_do_action, accessible); - - return TRUE; -} - -static void -atk_action_interface_init (AtkActionIface *iface) -{ - iface->do_action = gtk_switch_action_do_action; - iface->get_n_actions = gtk_switch_action_get_n_actions; - iface->get_name = gtk_switch_action_get_name; - iface->get_description = gtk_switch_action_get_description; - iface->set_description = gtk_switch_action_set_description; -} - -/* 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) -{ -}