[gtk/gtk-3-24] infobar: Activate default action on clicks



commit b55ef8d89a8a794d08cffe631a264ba4271e2e0d
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Jan 9 19:03:38 2020 -0500

    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);
 }
 
 /**


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]