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: !2800
This commit is contained in:
Luca Bacci 2020-11-06 22:43:45 +01:00
parent 4661f15fab
commit aec87a3514
No known key found for this signature in database
GPG Key ID: 8E3C8D989C98883D

View File

@ -174,38 +174,25 @@ _gdk_device_win32_surface_at_position (GdkDevice *device,
GdkSurface *window = NULL; GdkSurface *window = NULL;
GdkWin32Surface *impl = NULL; GdkWin32Surface *impl = NULL;
POINT screen_pt, client_pt; POINT screen_pt, client_pt;
HWND hwnd, hwndc; HWND hwnd;
RECT rect; RECT rect;
GetCursorPos (&screen_pt); if (!GetCursorPos (&screen_pt))
return NULL;
/* Only consider visible children of the desktop to avoid the various /* Use WindowFromPoint instead of ChildWindowFromPoint(Ex).
* non-visible windows you often find on a running Windows box. These * Only WindowFromPoint is able to look through transparent
* might overlap our windows and cause our walk to fail. As we assume * layered windows.
* WindowFromPoint() can find our windows, we follow similar logic
* here, and ignore invisible and disabled windows.
*/ */
hwnd = GetDesktopWindow (); hwnd = GetAncestor (WindowFromPoint (screen_pt), GA_ROOT);
do {
window = gdk_win32_handle_table_lookup (hwnd);
if (window != NULL)
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 */ /* Verify that we're really inside the client area of the window */
if (hwndc != hwnd) GetClientRect (hwnd, &rect);
{ screen_to_client (hwnd, screen_pt, &client_pt);
GetClientRect (hwndc, &rect);
screen_to_client (hwndc, screen_pt, &client_pt);
if (!PtInRect (&rect, client_pt)) if (!PtInRect (&rect, client_pt))
hwndc = hwnd; hwnd = NULL;
}
} while (hwndc != hwnd && (hwnd = hwndc, 1)); window = gdk_win32_handle_table_lookup (hwnd);
if (window && (win_x || win_y)) if (window && (win_x || win_y))
{ {