From b55ef8d89a8a794d08cffe631a264ba4271e2e0d Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 9 Jan 2020 19:03:38 -0500 Subject: [PATCH] infobar: Activate default action on clicks When we have a default action set on the infobar, activate it for clicks anywhere in the infobar. Also add an .action style class in this case, so we can add a hover highlight to the infobar just for this case. --- gtk/gtkinfobar.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/gtk/gtkinfobar.c b/gtk/gtkinfobar.c index 9b16a2d290..232e8b35f0 100644 --- a/gtk/gtkinfobar.c +++ b/gtk/gtkinfobar.c @@ -50,6 +50,7 @@ #include "gtktypebuiltins.h" #include "gtkwidgetprivate.h" #include "deprecated/gtkstock.h" +#include "gtkgesturemultipress.h" /** * SECTION:gtkinfobar @@ -147,6 +148,10 @@ struct _GtkInfoBarPrivate gboolean show_close_button; GtkMessageType message_type; + int default_response; + gboolean default_response_sensitive; + + GtkGesture *gesture; }; typedef struct _ResponseData ResponseData; @@ -299,6 +304,93 @@ find_button (GtkInfoBar *info_bar, return child; } +static void +update_state (GtkWidget *widget, + gboolean in) +{ + GtkStateFlags state; + + state = gtk_widget_get_state_flags (widget); + if (in) + state |= GTK_STATE_FLAG_PRELIGHT; + else + state &= ~GTK_STATE_FLAG_PRELIGHT; + + gtk_widget_set_state_flags (widget, state, TRUE); +} + +static gboolean +gtk_info_bar_enter_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + if (event->detail != GDK_NOTIFY_INFERIOR) + update_state (widget, TRUE); + + return FALSE; +} + +static gboolean +gtk_info_bar_leave_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + if (event->detail != GDK_NOTIFY_INFERIOR) + update_state (widget, FALSE); + + return FALSE; +} + +static void +gtk_info_bar_realize (GtkWidget *widget) +{ + GtkAllocation allocation; + GdkWindow *window; + GdkWindowAttr attributes; + gint attributes_mask; + + gtk_widget_get_allocation (widget, &allocation); + + gtk_widget_set_realized (widget, TRUE); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.wclass = GDK_INPUT_ONLY; + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_TOUCH_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y; + + window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); + gtk_widget_register_window (widget, window); + gtk_widget_set_window (widget, window); +} + +static void +gtk_info_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GdkWindow *window; + + gtk_widget_set_allocation (widget, allocation); + + window = gtk_widget_get_window (widget); + if (window != NULL) + gdk_window_move_resize (window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + allocation->x = 0; + allocation->y = 0; + + GTK_WIDGET_CLASS (gtk_info_bar_parent_class)->size_allocate (widget, allocation); +} + static void gtk_info_bar_close (GtkInfoBar *info_bar) { @@ -310,6 +402,16 @@ gtk_info_bar_close (GtkInfoBar *info_bar) GTK_RESPONSE_CANCEL); } +static void +gtk_info_bar_finalize (GObject *object) +{ + GtkInfoBar *info_bar = GTK_INFO_BAR (object); + + g_object_unref (info_bar->priv->gesture); + + G_OBJECT_CLASS (gtk_info_bar_parent_class)->finalize (object); +} + static void gtk_info_bar_class_init (GtkInfoBarClass *klass) { @@ -320,9 +422,15 @@ gtk_info_bar_class_init (GtkInfoBarClass *klass) widget_class = GTK_WIDGET_CLASS (klass); object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gtk_info_bar_finalize; object_class->get_property = gtk_info_bar_get_property; object_class->set_property = gtk_info_bar_set_property; + widget_class->realize = gtk_info_bar_realize; + widget_class->enter_notify_event = gtk_info_bar_enter_notify; + widget_class->leave_notify_event = gtk_info_bar_leave_notify; + widget_class->size_allocate = gtk_info_bar_size_allocate; + klass->close = gtk_info_bar_close; /** @@ -498,6 +606,19 @@ close_button_clicked_cb (GtkWidget *button, GTK_RESPONSE_CLOSE); } +static void +click_pressed_cb (GtkGestureMultiPress *gesture, + guint n_press, + gdouble x, + gdouble y, + GtkInfoBar *info_bar) +{ + GtkInfoBarPrivate *priv = gtk_info_bar_get_instance_private (info_bar); + + if (priv->default_response && priv->default_response_sensitive) + gtk_info_bar_response (info_bar, priv->default_response); +} + static void gtk_info_bar_init (GtkInfoBar *info_bar) { @@ -511,11 +632,16 @@ gtk_info_bar_init (GtkInfoBar *info_bar) * during construction */ priv->message_type = GTK_MESSAGE_OTHER; + gtk_widget_set_has_window (widget, TRUE); gtk_widget_init_template (widget); gtk_widget_set_no_show_all (priv->close_button, TRUE); g_signal_connect (priv->close_button, "clicked", G_CALLBACK (close_button_clicked_cb), info_bar); + + priv->gesture = gtk_gesture_multi_press_new (widget); + gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->gesture), GDK_BUTTON_PRIMARY); + g_signal_connect (priv->gesture, "pressed", G_CALLBACK (click_pressed_cb), widget); } static GtkBuildableIface *parent_buildable_iface; @@ -789,6 +915,22 @@ gtk_info_bar_new_with_buttons (const gchar *first_button_text, return GTK_WIDGET (info_bar); } +static void +update_default_response (GtkInfoBar *info_bar, + int response_id, + gboolean sensitive) +{ + GtkInfoBarPrivate *priv = gtk_info_bar_get_instance_private (info_bar); + + priv->default_response = response_id; + priv->default_response_sensitive = sensitive; + + if (response_id && sensitive) + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (info_bar)), "action"); + else + gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (info_bar)), "action"); +} + /** * gtk_info_bar_set_response_sensitive: * @info_bar: a #GtkInfoBar @@ -810,6 +952,9 @@ gtk_info_bar_set_response_sensitive (GtkInfoBar *info_bar, g_return_if_fail (GTK_IS_INFO_BAR (info_bar)); + if (info_bar->priv->default_response == response_id) + info_bar->priv->default_response_sensitive = setting; + children = gtk_container_get_children (GTK_CONTAINER (info_bar->priv->action_area)); for (list = children; list; list = list->next) @@ -822,6 +967,9 @@ gtk_info_bar_set_response_sensitive (GtkInfoBar *info_bar, } g_list_free (children); + + if (response_id == info_bar->priv->default_response) + update_default_response (info_bar, response_id, setting); } /** @@ -843,6 +991,7 @@ gtk_info_bar_set_default_response (GtkInfoBar *info_bar, gint response_id) { GList *children, *list; + gboolean sensitive = TRUE; g_return_if_fail (GTK_IS_INFO_BAR (info_bar)); @@ -854,10 +1003,15 @@ gtk_info_bar_set_default_response (GtkInfoBar *info_bar, ResponseData *rd = get_response_data (widget, FALSE); if (rd && rd->response_id == response_id) - gtk_widget_grab_default (widget); + { + gtk_widget_grab_default (widget); + sensitive = gtk_widget_get_sensitive (widget); + } } g_list_free (children); + + update_default_response (info_bar, response_id, sensitive); } /**