[gtk+/gtk-2-24] Win32: Fix _gdk_windowing_window_at_pointer to correctly return a toplevel



commit 7ee5e4f2c6396fb930f40cc6e5d982d1de99833a
Author: Peter Clifton <pcjc2 cam ac uk>
Date:   Sat Sep 10 16:30:56 2011 +0100

    Win32: Fix _gdk_windowing_window_at_pointer to correctly return a toplevel
    
    Commit 5ebb32d1ffa23241d562fb4d5be02bc6f156b515 didn't add the correct
    code to find the toplevel window. The WindowFromPoint() function does
    not return the toplevel window in the hierarchy, it returns the deepest
    non-disabled, non-invisible child. As we don't use invisible or disabled
    windows, we don't actually need to use the ChildWindowFromPoint walk for
    the non get_toplevel case, so we can remove that code path.
    
    To find a toplevel, we need to start from the desktop and work up, using
    ChildWindowFromPointEx (to ignore invisible and disabled windows). If we
    don't ignore invisible and disabled windows (as is the case with the
    ChildWindowFromPoint call, we are liable to get returns of hidden or
    disabled children of the desktop which don't belong to us, but notionally
    occupy the same area under the pointer.
    
    An alternative might be to start our walk with one of the children of the
    desktop owned by our process and thread - which we can enumerate using,
    the EnumThreadWindows call, or (presumably) determine internally. This
    would not work when we are inside a GtkSocket though, as the children of
    the desktop would belong to the process owning the GtkPlug - we would
    have to rely on our own list of windows.
    
    For correctness, this commit adds tests to ensure that we don't try to
    return either x or y window coordinates if that corresponding pointer is
    NULL.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=658842

 gdk/win32/gdkwindow-win32.c |   76 +++++++++++++++++++++++++++++--------------
 1 files changed, 51 insertions(+), 25 deletions(-)
---
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index 7a2ff60..d895262 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -2540,6 +2540,13 @@ gdk_display_warp_pointer (GdkDisplay *display,
   SetCursorPos (x - _gdk_offset_x, y - _gdk_offset_y);
 }
 
+static void
+screen_to_client (HWND hwnd, POINT screen_pt, POINT *client_pt)
+{
+  *client_pt = screen_pt;
+  ScreenToClient (hwnd, client_pt);
+}
+
 GdkWindow*
 _gdk_windowing_window_at_pointer (GdkDisplay *display,
 				  gint       *win_x,
@@ -2547,43 +2554,62 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display,
 				  GdkModifierType *mask,
 				  gboolean    get_toplevel)
 {
-  GdkWindow *window;
-  POINT point, pointc;
+  GdkWindow *window = NULL;
+  POINT screen_pt, client_pt;
   HWND hwnd, hwndc;
   RECT rect;
 
-  GetCursorPos (&pointc);
-  point = pointc;
-  hwnd = WindowFromPoint (point);
+  GetCursorPos (&screen_pt);
 
-  if (hwnd == NULL)
+  if (get_toplevel)
     {
-      window = _gdk_root;
-      *win_x = pointc.x + _gdk_offset_x;
-      *win_y = pointc.y + _gdk_offset_y;
-      return window;
-    }
-      
-  ScreenToClient (hwnd, &point);
+      /* 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 ((GdkNativeWindow) hwnd);
 
-  do {
-    if (get_toplevel &&
-	(window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd)) != NULL &&
-	GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
-      break;
+        if (window != NULL &&
+            GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT &&
+            GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN)
+          break;
 
-    hwndc = ChildWindowFromPoint (hwnd, point);
-    ClientToScreen (hwnd, &point);
-    ScreenToClient (hwndc, &point);
-  } while (hwndc != hwnd && (hwnd = hwndc, 1));
+        screen_to_client (hwnd, screen_pt, &client_pt);
+        hwndc = ChildWindowFromPointEx (hwnd, client_pt, CWP_SKIPDISABLED  |
+                                                         CWP_SKIPINVISIBLE);
+      } while (hwndc != hwnd && (hwnd = hwndc, 1));
 
-  window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd);
+    }
+  else
+    {
+      hwnd = WindowFromPoint (screen_pt);
+
+      /* If we didn't hit any window at that point, return the desktop */
+      if (hwnd == NULL)
+        {
+          if (win_x)
+            *win_x = screen_pt.x + _gdk_offset_x;
+          if (win_y)
+            *win_y = screen_pt.y + _gdk_offset_y;
+          return _gdk_root;
+        }
+
+      window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd);
+    }
 
   if (window && (win_x || win_y))
     {
+      screen_to_client (hwnd, screen_pt, &client_pt);
       GetClientRect (hwnd, &rect);
-      *win_x = point.x - rect.left;
-      *win_y = point.y - rect.top;
+
+      if (win_x)
+        *win_x = client_pt.x - rect.left;
+      if (win_y)
+        *win_y = client_pt.y - rect.top;
     }
 
   GDK_NOTE (MISC, g_print ("_gdk_windowing_window_at_pointer: %+d%+d %p%s\n",



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