[gtk+] widget: Implement gtk_widget_pick()



commit cf2d549e922b51e7c4c790c04531be0cfb6ddd63
Author: Benjamin Otte <otte redhat com>
Date:   Sun Nov 5 00:49:18 2017 +0100

    widget: Implement gtk_widget_pick()
    
    ... and use it.

 docs/reference/gtk/gtk4-sections.txt |    1 +
 gtk/gtkmain.c                        |   31 ++++----------------
 gtk/gtkpointerfocus.c                |    5 ++-
 gtk/gtkwidget.c                      |   53 +++++++++++++++++++++++++++------
 gtk/gtkwidget.h                      |    8 +++--
 gtk/gtkwindow.c                      |   36 ++++++----------------
 gtk/inspector/inspect-button.c       |   14 +-------
 7 files changed, 70 insertions(+), 78 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 0c5003c..27c8de3 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -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
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 198bd91..5837f7c 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -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;
-}
diff --git a/gtk/gtkpointerfocus.c b/gtk/gtkpointerfocus.c
index cb484b8..5229e39 100644
--- a/gtk/gtkpointerfocus.c
+++ b/gtk/gtkpointerfocus.c
@@ -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);
 }
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 70152b9..69dfe6d 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -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)
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 0f4a785..3568d87 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -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
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index ed60d5c..6a80635 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -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
diff --git a/gtk/inspector/inspect-button.c b/gtk/inspector/inspect-button.c
index 8c5ecdc..517e716 100644
--- a/gtk/inspector/inspect-button.c
+++ b/gtk/inspector/inspect-button.c
@@ -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,


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