From: "John Found" Subject: [PATCH v2] winex11.drv: Search for the drop target in a correct manner. Message-Id: <20190420072027.8282-1-johnfound@asm32.info> Date: Sat, 20 Apr 2019 10:20:27 +0300 Signed-off-by: John Found --- dlls/winex11.drv/xdnd.c | 50 ++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index 2ab28e43bf..ac2fc644dc 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -254,6 +254,34 @@ void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ) XFree(xdndtypes); } +/* Recursively searches for a window on given coordinates in a drag&drop specific manner. + * + * Don't use WindowFromPoint instead, because it omits the STATIC and transparent + * windows, but they can be a valid drop targets if have WS_EX_ACCEPTFILES set. + */ +static HWND window_from_point_dnd(HWND hwnd, POINT point) +{ + HWND child; + ScreenToClient(hwnd, &point); + while ((child = ChildWindowFromPointEx(hwnd, point, CWP_SKIPDISABLED | CWP_SKIPINVISIBLE)) && child != hwnd) + { + MapWindowPoints(hwnd, child, &point, 1); + hwnd = child; + } + + return hwnd; +} + +/* Returns the first window down the hierarchy that has WS_EX_ACCEPTFILES set or + * returns NULL, if such window does not exists. + */ +static HWND window_accepting_files(HWND hwnd) +{ + while (hwnd && !(GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_ACCEPTFILES)) + hwnd = GetAncestor(hwnd, GA_PARENT); + return hwnd; +} + /************************************************************************** * X11DRV_XDND_PositionEvent * @@ -270,7 +298,7 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) HRESULT hr; XDNDxy = root_to_virtual_screen( event->data.l[2] >> 16, event->data.l[2] & 0xFFFF ); - targetWindow = WindowFromPoint(XDNDxy); + targetWindow = window_from_point_dnd(hWnd, XDNDxy); pointl.x = XDNDxy.x; pointl.y = XDNDxy.y; @@ -334,11 +362,15 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) if (XDNDAccepted) accept = 1; - else if ((GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) && - X11DRV_XDND_HasHDROP()) + else { - accept = 1; - effect = DROPEFFECT_COPY; + /* fallback search for window able to accept these files. */ + + if (window_accepting_files(targetWindow) && X11DRV_XDND_HasHDROP()) + { + accept = 1; + effect = DROPEFFECT_COPY; + } } TRACE("actionRequested(%ld) accept(%d) chosen(0x%x) at x(%d),y(%d)\n", @@ -423,10 +455,12 @@ void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) { /* Only send WM_DROPFILES if Drop didn't succeed or DROPEFFECT_NONE was set. * Doing both causes winamp to duplicate the dropped files (#29081) */ - if ((GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) && - X11DRV_XDND_HasHDROP()) + + HWND hwnd_drop = window_accepting_files(window_from_point_dnd(hWnd, XDNDxy)); + + if (hwnd_drop && X11DRV_XDND_HasHDROP()) { - HRESULT hr = X11DRV_XDND_SendDropFiles( hWnd ); + HRESULT hr = X11DRV_XDND_SendDropFiles(hwnd_drop); if (SUCCEEDED(hr)) { accept = 1; -- 2.21.0