widget: Implement gtk_widget_pick()
authorBenjamin Otte <otte@redhat.com>
Sat, 4 Nov 2017 23:49:18 +0000 (00:49 +0100)
committerBenjamin Otte <otte@redhat.com>
Sun, 5 Nov 2017 04:13:17 +0000 (05:13 +0100)
... and use it.

docs/reference/gtk/gtk4-sections.txt
gtk/gtkmain.c
gtk/gtkpointerfocus.c
gtk/gtkwidget.c
gtk/gtkwidget.h
gtk/gtkwindow.c
gtk/inspector/inspect-button.c

index 0c5003ccf23cf7bdd597452064eca8e0ad65f8ac..27c8de3280b61f60b1f90a825534227b2a5d0150 100644 (file)
@@ -4592,6 +4592,7 @@ gtk_widget_get_width
 gtk_widget_get_height
 gtk_widget_get_clip
 gtk_widget_contains
+gtk_widget_pick
 gtk_widget_get_can_default
 gtk_widget_set_can_default
 gtk_widget_get_can_focus
index 198bd91373f269885868994833f8a9307a7c9eef..5837f7ceb53ad3d87fd5d2c347f623113f1dbacf 100644 (file)
@@ -1509,7 +1509,9 @@ handle_pointing_event (GdkEvent *event)
     case GDK_TOUCH_BEGIN:
     case GDK_TOUCH_UPDATE:
     case GDK_MOTION_NOTIFY:
-      target = _gtk_toplevel_pick (toplevel, x, y, NULL, NULL);
+      target = gtk_widget_pick (GTK_WIDGET (toplevel), x, y);
+      if (target == NULL)
+        target = GTK_WIDGET (toplevel);
       old_target = update_pointer_focus_state (toplevel, event, target);
 
       if (event->type == GDK_MOTION_NOTIFY || event->type == GDK_ENTER_NOTIFY)
@@ -1544,7 +1546,9 @@ handle_pointing_event (GdkEvent *event)
       if (event->type == GDK_BUTTON_RELEASE)
         {
           old_target = target;
-          target = _gtk_toplevel_pick (toplevel, x, y, NULL, NULL);
+          target = gtk_widget_pick (GTK_WIDGET (toplevel), x, y);
+          if (target == NULL)
+            target = GTK_WIDGET (toplevel);
           gtk_synthesize_crossing_events (toplevel, old_target, target, event,
                                           GDK_CROSSING_UNGRAB);
           gtk_window_maybe_update_cursor (toplevel, NULL, device);
@@ -2617,26 +2621,3 @@ gtk_propagate_event (GtkWidget *widget,
 
   gtk_propagate_event_internal (widget, event, topmost);
 }
-
-GtkWidget *
-_gtk_toplevel_pick (GtkWindow *toplevel,
-                    gdouble    x,
-                    gdouble    y,
-                    gdouble   *x_out,
-                    gdouble   *y_out)
-{
-  GtkWidget *target = NULL, *widget = GTK_WIDGET (toplevel);
-
-  while (widget)
-    {
-      target = widget;
-      widget = GTK_WIDGET_GET_CLASS (target)->pick (widget, x, y, &x, &y);
-    }
-
-  if (x_out)
-    *x_out = x;
-  if (y_out)
-    *y_out = y;
-
-  return target;
-}
index cb484b8d343d3ff77f469526fdbe549431086ebb..5229e39e12f6c7bb6c226579cade41f8d8093658 100644 (file)
@@ -133,7 +133,8 @@ gtk_pointer_focus_repick_target (GtkPointerFocus *focus)
 {
   GtkWidget *target;
 
-  target = _gtk_toplevel_pick (focus->toplevel, focus->x, focus->y,
-                               NULL, NULL);
+  target = gtk_widget_pick (GTK_WIDGET (focus->toplevel), focus->x, focus->y);
+  if (target == NULL)
+    target = GTK_WIDGET (focus->toplevel);
   gtk_pointer_focus_set_target (focus, target);
 }
index 70152b9d4e30bcf22f3b95903c6e5d3aa05f0c28..69dfe6d8ae74d01b4255e4ca907d3c66ccbd1b07 100644 (file)
@@ -951,29 +951,28 @@ gtk_widget_real_contains (GtkWidget *widget,
 static GtkWidget *
 gtk_widget_real_pick (GtkWidget *widget,
                       gdouble    x,
-                      gdouble    y,
-                      gdouble   *x_out,
-                      gdouble   *y_out)
+                      gdouble    y)
 {
   GtkWidget *child;
 
+  if (!gtk_widget_contains (widget, x, y))
+    return NULL;
+
   for (child = _gtk_widget_get_last_child (widget);
        child;
        child = _gtk_widget_get_prev_sibling (child))
     {
+      GtkWidget *picked;
       int dx, dy;
 
       gtk_widget_get_origin_relative_to_parent (child, &dx, &dy);
 
-      if (gtk_widget_contains (child, x - dx, y - dy))
-        {
-          *x_out = x - dx;
-          *y_out = y - dy;
-          return child;
-        }
+      picked = gtk_widget_pick (child, x - dx, y - dy);
+      if (picked)
+        return picked;
     }
 
-  return NULL;
+  return widget;
 }
 
 static void
@@ -13156,6 +13155,40 @@ gtk_widget_contains (GtkWidget  *widget,
   return GTK_WIDGET_GET_CLASS (widget)->contains (widget, x, y);
 }
 
+/**
+ * gtk_widget_pick:
+ * @widget: the widget to query
+ * @x: X coordinate to test, relative to @widget's origin
+ * @y: Y coordinate to test, relative to @widget's origin
+ *
+ * Finds the descendant of widget (including widget itself) closest
+ * to the screen at the point (@x, @y). The point must be given in
+ * widget coordinates, so (0, 0) is assumed to be the top left of
+ * @widget's content area.
+ *
+ * Usually widgets will return %NULL if the given coordinate is not
+ * contained in @widget checked via gtk_widget_contains(). Otherwise
+ * they will recursively try to find a child that does not return %NULL.
+ * Widgets are however free to customize their picking algorithm.
+ *
+ * This function is used on the toplevel to determine the widget below
+ * the mouse cursor for purposes of hover hilighting and delivering events.
+ *
+ * Returns: (nullable) (transfer none): The widget descendant at the given
+ *     coordinate or %NULL if none.
+ *
+ * Since: 3.94
+ **/
+GtkWidget *
+gtk_widget_pick (GtkWidget *widget,
+                 gdouble    x,
+                 gdouble    y)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+  return GTK_WIDGET_GET_CLASS (widget)->pick (widget, x, y);
+}
+
 void
 gtk_widget_get_outer_allocation (GtkWidget    *widget,
                                  GdkRectangle *allocation)
index 0f4a785c17b52fea5af0b855f20f628263894241..3568d8736211bd500616a7ca9237c8aa601c330f 100644 (file)
@@ -472,9 +472,7 @@ struct _GtkWidgetClass
                                                 gdouble    y);
   GtkWidget *  (* pick)                        (GtkWidget *widget,
                                                 gdouble    x,
-                                                gdouble    y,
-                                                gdouble   *x_out,
-                                                gdouble   *y_out);
+                                                gdouble    y);
 
   /*< private >*/
 
@@ -894,6 +892,10 @@ GDK_AVAILABLE_IN_3_94
 gboolean     gtk_widget_contains              (GtkWidget  *widget,
                                                gdouble     x,
                                                gdouble     y);
+GDK_AVAILABLE_IN_3_94
+GtkWidget *  gtk_widget_pick                  (GtkWidget  *widget,
+                                               gdouble     x,
+                                               gdouble     y);
 /* Hide widget and return TRUE.
  */
 GDK_AVAILABLE_IN_ALL
index ed60d5cf05f6c71254eb4dbd36133f4b17bda4f5..6a806357b0ef75a5538954aa13a73f95c134b553 100644 (file)
@@ -742,9 +742,7 @@ static void popover_get_rect (GtkWindowPopover      *popover,
 static GtkWidget *
 gtk_window_pick (GtkWidget *widget,
                  gdouble    x,
-                 gdouble    y,
-                 gdouble   *x_out,
-                 gdouble   *y_out)
+                 gdouble    y)
 {
   GtkWindow *window = GTK_WINDOW (widget);
   GList *popovers;
@@ -752,33 +750,19 @@ gtk_window_pick (GtkWidget *widget,
   for (popovers = window->priv->popovers.tail; popovers; popovers = popovers->prev)
     {
       GtkWindowPopover *popover = popovers->data;
-      cairo_rectangle_int_t rect;
-
-      if (!gtk_widget_is_sensitive (popover->widget) ||
-          !gtk_widget_is_drawable (popover->widget))
-        continue;
+      int dest_x, dest_y;
+      GtkWidget *picked;
 
-      gtk_widget_get_outer_allocation (popover->widget, &rect);
+      gtk_widget_translate_coordinates (widget, popover->widget,
+                                        x, y,
+                                        &dest_x, &dest_y);
 
-      if (gdk_rectangle_contains_point (&rect, x, y))
-        {
-          if (x_out && y_out)
-            {
-              int dest_x, dest_y;
-              gtk_widget_translate_coordinates (widget, popover->widget,
-                                                x, y,
-                                                &dest_x, &dest_y);
-
-              *x_out = dest_x;
-              *y_out = dest_y;
-            }
-
-          return popover->widget;
-        }
+      picked = gtk_widget_pick (popover->widget, dest_x, dest_y);
+      if (picked)
+        return picked;
     }
 
-  return GTK_WIDGET_CLASS (gtk_window_parent_class)->pick (widget, x, y,
-                                                           x_out, y_out);
+  return GTK_WIDGET_CLASS (gtk_window_parent_class)->pick (widget, x, y);
 }
 
 static void
index 8c5ecdc0d3684934097f6e615d68ac6d9db00f68..517e716c0f587a2520063d6dc20dc53e55d53ecd 100644 (file)
@@ -73,20 +73,10 @@ find_widget_at_pointer (GdkDevice *device)
       gdk_window_get_device_position_double (gtk_widget_get_window (widget),
                                              device, &x, &y, NULL);
 
-      while (widget)
-        {
-          GtkWidget *w;
-
-          w = GTK_WIDGET_GET_CLASS (widget)->pick (widget, x, y, &x, &y);
-
-          if (!w)
-            return widget;
-
-          widget = w;
-        }
+      widget = gtk_widget_pick (widget, x, y);
     }
 
-  return NULL;
+  return widget;
 }
 
 static gboolean draw_flash (GtkWidget          *widget,