[gtk/gtk-3-24: 1/2] GdkWin32: Fix mouse events in presence of transparent windows on the desktop




commit 67be62aeaf470ef27ed78426f5c964ad176a8356
Author: Luca Bacci <luca bacci982 gmail com>
Date:   Thu Apr 30 12:51:05 2020 +0200

    GdkWin32: Fix mouse events in presence of transparent windows on the desktop
    
    In gdkdevice-win32.c we are interested in knowing which window
    receives mouse input at a specific location.
    
    Only WindowFromPoint is the right API for the task, other API's
    (such as (Real)ChildWindowFromPoint(Ex)) have shortcomings because
    they are really designed for other purposes. For example, only
    WindowFromPoint is able to look through transparent layered windows.
    
    So even if we want to find a direct child we have to use
    WindowFromPoint and then walk up the hierarchy.
    
    Fixes: #370, #417
    See: !2767

 gdk/win32/gdkdevice-win32.c | 94 +++++++++++++++++++--------------------------
 1 file changed, 40 insertions(+), 54 deletions(-)
---
diff --git a/gdk/win32/gdkdevice-win32.c b/gdk/win32/gdkdevice-win32.c
index 190372de2d..3ca8e03a51 100644
--- a/gdk/win32/gdkdevice-win32.c
+++ b/gdk/win32/gdkdevice-win32.c
@@ -150,7 +150,18 @@ gdk_device_win32_query_state (GdkDevice        *device,
 
   if (child_window)
     {
-      hwndc = ChildWindowFromPoint (hwnd, point);
+      if (window == gdk_screen_get_root_window (screen))
+        {
+          /* Always use WindowFromPoint when searching from the root window.
+          *  Only WindowFromPoint is able to look through transparent
+          *  layered windows.
+          */
+          hwndc = GetAncestor (WindowFromPoint (point), GA_ROOT);
+        }
+      else
+        {
+          hwndc = ChildWindowFromPoint (hwnd, point);
+        }
 
       if (hwndc && hwndc != hwnd)
         *child_window = gdk_win32_handle_table_lookup (hwndc);
@@ -201,71 +212,46 @@ _gdk_device_win32_window_at_position (GdkDevice       *device,
   GdkWindow *window = NULL;
   GdkWindowImplWin32 *impl = NULL;
   POINT screen_pt, client_pt;
-  HWND hwnd, hwndc;
+  HWND hwnd;
   RECT rect;
 
-  GetCursorPos (&screen_pt);
+  if (!GetCursorPos (&screen_pt))
+    return NULL;
+
+  hwnd = WindowFromPoint (screen_pt);
 
   if (get_toplevel)
     {
-      /* Only consider visible children of the desktop to avoid the various
-       * non-visible windows you often find on a running Windows box. These
-       * might overlap our windows and cause our walk to fail. As we assume
-       * WindowFromPoint() can find our windows, we follow similar logic
-       * here, and ignore invisible and disabled windows.
-       */
-      hwnd = GetDesktopWindow ();
-      do {
-        window = gdk_win32_handle_table_lookup (hwnd);
-
-        if (window != NULL &&
-            GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT &&
-            GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
-          break;
-
-        screen_to_client (hwnd, screen_pt, &client_pt);
-        hwndc = ChildWindowFromPointEx (hwnd, client_pt, CWP_SKIPDISABLED  |
-                                                         CWP_SKIPINVISIBLE);
-
-       /* Verify that we're really inside the client area of the window */
-       if (hwndc != hwnd)
-         {
-           GetClientRect (hwndc, &rect);
-           screen_to_client (hwndc, screen_pt, &client_pt);
-           if (!PtInRect (&rect, client_pt))
-             hwndc = hwnd;
-         }
-
-      } while (hwndc != hwnd && (hwnd = hwndc, 1));
-
+      /* Use WindowFromPoint instead of ChildWindowFromPoint(Ex).
+      *  Only WindowFromPoint is able to look through transparent
+      *  layered windows.
+      */
+      hwnd = GetAncestor (hwnd, GA_ROOT);
     }
-  else
-    {
-      hwnd = WindowFromPoint (screen_pt);
 
-      /* Verify that we're really inside the client area of the window */
-      GetClientRect (hwnd, &rect);
-      screen_to_client (hwnd, screen_pt, &client_pt);
-      if (!PtInRect (&rect, client_pt))
-       hwnd = NULL;
+  /* Verify that we're really inside the client area of the window */
+  GetClientRect (hwnd, &rect);
+  screen_to_client (hwnd, screen_pt, &client_pt);
+  if (!PtInRect (&rect, client_pt))
+    hwnd = NULL;
 
-      /* If we didn't hit any window at that point, return the desktop */
-      if (hwnd == NULL)
-        {
-          window = gdk_get_default_root_window ();
-          impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
-
-          if (win_x)
-            *win_x = (screen_pt.x + _gdk_offset_x) / impl->window_scale;
-          if (win_y)
-            *win_y = (screen_pt.y + _gdk_offset_y) / impl->window_scale;
+  if (!get_toplevel && hwnd == NULL)
+    {
+      /* If we didn't hit any window, return the root window */
+      /* note that the root window ain't a toplevel window */
+      window = gdk_get_default_root_window ();
+      impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
-          return window;
-        }
+      if (win_x)
+        *win_x = (screen_pt.x + _gdk_offset_x) / impl->window_scale;
+      if (win_y)
+        *win_y = (screen_pt.y + _gdk_offset_y) / impl->window_scale;
 
-      window = gdk_win32_handle_table_lookup (hwnd);
+      return window;
     }
 
+  window = gdk_win32_handle_table_lookup (hwnd);
+
   if (window && (win_x || win_y))
     {
       impl = GDK_WINDOW_IMPL_WIN32 (window->impl);


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