[gtk/wip/matthiasc/popup4: 121/140] Introduce event controller propagation limits



commit 06aefb8237d5254cc70567b9e4a798982c08de97
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Apr 29 02:19:44 2019 +0000

    Introduce event controller propagation limits
    
    Limit event handlers by default to only handle
    events targeting the same surface as their widget.

 docs/reference/gtk/gtk4-sections.txt |  3 ++
 gtk/gtkenums.h                       | 17 +++++++
 gtk/gtkeventcontroller.c             | 93 +++++++++++++++++++++++++++++++++++-
 gtk/gtkeventcontroller.h             |  6 +++
 gtk/gtkgesture.c                     |  3 ++
 5 files changed, 121 insertions(+), 1 deletion(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index df2e305f71..68dff2c47d 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -6516,6 +6516,9 @@ GtkEventController
 GtkPropagationPhase
 gtk_event_controller_get_propagation_phase
 gtk_event_controller_set_propagation_phase
+GtkPropagationLimit
+gtk_event_controller_get_propagation_limit
+gtk_event_controller_set_propagation_limit
 gtk_event_controller_handle_event
 gtk_event_controller_get_widget
 gtk_event_controller_reset
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index d18f3f995d..3de47a5565 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -967,6 +967,23 @@ typedef enum
   GTK_PHASE_TARGET
 } GtkPropagationPhase;
 
+/**
+ * GtkPropagationLimit:
+ * @GTK_LIMIT_NONE: Events are handled regardless of what their
+ *   target is.
+ * @GTK_LIMIT_SAME_BUD: Events are only handled if their target
+ *   is on the same #GtkBud as the event controllers widget. Note
+ *   that some event types have two targets (origin and destination).
+ *
+ * Describes limits of a #GtkEventController for handling events
+ * targeting other widgets.
+ */
+typedef enum
+{
+  GTK_LIMIT_NONE,
+  GTK_LIMIT_SAME_BUD
+} GtkPropagationLimit;
+
 /**
  * GtkEventSequenceState:
  * @GTK_EVENT_SEQUENCE_NONE: The sequence is handled, but not grabbed.
diff --git a/gtk/gtkeventcontroller.c b/gtk/gtkeventcontroller.c
index aed43c3d5e..333fa1aa33 100644
--- a/gtk/gtkeventcontroller.c
+++ b/gtk/gtkeventcontroller.c
@@ -32,17 +32,20 @@
 #include "config.h"
 #include "gtkeventcontroller.h"
 #include "gtkeventcontrollerprivate.h"
+
 #include "gtkwidgetprivate.h"
 #include "gtktypebuiltins.h"
 #include "gtkmarshalers.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
+#include "gtkbud.h"
 
 typedef struct _GtkEventControllerPrivate GtkEventControllerPrivate;
 
 enum {
   PROP_WIDGET = 1,
   PROP_PROPAGATION_PHASE,
+  PROP_PROPAGATION_LIMIT,
   LAST_PROP
 };
 
@@ -52,6 +55,7 @@ struct _GtkEventControllerPrivate
 {
   GtkWidget *widget;
   GtkPropagationPhase phase;
+  GtkPropagationLimit limit;
 };
 
 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkEventController, gtk_event_controller, G_TYPE_OBJECT)
@@ -73,6 +77,42 @@ gtk_event_controller_unset_widget (GtkEventController *self)
   priv->widget = NULL;
 }
 
+static gboolean
+gtk_event_controller_filter_event_default (GtkEventController *self,
+                                           const GdkEvent     *event)
+{
+  GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self);
+
+  if (priv->limit == GTK_LIMIT_SAME_BUD)
+    {
+      GtkWidget *bud;
+      GtkWidget *bud2;
+      GtkWidget *target;
+
+      bud = gtk_widget_get_ancestor (priv->widget, GTK_TYPE_BUD);
+
+      target = GTK_WIDGET (gdk_event_get_target (event));
+      if (target)
+        {
+          bud2 = gtk_widget_get_ancestor (target, GTK_TYPE_BUD);
+          if (bud == bud2)
+            return FALSE;
+        }
+
+      target = GTK_WIDGET (gdk_event_get_related_target (event));
+      if (target)
+        {
+          bud2 = gtk_widget_get_ancestor (target, GTK_TYPE_BUD);
+          if (bud == bud2)
+            return FALSE;
+        }
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 static gboolean
 gtk_event_controller_handle_event_default (GtkEventController *self,
                                            const GdkEvent     *event)
@@ -94,6 +134,10 @@ gtk_event_controller_set_property (GObject      *object,
       gtk_event_controller_set_propagation_phase (self,
                                                   g_value_get_enum (value));
       break;
+    case PROP_PROPAGATION_LIMIT:
+      gtk_event_controller_set_propagation_limit (self,
+                                                  g_value_get_enum (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -116,6 +160,9 @@ gtk_event_controller_get_property (GObject    *object,
     case PROP_PROPAGATION_PHASE:
       g_value_set_enum (value, priv->phase);
       break;
+    case PROP_PROPAGATION_LIMIT:
+      g_value_set_enum (value, priv->limit);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -128,7 +175,7 @@ gtk_event_controller_class_init (GtkEventControllerClass *klass)
 
   klass->set_widget = gtk_event_controller_set_widget;
   klass->unset_widget = gtk_event_controller_unset_widget;
-  klass->filter_event = gtk_event_controller_handle_event_default;
+  klass->filter_event = gtk_event_controller_filter_event_default;
   klass->handle_event = gtk_event_controller_handle_event_default;
 
   object_class->set_property = gtk_event_controller_set_property;
@@ -145,6 +192,7 @@ gtk_event_controller_class_init (GtkEventControllerClass *klass)
                            P_("Widget the gesture relates to"),
                            GTK_TYPE_WIDGET,
                            GTK_PARAM_READABLE);
+
   /**
    * GtkEventController:propagation-phase:
    *
@@ -158,6 +206,19 @@ gtk_event_controller_class_init (GtkEventControllerClass *klass)
                          GTK_PHASE_BUBBLE,
                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
+  /**
+   * GtkEventController:propagation-limit:
+   *
+   * The limit for which events this controller will handle.
+   */
+  properties[PROP_PROPAGATION_LIMIT] =
+      g_param_spec_enum ("propagation-limit",
+                         P_("Propagation limit"),
+                         P_("Propagation limit for events handled by this controller"),
+                         GTK_TYPE_PROPAGATION_LIMIT,
+                         GTK_LIMIT_SAME_BUD,
+                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
   g_object_class_install_properties (object_class, LAST_PROP, properties);
 }
 
@@ -168,6 +229,7 @@ gtk_event_controller_init (GtkEventController *controller)
 
   priv = gtk_event_controller_get_instance_private (controller);
   priv->phase = GTK_PHASE_BUBBLE;
+  priv->limit = GTK_LIMIT_SAME_BUD;
 }
 
 /**
@@ -299,3 +361,32 @@ gtk_event_controller_set_propagation_phase (GtkEventController  *controller,
 
   g_object_notify_by_pspec (G_OBJECT (controller), properties[PROP_PROPAGATION_PHASE]);
 }
+
+GtkPropagationLimit
+gtk_event_controller_get_propagation_limit (GtkEventController *controller)
+{
+  GtkEventControllerPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), GTK_LIMIT_SAME_BUD);
+
+  priv = gtk_event_controller_get_instance_private (controller);
+
+  return priv->limit;
+}
+void
+gtk_event_controller_set_propagation_limit (GtkEventController  *controller,
+                                            GtkPropagationLimit  limit)
+{
+  GtkEventControllerPrivate *priv;
+
+  g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
+
+  priv = gtk_event_controller_get_instance_private (controller);
+
+  if (priv->limit == limit)
+    return;
+
+  priv->limit = limit;
+
+  g_object_notify_by_pspec (G_OBJECT (controller), properties[PROP_PROPAGATION_LIMIT]);
+}
diff --git a/gtk/gtkeventcontroller.h b/gtk/gtkeventcontroller.h
index f2f2b6a2b0..963f440e6a 100644
--- a/gtk/gtkeventcontroller.h
+++ b/gtk/gtkeventcontroller.h
@@ -59,6 +59,12 @@ GDK_AVAILABLE_IN_ALL
 void                gtk_event_controller_set_propagation_phase (GtkEventController  *controller,
                                                                 GtkPropagationPhase  phase);
 
+GDK_AVAILABLE_IN_ALL
+GtkPropagationLimit gtk_event_controller_get_propagation_limit (GtkEventController *controller);
+
+GDK_AVAILABLE_IN_ALL
+void                gtk_event_controller_set_propagation_limit (GtkEventController  *controller,
+                                                                GtkPropagationLimit  limit);
 G_END_DECLS
 
 #endif /* __GTK_EVENT_CONTROLLER_H__ */
diff --git a/gtk/gtkgesture.c b/gtk/gtkgesture.c
index 2125af2bf1..f875242a45 100644
--- a/gtk/gtkgesture.c
+++ b/gtk/gtkgesture.c
@@ -617,6 +617,9 @@ gtk_gesture_filter_event (GtkEventController *controller,
    * subclasses which punch the holes in for the events
    * they can possibly handle.
    */
+  if (GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_parent_class)->filter_event (controller, event))
+    return TRUE;
+
   return EVENT_IS_TOUCHPAD_GESTURE (event);
 }
 


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