[gtk/crossing-details: 69/70] motion controller: Add focus properties



commit ecd6446d0802a87227fe6362ad234c9495d45b2d
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Mar 16 23:29:48 2019 -0400

    motion controller: Add focus properties
    
    Add boolean properties, is-pointer-focus and
    contains-pointer-focus, that track whether the pointer
    is in the widget itself or in one of its descendants.

 gtk/gtkeventcontrollermotion.c | 123 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 123 insertions(+)
---
diff --git a/gtk/gtkeventcontrollermotion.c b/gtk/gtkeventcontrollermotion.c
index 5f40e94ade..377287742c 100644
--- a/gtk/gtkeventcontrollermotion.c
+++ b/gtk/gtkeventcontrollermotion.c
@@ -38,6 +38,9 @@
 struct _GtkEventControllerMotion
 {
   GtkEventController parent_instance;
+
+  guint is_pointer_focus       : 1;
+  guint contains_pointer_focus : 1;
 };
 
 struct _GtkEventControllerMotionClass
@@ -52,14 +55,67 @@ enum {
   N_SIGNALS
 };
 
+enum {
+  PROP_IS_POINTER_FOCUS = 1,
+  PROP_CONTAINS_POINTER_FOCUS,
+  NUM_PROPERTIES
+};
+
+static GParamSpec *props[NUM_PROPERTIES] = { NULL, };
+
 static guint signals[N_SIGNALS] = { 0 };
 
 G_DEFINE_TYPE (GtkEventControllerMotion, gtk_event_controller_motion, GTK_TYPE_EVENT_CONTROLLER)
 
+static void
+update_pointer_focus (GtkEventControllerMotion *motion,
+                      gboolean                  enter,
+                      GdkNotifyType             detail)
+{
+  gboolean is_pointer;
+  gboolean contains_pointer;
+
+  switch (detail)
+    {
+    case GDK_NOTIFY_VIRTUAL:
+    case GDK_NOTIFY_NONLINEAR_VIRTUAL:
+      is_pointer = FALSE;
+      contains_pointer = enter;
+      break;
+    case GDK_NOTIFY_ANCESTOR:
+    case GDK_NOTIFY_NONLINEAR:
+      is_pointer = enter;
+      contains_pointer = FALSE;
+      break;
+    case GDK_NOTIFY_INFERIOR:
+      is_pointer = enter;
+      contains_pointer = !enter;
+      break;
+    case GDK_NOTIFY_UNKNOWN:
+    default:
+      g_warning ("Unknown crossing detail");
+      return;
+    }
+
+  g_object_freeze_notify (G_OBJECT (motion));
+  if (motion->is_pointer_focus != is_pointer)
+    {
+      motion->is_pointer_focus = is_pointer;
+      g_object_notify (G_OBJECT (motion), "is-pointer-focus");
+    }
+  if (motion->contains_pointer_focus != contains_pointer)
+    {
+      motion->contains_pointer_focus = contains_pointer;
+      g_object_notify (G_OBJECT (motion), "contains-pointer-focus");
+    }
+  g_object_thaw_notify (G_OBJECT (motion));
+}
+
 static gboolean
 gtk_event_controller_motion_handle_event (GtkEventController *controller,
                                           const GdkEvent     *event)
 {
+  GtkEventControllerMotion *motion = GTK_EVENT_CONTROLLER_MOTION (controller);
   GtkEventControllerClass *parent_class;
   GdkEventType type;
 
@@ -73,6 +129,9 @@ gtk_event_controller_motion_handle_event (GtkEventController *controller,
       gdk_event_get_coords (event, &x, &y);
       gdk_event_get_crossing_mode (event, &mode);
       gdk_event_get_crossing_detail (event, &detail);
+
+      update_pointer_focus (motion, TRUE, detail);
+
       g_signal_emit (controller, signals[ENTER], 0, x, y, mode, detail);
     }
   else if (type == GDK_LEAVE_NOTIFY)
@@ -82,6 +141,9 @@ gtk_event_controller_motion_handle_event (GtkEventController *controller,
 
       gdk_event_get_crossing_mode (event, &mode);
       gdk_event_get_crossing_detail (event, &detail);
+
+      update_pointer_focus (motion, FALSE, detail);
+
       g_signal_emit (controller, signals[LEAVE], 0, mode, detail);
     }
   else if (type == GDK_MOTION_NOTIFY)
@@ -97,13 +159,74 @@ gtk_event_controller_motion_handle_event (GtkEventController *controller,
   return parent_class->handle_event (controller, event);
 }
 
+static void
+gtk_event_controller_motion_get_property (GObject    *object,
+                                          guint       prop_id,
+                                          GValue     *value,
+                                          GParamSpec *pspec)
+{
+  GtkEventControllerMotion *controller = GTK_EVENT_CONTROLLER_MOTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_IS_POINTER_FOCUS:
+      g_value_set_boolean (value, controller->is_pointer_focus);
+      break;
+
+    case PROP_CONTAINS_POINTER_FOCUS:
+      g_value_set_boolean (value, controller->contains_pointer_focus);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
 static void
 gtk_event_controller_motion_class_init (GtkEventControllerMotionClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
 
+  object_class->get_property = gtk_event_controller_motion_get_property;
+
   controller_class->handle_event = gtk_event_controller_motion_handle_event;
 
+  /**
+   * GtkEventControllerMotion:is-pointer-focus:
+   *
+   * Whether the pointer is in the controllers widget itself,
+   * as opposed to in a descendent widget. See
+   * #GtkEventControllerMotion:contains-pointer-focus.
+   *
+   * When handling crossing events, this property is updated
+   * before #GtkEventControllerMotion::enter or
+   * #GtkEventControllerMotion::leave are emitted.
+   */
+  props[PROP_IS_POINTER_FOCUS] =
+      g_param_spec_boolean ("is-pointer-focus",
+                            P_("Is Pointer Focus"),
+                            P_("Whether the pointer is in the controllers widget"),
+                            FALSE,
+                            G_PARAM_READABLE);
+
+  /**
+   * GtkEventControllerMotion:contains-pointer-focus:
+   *
+   * Whether the pointer is in a descendant of the controllers widget.
+   * See #GtkEventControllerMotion:is-pointer-focus.
+   *
+   * When handling crossing events, this property is updated
+   * before #GtkEventControllerMotion::enter or
+   * #GtkEventControllerMotion::leave are emitted.
+   */
+  props[PROP_CONTAINS_POINTER_FOCUS] =
+      g_param_spec_boolean ("contains-pointer-focus",
+                            P_("Contains Pointer Focus"),
+                            P_("Whether the pointer is in a descendant of the controllers widget"),
+                            FALSE,
+                            G_PARAM_READABLE);
+
   /**
    * GtkEventControllerMotion::enter:
    * @controller: The object that received the signal


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