[gtk+] gdk: Add gdk_window_set_pass_through



commit 4c3eece6638aa36fbcd8379109dcb4e27323a306
Author: Alexander Larsson <alexl redhat com>
Date:   Mon Jun 8 15:36:43 2015 +0200

    gdk: Add gdk_window_set_pass_through
    
    An pass_through window is something you can draw in but does not
    affect event handling. Normally if a window has with no event mask set
    for a particular event then input events in it go to its parent window
    (X11 semantics), whereas if pass_through is enabled the window below
    the window will get the event. The later mode is useful when the
    window is partially transparent. Note that an pass-through windows can
    have child windows that are not pass-through so they can still get events
    on some parts.
    
    Semantically, this behaves the same as an regular window with
    gdk_window_set_child_input_shapes() called on it (and re-called any
    time a child is changed), but its far more efficient and easy to use.
    
    This allows us to fix the testoverlay input stacking test.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=750568
    
    https://bugs.freedesktop.org/show_bug.cgi?id=90917

 gdk/gdkinternals.h |    1 +
 gdk/gdkwindow.c    |  125 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 gdk/gdkwindow.h    |    6 +++
 3 files changed, 128 insertions(+), 4 deletions(-)
---
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index d1d1e4d..e5ec4b2 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -314,6 +314,7 @@ struct _GdkWindow
   guint8 fullscreen_mode;
 
   guint input_only : 1;
+  guint pass_through : 1;
   guint modal_hint : 1;
   guint composited : 1;
   guint has_alpha_background : 1;
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 612d796..faa848c 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -6785,6 +6785,64 @@ gdk_window_set_child_input_shapes (GdkWindow *window)
 }
 
 /**
+ * gdk_window_set_pass_through:
+ * @window: a #GdkWindow
+ * @pass_through: a boolean
+ *
+ * Sets whether input to the window is passed through to the window
+ * below.
+ *
+ * The default value of this is %FALSE, which means that pointer
+ * events that happen inside the window are send first to the window,
+ * but if the event is not selected by the event mask then the event
+ * is sent to the parent window, and so on up the hierarchy.
+ *
+ * If @pass_through is %TRUE then such pointer events happen as if the
+ * window wasn't there at all, and thus will be sent first to any
+ * windows below @window. This is useful if the window is used in a
+ * transparent fashion. In the terminology of the web this would be called
+ * "pointer-events: none".
+ *
+ * Note that a window with @pass_through %TRUE can still have a subwindow
+ * without pass through, so you can get events on a subset of a window. And in
+ * that cases you would get the in-between related events such as the pointer
+ * enter/leave events on its way to the destination window.
+ *
+ * Since: 3.18
+ **/
+void
+gdk_window_set_pass_through (GdkWindow *window,
+                            gboolean pass_through)
+{
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  window->pass_through = !!pass_through;
+
+  /* Pointer may have e.g. moved outside window due to the input region change */
+  _gdk_synthesize_crossing_events_for_geometry_change (window);
+}
+
+/**
+ * gdk_window_get_pass_through:
+ * @window: a #GdkWindow
+ * @pass_through: a boolean
+ *
+ * Returns whether input to the window is passed through to the window
+ * below.
+ *
+ * See gdk_window_set_pass_through() for details
+ *
+ * Since: 3.18
+ **/
+gboolean
+gdk_window_get_pass_through (GdkWindow *window)
+{
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  return window->pass_through;
+}
+
+/**
  * gdk_window_merge_child_input_shapes:
  * @window: a #GdkWindow
  *
@@ -7133,6 +7191,63 @@ point_in_window (GdkWindow *window,
                          x, y));
 }
 
+/* Same as point_in_window, except it also takes pass_through and its
+   interaction with child windows into account */
+static gboolean
+point_in_input_window (GdkWindow *window,
+                      gdouble    x,
+                      gdouble    y,
+                      GdkWindow **input_window,
+                      gdouble   *input_window_x,
+                      gdouble   *input_window_y)
+{
+  GdkWindow *sub;
+  double child_x, child_y;
+  GList *l;
+
+  if (!point_in_window (window, x, y))
+    return FALSE;
+
+  if (!window->pass_through)
+    {
+      if (input_window)
+       {
+         *input_window = window;
+         *input_window_x = x;
+         *input_window_y = y;
+       }
+      return TRUE;
+    }
+
+  /* For pass-through, must be over a child input window */
+
+  /* Children is ordered in reverse stack order, i.e. first is topmost */
+  for (l = window->children; l != NULL; l = l->next)
+    {
+      sub = l->data;
+
+      if (!GDK_WINDOW_IS_MAPPED (sub))
+       continue;
+
+      gdk_window_coords_from_parent ((GdkWindow *)sub,
+                                    x, y,
+                                    &child_x, &child_y);
+      if (point_in_input_window (sub, child_x, child_y,
+                                input_window, input_window_x, input_window_y))
+       {
+         if (input_window)
+           gdk_window_coords_to_parent (sub,
+                                        *input_window_x,
+                                        *input_window_y,
+                                        input_window_x,
+                                        input_window_y);
+         return TRUE;
+       }
+    }
+
+  return FALSE;
+}
+
 static GdkWindow *
 convert_native_coords_to_toplevel (GdkWindow *window,
                                   gdouble    child_x,
@@ -7226,7 +7341,8 @@ _gdk_window_find_child_at (GdkWindow *window,
          gdk_window_coords_from_parent ((GdkWindow *)sub,
                                          x, y,
                                          &child_x, &child_y);
-         if (point_in_window (sub, child_x, child_y))
+         if (point_in_input_window (sub, child_x, child_y,
+                                    NULL, NULL, NULL))
            return (GdkWindow *)sub;
        }
 
@@ -7249,7 +7365,7 @@ _gdk_window_find_descendant_at (GdkWindow *window,
                                gdouble   *found_x,
                                gdouble   *found_y)
 {
-  GdkWindow *sub;
+  GdkWindow *sub, *input_window;
   gdouble child_x, child_y;
   GList *l;
   gboolean found;
@@ -7270,11 +7386,12 @@ _gdk_window_find_descendant_at (GdkWindow *window,
              gdk_window_coords_from_parent ((GdkWindow *)sub,
                                              x, y,
                                              &child_x, &child_y);
-             if (point_in_window (sub, child_x, child_y))
+             if (point_in_input_window (sub, child_x, child_y,
+                                        &input_window, &child_x, &child_y))
                {
                  x = child_x;
                  y = child_y;
-                 window = sub;
+                 window = input_window;
                  found = TRUE;
                  break;
                }
diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
index ad5e88c..b42f9df 100644
--- a/gdk/gdkwindow.h
+++ b/gdk/gdkwindow.h
@@ -654,6 +654,12 @@ GDK_AVAILABLE_IN_ALL
 void gdk_window_merge_child_input_shapes   (GdkWindow       *window);
 
 
+GDK_AVAILABLE_IN_3_18
+void gdk_window_set_pass_through (GdkWindow *window,
+                                 gboolean pass_through);
+GDK_AVAILABLE_IN_3_18
+gboolean gdk_window_get_pass_through (GdkWindow *window);
+
 /*
  * Check if a window has been shown, and whether all its
  * parents up to a toplevel have been shown, respectively.


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