[gtk+/wip/carlosg/event-delivery: 198/261] gtk: Add private _gtk_toplevel_pick() method



commit 44efaaf0a3e0fee9e316e5a44f052d20d05b8daa
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Mar 31 16:49:22 2017 +0200

    gtk: Add private _gtk_toplevel_pick() method
    
    This function returns both the widget at the given toplevel coordinates,
    and the translated x/y in widget relative coordinates.

 gtk/gtkmain.c    |   88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkprivate.h |    5 +++
 2 files changed, 93 insertions(+), 0 deletions(-)
---
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index b145f00..0e6a8a5 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -177,6 +177,12 @@ static const GDebugKey gtk_debug_keys[] = {
 };
 #endif /* G_ENABLE_DEBUG */
 
+#define POINT_IN_RECT(point_x, point_y, rect)    \
+  ((point_x) >= (rect)->x &&                     \
+   (point_x) < (rect)->x + (rect)->width &&      \
+   (point_y) >= (rect)->y &&                     \
+   (point_y) < (rect)->y + (rect)->height)
+
 /**
  * gtk_get_major_version:
  *
@@ -2304,3 +2310,85 @@ _gtk_propagate_captured_event (GtkWidget *widget,
 {
   return propagate_event (widget, event, TRUE, topmost);
 }
+
+static void
+transform_to_widget_coords (GtkWidget *widget,
+                            gdouble    x,
+                            gdouble    y,
+                            gdouble   *x_out,
+                            gdouble   *y_out)
+{
+  GdkWindow *window;
+  gdouble origin_x = 0, origin_y = 0;
+
+  /* XXX: This sucks on purpose, on one hand, when all child windows
+   * are removed this will boil down to comparisons between toplevel-
+   * relative coordinates.
+   *
+   * On the other hand, widgets might eventually get arbitrary
+   * transforms (even 3D) so this function should cater for correct
+   * picking and coordinate transformation for these circumstances.
+   */
+  window = _gtk_widget_get_window (widget);
+
+  while (window && gdk_window_get_window_type (window) == GDK_WINDOW_CHILD)
+    {
+      gdk_window_coords_to_parent (window, origin_x, origin_y,
+                                   &origin_x, &origin_y);
+      window = gdk_window_get_parent (window);
+    }
+
+  *x_out = x - origin_x;
+  *y_out = y - origin_y;
+}
+
+GtkWidget *
+_gtk_toplevel_pick (GtkWindow *toplevel,
+                    gdouble    x,
+                    gdouble    y,
+                    gdouble   *x_out,
+                    gdouble   *y_out)
+{
+  GQueue candidates = G_QUEUE_INIT;
+  GtkWidget *target;
+
+  g_queue_push_tail (&candidates, GTK_WIDGET (toplevel));
+  target = GTK_WIDGET (toplevel);
+
+  while (!g_queue_is_empty (&candidates))
+    {
+      GtkAllocation allocation, clip;
+      GtkWidget *child;
+
+      child = g_queue_pop_head (&candidates);
+
+      for (child = _gtk_widget_get_last_child (child);
+           child;
+           child = _gtk_widget_get_prev_sibling (child))
+        {
+          gdouble tx = x, ty = y;
+
+          if (!gtk_widget_is_sensitive (child) ||
+              !gtk_widget_is_drawable (child))
+            continue;
+
+          transform_to_widget_coords (child, tx, ty, &tx, &ty);
+          gtk_widget_get_clip (child, &clip);
+          _gtk_widget_get_allocation (child, &allocation);
+
+          if (POINT_IN_RECT (tx, ty, &clip))
+            g_queue_push_tail (&candidates, child);
+
+          if (POINT_IN_RECT (tx, ty, &allocation))
+            {
+              target = child;
+              break;
+            }
+        }
+    }
+
+  if (x_out && y_out)
+    transform_to_widget_coords (target, x, y, x_out, y_out);
+
+  return target;
+}
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index de26e9f..21de486 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -91,6 +91,11 @@ gboolean        _gtk_propagate_captured_event  (GtkWidget       *widget,
                                                 GdkEvent        *event,
                                                 GtkWidget       *topmost);
 
+GtkWidget *     _gtk_toplevel_pick (GtkWindow *toplevel,
+                                    gdouble    x,
+                                    gdouble    y,
+                                    gdouble   *x_out,
+                                    gdouble   *y_out);
 
 gdouble _gtk_get_slowdown (void);
 void    _gtk_set_slowdown (gdouble slowdown_factor);


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