From c71dca236c9f20f8316fe439ff1bfa2d7e38ba2d Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Wed, 25 Aug 2021 17:06:47 +0200 Subject: [PATCH] Use WindowFromPoint to find DND target window --- gdk/win32/gdkdnd-win32.c | 99 +++++++++++-------------------------- gdk/win32/gdkwindow-win32.c | 50 ++++++++++++++----- 2 files changed, 66 insertions(+), 83 deletions(-) diff --git a/gdk/win32/gdkdnd-win32.c b/gdk/win32/gdkdnd-win32.c index 762e5c3023..ff8abc6cbd 100644 --- a/gdk/win32/gdkdnd-win32.c +++ b/gdk/win32/gdkdnd-win32.c @@ -2204,43 +2204,6 @@ _gdk_win32_window_get_drag_protocol (GdkWindow *window, return protocol; } -typedef struct { - gint x; - gint y; - HWND ignore; - HWND result; -} find_window_enum_arg; - -static BOOL CALLBACK -find_window_enum_proc (HWND hwnd, - LPARAM lparam) -{ - RECT rect; - POINT tl, br; - find_window_enum_arg *a = (find_window_enum_arg *) lparam; - - if (hwnd == a->ignore) - return TRUE; - - if (!IsWindowVisible (hwnd)) - return TRUE; - - tl.x = tl.y = 0; - ClientToScreen (hwnd, &tl); - GetClientRect (hwnd, &rect); - br.x = rect.right; - br.y = rect.bottom; - ClientToScreen (hwnd, &br); - - if (a->x >= tl.x && a->y >= tl.y && a->x < br.x && a->y < br.y) - { - a->result = hwnd; - return FALSE; - } - else - return TRUE; -} - static GdkWindow * gdk_win32_drag_context_find_window (GdkDragContext *context, GdkWindow *drag_window, @@ -2250,51 +2213,47 @@ gdk_win32_drag_context_find_window (GdkDragContext *context, GdkDragProtocol *protocol) { GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - GdkWindow *dest_window, *dw; - find_window_enum_arg a; + GdkWindow *toplevel = NULL; + HWND hwnd = NULL; + POINT pt; - a.x = x_root * context_win32->scale - _gdk_offset_x; - a.y = y_root * context_win32->scale - _gdk_offset_y; - a.ignore = drag_window ? GDK_WINDOW_HWND (drag_window) : NULL; - a.result = NULL; + pt.x = x_root * context_win32->scale - _gdk_offset_x; + pt.y = y_root * context_win32->scale - _gdk_offset_y; GDK_NOTE (DND, - g_print ("gdk_drag_find_window_real: %p %+d%+d\n", - (drag_window ? GDK_WINDOW_HWND (drag_window) : NULL), - a.x, a.y)); + g_print ("gdk_drag_find_window_real: %+d%+d\n", + (int) pt.x, (int) pt.y)); - EnumWindows (find_window_enum_proc, (LPARAM) &a); + hwnd = WindowFromPoint (pt); - if (a.result == NULL) - dest_window = NULL; - else + if (hwnd) { - dw = gdk_win32_handle_table_lookup (a.result); - if (dw) + GdkWindow *window = gdk_win32_handle_table_lookup (hwnd); + + if (window) { - dest_window = gdk_window_get_toplevel (dw); - g_object_ref (dest_window); + toplevel = gdk_window_get_toplevel (window); + g_object_ref (toplevel); } else - dest_window = gdk_win32_window_foreign_new_for_display (gdk_screen_get_display (screen), a.result); - - if (use_ole2_dnd) - *protocol = GDK_DRAG_PROTO_OLE2; - else if (context->source_window) - *protocol = GDK_DRAG_PROTO_LOCAL; - else - *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES; + toplevel = gdk_win32_window_foreign_new_for_display (gdk_screen_get_display (screen), hwnd); } - GDK_NOTE (DND, - g_print ("gdk_drag_find_window: %p %+d%+d: %p: %p %s\n", - (drag_window ? GDK_WINDOW_HWND (drag_window) : NULL), - x_root, y_root, - a.result, - (dest_window ? GDK_WINDOW_HWND (dest_window) : NULL), - _gdk_win32_drag_protocol_to_string (*protocol))); + if (use_ole2_dnd) + *protocol = GDK_DRAG_PROTO_OLE2; + else if (context->source_window) + *protocol = GDK_DRAG_PROTO_LOCAL; + else + *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES; - return dest_window; + GDK_NOTE (DND, + g_print ("gdk_drag_find_window: %+d%+d: %p: %p %s\n", + x_root, y_root, + hwnd, + (toplevel ? GDK_WINDOW_HWND (toplevel) : NULL), + _gdk_win32_drag_protocol_to_string (*protocol))); + + return toplevel; } static gboolean diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index 2d0faaca3e..29004669ab 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -885,13 +885,13 @@ _gdk_win32_display_create_window_impl (GdkDisplay *display, if (impl->type_hint == GDK_WINDOW_TYPE_HINT_UTILITY) dwExStyle |= WS_EX_TOOLWINDOW; - /* WS_EX_TRANSPARENT means "try draw this window last, and ignore input". - * It's the last part we're after. We don't want DND indicator to accept - * input, because that will make it a potential drop target, and if it's - * under the mouse cursor, this will kill any DND. + /* WS_EX_LAYERED | WS_EX_TRANSPARENT makes the window transparent w.r.t. + * pointer input: the system will direct all pointer input to the window + * below. We don't want a DND indicator to accept pointer input, because + * that will make it a potential drop target. */ if (impl->type_hint == GDK_WINDOW_TYPE_HINT_DND) - dwExStyle |= WS_EX_TRANSPARENT; + dwExStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT; klass = RegisterGdkClass (window->window_type, impl->type_hint); @@ -1277,10 +1277,10 @@ show_window_internal (GdkWindow *window, exstyle = GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE); - /* Use SetWindowPos to show transparent windows so automatic redraws - * in other windows can be suppressed. + /* If we have to show an input-only window, + * redraws can be safely skipped. */ - if (exstyle & WS_EX_TRANSPARENT) + if (window->input_only) { UINT flags = SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER; @@ -1416,7 +1416,6 @@ show_window_internal (GdkWindow *window, } } - if (window->state & GDK_WINDOW_STATE_FULLSCREEN) { gdk_window_fullscreen (window); @@ -1489,10 +1488,10 @@ gdk_win32_window_hide (GdkWindow *window) if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL) ShowOwnedPopups (GDK_WINDOW_HWND (window), FALSE); - /* Use SetWindowPos to hide transparent windows so automatic redraws - * in other windows can be suppressed. + /* If we have to hide an input-only window, + * readraws can be safely skipped. */ - if (GetWindowLong (GDK_WINDOW_HWND (window), GWL_EXSTYLE) & WS_EX_TRANSPARENT) + if (window->input_only) { SetWindowPos (GDK_WINDOW_HWND (window), SWP_NOZORDER_SPECIFIED, 0, 0, 0, 0, @@ -2787,6 +2786,7 @@ _gdk_win32_window_update_style_bits (GdkWindow *window) GdkWindowImplWin32 *impl = (GdkWindowImplWin32 *)window->impl; GdkWMDecoration decorations; LONG old_style, new_style, old_exstyle, new_exstyle; + gboolean needs_basic_layering = FALSE; gboolean all; RECT rect, before, after; gboolean was_topmost; @@ -2842,7 +2842,18 @@ _gdk_win32_window_update_style_bits (GdkWindow *window) else impl->layered = FALSE; - if (impl->layered) + /* DND windows need to have the WS_EX_TRANSPARENT | WS_EX_LAYERED styles + * set so to behave in input passthrough mode. That's essential for DND + * indicators. + */ + if (!impl->layered && + GDK_WINDOW_HWND (window) != NULL && + impl->type_hint == GDK_WINDOW_TYPE_HINT_DND) + { + needs_basic_layering = TRUE; + } + + if (impl->layered || needs_basic_layering) new_exstyle |= WS_EX_LAYERED; else new_exstyle &= ~WS_EX_LAYERED; @@ -2859,6 +2870,19 @@ _gdk_win32_window_update_style_bits (GdkWindow *window) update_single_bit (&new_style, all, decorations & GDK_DECOR_MAXIMIZE, WS_MAXIMIZEBOX); } + if (needs_basic_layering) + { + /* SetLayeredWindowAttributes may have been already called, e.g. to set an opacity level. + * We only have to call the API in case it has never been called before on the window. + */ + if (SetLastError(0), + !GetLayeredWindowAttributes (GDK_WINDOW_HWND (window), NULL, NULL, NULL) && + GetLastError() == 0) + { + API_CALL (SetLayeredWindowAttributes, (GDK_WINDOW_HWND (window), 0, 255, LWA_ALPHA)); + } + } + if (old_style == new_style && old_exstyle == new_exstyle ) { GDK_NOTE (MISC, g_print ("_gdk_win32_window_update_style_bits: %p: no change\n",