[gtk+/wip/carlosg/event-delivery: 10/104] GtkWidget: Add ::pick vmethod



commit 9c97bf0c02721bf8d2850e622f374d73dbb48a0f
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri May 12 12:33:58 2017 +0200

    GtkWidget: Add ::pick vmethod
    
    The default implementation iterates through all children, so should suffice
    for most widgets.

 gtk/gtkwidget.c |   74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkwidget.h |    6 ++++
 2 files changed, 80 insertions(+), 0 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 2ed1038..8562829 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -948,6 +948,78 @@ gtk_widget_real_snapshot (GtkWidget   *widget,
 }
 
 static void
+transform_to_child_coords (GtkWidget *widget,
+                           GtkWidget *child,
+                           gdouble    x,
+                           gdouble    y,
+                           gdouble   *x_out,
+                           gdouble   *y_out)
+{
+  GtkAllocation alloc, child_alloc;
+  GdkWindow *window;
+  gdouble dx = 0, dy = 0;
+
+  gtk_widget_get_allocation (widget, &alloc);
+  gtk_widget_get_allocation (child, &child_alloc);
+
+  child_alloc.x -= alloc.x;
+  child_alloc.y -= alloc.y;
+
+  window = _gtk_widget_get_window (child);
+
+  while (window != _gtk_widget_get_window (widget))
+    {
+      gdk_window_coords_to_parent (window, dx, dy, &dx, &dy);
+      window = gdk_window_get_parent (window);
+    }
+
+  *x_out = x - child_alloc.x - dx;
+  *y_out = y - child_alloc.y - dy;
+}
+
+static GtkWidget *
+gtk_widget_real_pick (GtkWidget *widget,
+                      gdouble    x,
+                      gdouble    y,
+                      gdouble   *x_out,
+                      gdouble   *y_out)
+{
+  GtkAllocation allocation, parent_allocation;
+  GtkWidget *child;
+
+  gtk_widget_get_allocation (widget, &parent_allocation);
+
+  for (child = _gtk_widget_get_last_child (widget);
+       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_child_coords (widget, child, tx, ty, &tx, &ty);
+      _gtk_widget_get_allocation (child, &allocation);
+      allocation.x = 0;
+      allocation.y = 0;
+
+      if (gdk_rectangle_contains_point (&allocation, tx, ty))
+        {
+          if (x_out && y_out)
+            {
+              *x_out = tx;
+              *y_out = ty;
+            }
+
+          return child;
+        }
+    }
+
+  return NULL;
+}
+
+static void
 gtk_widget_class_init (GtkWidgetClass *klass)
 {
   static GObjectNotifyContext cpn_context = { 0, NULL, NULL };
@@ -1061,6 +1133,8 @@ gtk_widget_class_init (GtkWidgetClass *klass)
   klass->queue_draw_region = gtk_widget_real_queue_draw_region;
   klass->queue_draw_child = gtk_widget_real_queue_draw_child;
 
+  klass->pick = gtk_widget_real_pick;
+
   widget_props[PROP_NAME] =
       g_param_spec_string ("name",
                            P_("Widget name"),
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 60f5a7f..ded422a 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -480,6 +480,12 @@ struct _GtkWidgetClass
   void         (* snapshot)                    (GtkWidget            *widget,
                                                 GtkSnapshot          *snapshot);
 
+  GtkWidget *  (* pick)                        (GtkWidget *widget,
+                                                gdouble    x,
+                                                gdouble    y,
+                                                gdouble   *x_out,
+                                                gdouble   *y_out);
+
   /*< private >*/
 
   GtkWidgetClassPrivate *priv;


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