From 822c2aba36ca0fdb67dc6dee182219fc4f0e91dc Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 9 Apr 2020 20:24:23 -0400 Subject: [PATCH] scalebutton: Don't derive from GtkButton Make GtkScaleButton a widget that has a toggle button as a child, just like all the other button widgets now. The immediate benefit of this arrangement is to avoid the "double focus" problem when we pop up the popup. Update accessible, demos and tests to match. --- demos/widget-factory/widget-factory.c | 35 +--- demos/widget-factory/widget-factory.ui | 1 - gtk/a11y/gtkscalebuttonaccessible.c | 2 +- gtk/a11y/gtkscalebuttonaccessible.h | 4 +- gtk/gtkscalebutton.c | 158 +++++++++--------- gtk/ui/gtkscalebutton.ui | 11 +- gtk/ui/gtkvolumebutton.ui | 18 +- testsuite/gtk/focus-chain/widget-factory2.tab | 4 +- .../focus-chain/widget-factory2.tab-backward | 4 +- 9 files changed, 104 insertions(+), 133 deletions(-) diff --git a/demos/widget-factory/widget-factory.c b/demos/widget-factory/widget-factory.c index 0d78b1bb89..56088fcca5 100644 --- a/demos/widget-factory/widget-factory.c +++ b/demos/widget-factory/widget-factory.c @@ -442,24 +442,17 @@ on_entry_icon_release (GtkEntry *entry, #define EPSILON (1e-10) -static gboolean -on_scale_button_query_tooltip (GtkWidget *button, - gint x, - gint y, - gboolean keyboard_mode, - GtkTooltip *tooltip, - gpointer user_data) +static void +on_scale_button_value_changed (GtkScaleButton *button, + gdouble value, + gpointer user_data) { - GtkScaleButton *scale_button = GTK_SCALE_BUTTON (button); GtkAdjustment *adjustment; gdouble val; gchar *str; - AtkImage *image; - image = ATK_IMAGE (gtk_widget_get_accessible (button)); - - adjustment = gtk_scale_button_get_adjustment (scale_button); - val = gtk_scale_button_get_value (scale_button); + adjustment = gtk_scale_button_get_adjustment (button); + val = gtk_scale_button_get_value (button); if (val < (gtk_adjustment_get_lower (adjustment) + EPSILON)) { @@ -478,19 +471,10 @@ on_scale_button_query_tooltip (GtkWidget *button, str = g_strdup_printf (C_("volume percentage", "%d %%"), percent); } - gtk_tooltip_set_text (tooltip, str); - atk_image_set_image_description (image, str); + gtk_widget_set_tooltip_text (GTK_WIDGET (button), str); + atk_object_set_description (gtk_widget_get_accessible (GTK_WIDGET (button)), str); + g_free (str); - - return TRUE; -} - -static void -on_scale_button_value_changed (GtkScaleButton *button, - gdouble value, - gpointer user_data) -{ - gtk_widget_trigger_tooltip_query (GTK_WIDGET (button)); } static void @@ -1774,7 +1758,6 @@ activate (GApplication *app) gtk_builder_cscope_add_callback_symbols (GTK_BUILDER_CSCOPE (scope), "on_entry_icon_release", (GCallback)on_entry_icon_release, "on_scale_button_value_changed", (GCallback)on_scale_button_value_changed, - "on_scale_button_query_tooltip", (GCallback)on_scale_button_query_tooltip, "on_record_button_toggled", (GCallback)on_record_button_toggled, "on_page_combo_changed", (GCallback)on_page_combo_changed, "on_range_from_changed", (GCallback)on_range_from_changed, diff --git a/demos/widget-factory/widget-factory.ui b/demos/widget-factory/widget-factory.ui index 4d8b74e8c8..7e8df27601 100644 --- a/demos/widget-factory/widget-factory.ui +++ b/demos/widget-factory/widget-factory.ui @@ -1510,7 +1510,6 @@ microphone-sensitivity-medium-symbolic center .5 center - 0 diff --git a/gtk/a11y/gtkscalebuttonaccessible.c b/gtk/a11y/gtkscalebuttonaccessible.c index 1db9db7ba8..98b685382a 100644 --- a/gtk/a11y/gtkscalebuttonaccessible.c +++ b/gtk/a11y/gtkscalebuttonaccessible.c @@ -27,7 +27,7 @@ static void atk_action_interface_init (AtkActionIface *iface); static void atk_value_interface_init (AtkValueIface *iface); -G_DEFINE_TYPE_WITH_CODE (GtkScaleButtonAccessible, gtk_scale_button_accessible, GTK_TYPE_BUTTON_ACCESSIBLE, +G_DEFINE_TYPE_WITH_CODE (GtkScaleButtonAccessible, gtk_scale_button_accessible, GTK_TYPE_WIDGET_ACCESSIBLE, G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init) G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init)); diff --git a/gtk/a11y/gtkscalebuttonaccessible.h b/gtk/a11y/gtkscalebuttonaccessible.h index f5f1d4e17e..2437cda587 100644 --- a/gtk/a11y/gtkscalebuttonaccessible.h +++ b/gtk/a11y/gtkscalebuttonaccessible.h @@ -39,14 +39,14 @@ typedef struct _GtkScaleButtonAccessiblePrivate GtkScaleButtonAccessiblePrivate; struct _GtkScaleButtonAccessible { - GtkButtonAccessible parent; + GtkWidgetAccessible parent; GtkScaleButtonAccessiblePrivate *priv; }; struct _GtkScaleButtonAccessibleClass { - GtkButtonAccessibleClass parent_class; + GtkWidgetAccessibleClass parent_class; }; GDK_AVAILABLE_IN_ALL diff --git a/gtk/gtkscalebutton.c b/gtk/gtkscalebutton.c index 76c2173d49..809e790857 100644 --- a/gtk/gtkscalebutton.c +++ b/gtk/gtkscalebutton.c @@ -39,7 +39,7 @@ #include "gtkadjustment.h" #include "gtkbox.h" #include "gtkbuttonprivate.h" -#include "gtkimage.h" +#include "gtktogglebutton.h" #include "gtkeventcontrollerscroll.h" #include "gtkframe.h" #include "gtkgesture.h" @@ -52,6 +52,7 @@ #include "gtkrangeprivate.h" #include "gtkscale.h" #include "gtktypebuiltins.h" +#include "gtkwidgetprivate.h" #include "gtkwindowprivate.h" #include "gtknative.h" @@ -102,12 +103,13 @@ enum typedef struct { + GtkWidget *button; + GtkWidget *plus_button; GtkWidget *minus_button; GtkWidget *dock; GtkWidget *box; GtkWidget *scale; - GtkWidget *image; GtkWidget *active_button; GtkOrientation orientation; @@ -139,9 +141,15 @@ static void gtk_scale_button_size_allocate (GtkWidget *widget, int width, int height, int baseline); +static void gtk_scale_button_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline); static void gtk_scale_button_set_orientation_private (GtkScaleButton *button, GtkOrientation orientation); -static void gtk_scale_button_clicked (GtkButton *button); static void gtk_scale_button_popup (GtkWidget *widget); static void gtk_scale_button_popdown (GtkWidget *widget); static void cb_button_clicked (GtkWidget *button, @@ -157,10 +165,9 @@ static gboolean gtk_scale_button_scroll_controller_scroll (GtkEventControllerScr gdouble dy, GtkScaleButton *button); -G_DEFINE_TYPE_WITH_CODE (GtkScaleButton, gtk_scale_button, GTK_TYPE_BUTTON, +G_DEFINE_TYPE_WITH_CODE (GtkScaleButton, gtk_scale_button, GTK_TYPE_WIDGET, G_ADD_PRIVATE (GtkScaleButton) - G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, - NULL)) + G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)) static guint signals[LAST_SIGNAL] = { 0, }; @@ -169,7 +176,6 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass); gobject_class->constructed = gtk_scale_button_constructed; gobject_class->finalize = gtk_scale_button_finalize; @@ -177,9 +183,11 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass) gobject_class->set_property = gtk_scale_button_set_property; gobject_class->get_property = gtk_scale_button_get_property; + widget_class->measure = gtk_scale_button_measure; widget_class->size_allocate = gtk_scale_button_size_allocate; + widget_class->focus = gtk_widget_focus_child; + widget_class->grab_focus = gtk_widget_grab_focus_child; - button_class->clicked = gtk_scale_button_clicked; /** * GtkScaleButton:orientation: @@ -326,19 +334,19 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkscalebutton.ui"); + gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, button); gtk_widget_class_bind_template_child_internal_private (widget_class, GtkScaleButton, plus_button); gtk_widget_class_bind_template_child_internal_private (widget_class, GtkScaleButton, minus_button); gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, dock); gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, box); gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, scale); - gtk_widget_class_bind_template_child_private (widget_class, GtkScaleButton, image); gtk_widget_class_bind_template_callback (widget_class, cb_button_clicked); gtk_widget_class_bind_template_callback (widget_class, cb_scale_value_changed); gtk_widget_class_bind_template_callback (widget_class, cb_popup_mapped); gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SCALE_BUTTON_ACCESSIBLE); - gtk_widget_class_set_css_name (widget_class, I_("button")); + gtk_widget_class_set_css_name (widget_class, I_("scalebutton")); } static gboolean @@ -373,6 +381,28 @@ button_pressed_cb (GtkGesture *gesture, priv->autoscroll_timeout = g_timeout_add (200, start_autoscroll, button); } +static void +gtk_scale_button_toggled (GtkScaleButton *button) +{ + GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button); + gboolean active; + + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button)); + + if (active) + gtk_popover_popup (GTK_POPOVER (priv->dock)); + else + gtk_popover_popdown (GTK_POPOVER (priv->dock)); +} + +static void +gtk_scale_button_closed (GtkScaleButton *button) +{ + GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), FALSE); +} + static void gtk_scale_button_init (GtkScaleButton *button) { @@ -399,6 +429,11 @@ gtk_scale_button_init (GtkScaleButton *button) button); gtk_widget_add_controller (GTK_WIDGET (button), controller); + g_signal_connect_swapped (priv->dock, "closed", + G_CALLBACK (gtk_scale_button_closed), button); + g_signal_connect_swapped (priv->button, "toggled", + G_CALLBACK (gtk_scale_button_toggled), button); + g_signal_connect (gtk_button_get_gesture (GTK_BUTTON (priv->plus_button)), "pressed", G_CALLBACK (button_pressed_cb), button); g_signal_connect (gtk_button_get_gesture (GTK_BUTTON (priv->minus_button)), @@ -505,6 +540,7 @@ gtk_scale_button_dispose (GObject *object) GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button); g_clear_pointer (&priv->dock, gtk_widget_unparent); + g_clear_pointer (&priv->button, gtk_widget_unparent); if (priv->click_id != 0) { @@ -722,43 +758,6 @@ gtk_scale_button_get_popup (GtkScaleButton *button) return priv->dock; } -static void -apply_orientation (GtkScaleButton *button, - GtkOrientation orientation) -{ - GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button); - - if (priv->applied_orientation != orientation) - { - priv->applied_orientation = orientation; - gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->box), orientation); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - gtk_box_reorder_child_after (GTK_BOX (priv->box), priv->plus_button, NULL); - gtk_box_reorder_child_after (GTK_BOX (priv->box), priv->scale, NULL); - } - else - { - gtk_box_reorder_child_after (GTK_BOX (priv->box), priv->scale, NULL); - gtk_box_reorder_child_after (GTK_BOX (priv->box), priv->plus_button, NULL); - } - - gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->scale), orientation); - - if (orientation == GTK_ORIENTATION_VERTICAL) - { - gtk_widget_set_size_request (GTK_WIDGET (priv->scale), -1, SCALE_SIZE); - gtk_range_set_inverted (GTK_RANGE (priv->scale), TRUE); - } - else - { - gtk_widget_set_size_request (GTK_WIDGET (priv->scale), SCALE_SIZE, -1); - gtk_range_set_inverted (GTK_RANGE (priv->scale), FALSE); - } - } -} - static void gtk_scale_button_set_orientation_private (GtkScaleButton *button, GtkOrientation orientation) @@ -798,34 +797,13 @@ gtk_scale_button_scroll_controller_scroll (GtkEventControllerScroll *scroll, * button callbacks. */ -static gboolean +static void gtk_scale_popup (GtkWidget *widget) { GtkScaleButton *button = GTK_SCALE_BUTTON (widget); GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button); - GtkWidget *toplevel; - GtkBorder border; - GtkRequisition req; - gint w, h; - gint size; - gtk_popover_popup (GTK_POPOVER (priv->dock)); - - toplevel = GTK_WIDGET (gtk_widget_get_root (widget)); - _gtk_window_get_shadow_width (GTK_WINDOW (toplevel), &border); - w = gtk_widget_get_allocated_width (toplevel) - border.left - border.right; - h = gtk_widget_get_allocated_height (toplevel) - border.top - border.bottom; - gtk_widget_get_preferred_size (priv->dock, NULL, &req); - size = MAX (req.width, req.height); - - if (size > w) - apply_orientation (button, GTK_ORIENTATION_VERTICAL); - else if (size > h) - apply_orientation (button, GTK_ORIENTATION_HORIZONTAL); - else - apply_orientation (button, priv->orientation); - - return TRUE; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), TRUE); } static void @@ -834,13 +812,7 @@ gtk_scale_button_popdown (GtkWidget *widget) GtkScaleButton *button = GTK_SCALE_BUTTON (widget); GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button); - gtk_popover_popdown (GTK_POPOVER (priv->dock)); -} - -static void -gtk_scale_button_clicked (GtkButton *button) -{ - gtk_scale_popup (GTK_WIDGET (button)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), FALSE); } static void @@ -918,7 +890,7 @@ gtk_scale_button_update_icon (GtkScaleButton *button) if (!priv->icon_list || priv->icon_list[0][0] == '\0') { - gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), "image-missing"); + gtk_button_set_icon_name (GTK_BUTTON (priv->button), "image-missing"); return; } @@ -927,7 +899,7 @@ gtk_scale_button_update_icon (GtkScaleButton *button) /* The 1-icon special case */ if (num_icons == 1) { - gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), priv->icon_list[0]); + gtk_button_set_icon_name (GTK_BUTTON (priv->button), priv->icon_list[0]); return; } @@ -945,7 +917,7 @@ gtk_scale_button_update_icon (GtkScaleButton *button) else name = priv->icon_list[1]; - gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), name); + gtk_button_set_icon_name (GTK_BUTTON (priv->button), name); return; } @@ -968,7 +940,7 @@ gtk_scale_button_update_icon (GtkScaleButton *button) name = priv->icon_list[i]; } - gtk_image_set_from_icon_name (GTK_IMAGE (priv->image), name); + gtk_button_set_icon_name (GTK_BUTTON (priv->button), name); } static void @@ -1003,6 +975,26 @@ cb_popup_mapped (GtkWidget *popup, gtk_widget_grab_focus (priv->scale); } +static void +gtk_scale_button_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkScaleButton *button = GTK_SCALE_BUTTON (widget); + GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button); + + gtk_widget_measure (priv->button, + orientation, + for_size, + minimum, natural, + minimum_baseline, natural_baseline); + +} + static void gtk_scale_button_size_allocate (GtkWidget *widget, int width, @@ -1012,7 +1004,9 @@ gtk_scale_button_size_allocate (GtkWidget *widget, GtkScaleButton *button = GTK_SCALE_BUTTON (widget); GtkScaleButtonPrivate *priv = gtk_scale_button_get_instance_private (button); - GTK_WIDGET_CLASS (gtk_scale_button_parent_class)->size_allocate (widget, width, height, baseline); + gtk_widget_size_allocate (priv->button, + &(GtkAllocation) { 0, 0, width, height }, + baseline); gtk_native_check_resize (GTK_NATIVE (priv->dock)); } diff --git a/gtk/ui/gtkscalebutton.ui b/gtk/ui/gtkscalebutton.ui index 1714b8b126..f7611fa481 100644 --- a/gtk/ui/gtkscalebutton.ui +++ b/gtk/ui/gtkscalebutton.ui @@ -1,13 +1,12 @@ -