From: Jacek Caban jacek@codeweavers.com
--- dlls/winex11.drv/event.c | 72 +++++++++++++++++++++++++++++++++++++- dlls/winex11.drv/unixlib.h | 43 +++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 10 ++---- dlls/winex11.drv/xdnd.c | 70 ++++++++++-------------------------- 4 files changed, 135 insertions(+), 60 deletions(-) create mode 100644 dlls/winex11.drv/unixlib.h
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index c8cd3fd5ef1..2bfcd3211ae 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1826,6 +1826,76 @@ static void handle_xdnd_enter_event( HWND hWnd, XClientMessageEvent *event ) }
+static DWORD xdnd_action_to_drop_effect( long action ) +{ + /* In Windows, nothing but the given effects is allowed. + * In X the given action is just a hint, and you can always + * XdndActionCopy and XdndActionPrivate, so be more permissive. */ + if (action == x11drv_atom(XdndActionCopy)) + return DROPEFFECT_COPY; + else if (action == x11drv_atom(XdndActionMove)) + return DROPEFFECT_MOVE | DROPEFFECT_COPY; + else if (action == x11drv_atom(XdndActionLink)) + return DROPEFFECT_LINK | DROPEFFECT_COPY; + else if (action == x11drv_atom(XdndActionAsk)) + /* FIXME: should we somehow ask the user what to do here? */ + return DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK; + + FIXME( "unknown action %ld, assuming DROPEFFECT_COPY\n", action ); + return DROPEFFECT_COPY; +} + + +static long drop_effect_to_xdnd_action( DWORD effect ) +{ + if (effect == DROPEFFECT_COPY) + return x11drv_atom(XdndActionCopy); + else if (effect == DROPEFFECT_MOVE) + return x11drv_atom(XdndActionMove); + else if (effect == DROPEFFECT_LINK) + return x11drv_atom(XdndActionLink); + else if (effect == DROPEFFECT_NONE) + return None; + + FIXME( "unknown drop effect %u, assuming XdndActionCopy\n", effect ); + return x11drv_atom(XdndActionCopy); +} + + +static void handle_xdnd_position_event( HWND hwnd, XClientMessageEvent *event ) +{ + struct dnd_position_event_params params; + XClientMessageEvent e; + DWORD effect; + + params.type = DND_POSITION_EVENT; + params.hwnd = hwnd; + params.point = root_to_virtual_screen( event->data.l[2] >> 16, event->data.l[2] & 0xFFFF ); + params.effect = effect = xdnd_action_to_drop_effect( event->data.l[4] ); + + effect = handle_dnd_event( ¶ms ); + + TRACE( "actionRequested(%ld) chosen(0x%x) at x(%d),y(%d)\n", + event->data.l[4], effect, params.point.x, params.point.y ); + + /* + * Let source know if we're accepting the drop by + * sending a status message. + */ + e.type = ClientMessage; + e.display = event->display; + e.window = event->data.l[0]; + e.message_type = x11drv_atom(XdndStatus); + e.format = 32; + e.data.l[0] = event->window; + e.data.l[1] = !!effect; + e.data.l[2] = 0; /* Empty Rect */ + e.data.l[3] = 0; /* Empty Rect */ + e.data.l[4] = drop_effect_to_xdnd_action( effect ); + XSendEvent( event->display, event->data.l[0], False, NoEventMask, (XEvent *)&e ); +} + + struct client_message_handler { int atom; /* protocol atom */ @@ -1839,7 +1909,7 @@ static const struct client_message_handler client_messages[] = { XATOM__XEMBED, handle_xembed_protocol }, { XATOM_DndProtocol, handle_dnd_protocol }, { XATOM_XdndEnter, handle_xdnd_enter_event }, - { XATOM_XdndPosition, X11DRV_XDND_PositionEvent }, + { XATOM_XdndPosition, handle_xdnd_position_event }, { XATOM_XdndDrop, X11DRV_XDND_DropEvent }, { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent } }; diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h new file mode 100644 index 00000000000..7f8ec28b7cf --- /dev/null +++ b/dlls/winex11.drv/unixlib.h @@ -0,0 +1,43 @@ +/* + * Copyright 2022 Jacek Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "ntuser.h" +#include "wine/unixlib.h" + +/* DnD support */ + +struct format_entry +{ + UINT format; + UINT size; + char data[1]; +}; + +enum dnd_event_type +{ + DND_POSITION_EVENT, +}; + +/* DND_POSITION_EVENT params */ +struct dnd_position_event_params +{ + UINT type; + HWND hwnd; + POINT point; + DWORD effect; +}; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9339c1c08e6..d49643a890b 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -61,6 +61,7 @@ typedef int Status; #include "winbase.h" #include "ntgdi.h" #include "wine/gdi_driver.h" +#include "unixlib.h" #include "wine/list.h"
#define MAX_DASHLEN 16 @@ -293,18 +294,11 @@ extern BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp, DWORD dwReadLen) DECLSPEC_HIDDEN; extern void IME_SetResultString(LPWSTR lpResult, DWORD dwResultlen) DECLSPEC_HIDDEN;
-extern void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; extern void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; extern void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN;
-struct format_entry -{ - UINT format; - UINT size; - char data[1]; -}; - extern void handle_dnd_enter_event( struct format_entry *formats, ULONG size ) DECLSPEC_HIDDEN; +extern UINT handle_dnd_event( void *params ) DECLSPEC_HIDDEN;
extern struct format_entry *import_xdnd_selection( Display *display, Window win, Atom selection, Atom *targets, UINT count, diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index e56fc964ada..7633738917f 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -142,27 +142,6 @@ static IDropTarget* get_droptarget_pointer(HWND hwnd) return droptarget; }
-/************************************************************************** - * X11DRV_XDND_XdndActionToDROPEFFECT - */ -static DWORD X11DRV_XDND_XdndActionToDROPEFFECT(long action) -{ - /* In Windows, nothing but the given effects is allowed. - * In X the given action is just a hint, and you can always - * XdndActionCopy and XdndActionPrivate, so be more permissive. */ - if (action == x11drv_atom(XdndActionCopy)) - return DROPEFFECT_COPY; - else if (action == x11drv_atom(XdndActionMove)) - return DROPEFFECT_MOVE | DROPEFFECT_COPY; - else if (action == x11drv_atom(XdndActionLink)) - return DROPEFFECT_LINK | DROPEFFECT_COPY; - else if (action == x11drv_atom(XdndActionAsk)) - /* FIXME: should we somehow ask the user what to do here? */ - return DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK; - FIXME("unknown action %ld, assuming DROPEFFECT_COPY\n", action); - return DROPEFFECT_COPY; -} - /************************************************************************** * X11DRV_XDND_DROPEFFECTToXdndAction */ @@ -215,22 +194,17 @@ static HWND window_accepting_files(HWND hwnd) * * Handle an XdndPosition event. */ -void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) +static BOOL handle_position_event( struct dnd_position_event_params *params ) { - XClientMessageEvent e; int accept = 0; /* Assume we're not accepting */ IDropTarget *dropTarget = NULL; - DWORD effect; + DWORD effect = params->effect; POINTL pointl; HWND targetWindow; HRESULT hr;
- XDNDxy = root_to_virtual_screen( event->data.l[2] >> 16, event->data.l[2] & 0xFFFF ); - targetWindow = window_from_point_dnd(hWnd, XDNDxy); - - pointl.x = XDNDxy.x; - pointl.y = XDNDxy.y; - effect = X11DRV_XDND_XdndActionToDROPEFFECT(event->data.l[4]); + XDNDxy = params->point; + targetWindow = window_from_point_dnd( params->hwnd, XDNDxy );
if (!XDNDAccepted || XDNDLastTargetWnd != targetWindow) { @@ -301,27 +275,7 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) } }
- TRACE("actionRequested(%ld) accept(%d) chosen(0x%x) at x(%d),y(%d)\n", - event->data.l[4], accept, effect, XDNDxy.x, XDNDxy.y); - - /* - * Let source know if we're accepting the drop by - * sending a status message. - */ - e.type = ClientMessage; - e.display = event->display; - e.window = event->data.l[0]; - e.message_type = x11drv_atom(XdndStatus); - e.format = 32; - e.data.l[0] = event->window; - e.data.l[1] = accept; - e.data.l[2] = 0; /* Empty Rect */ - e.data.l[3] = 0; /* Empty Rect */ - if (accept) - e.data.l[4] = X11DRV_XDND_DROPEFFECTToXdndAction(effect); - else - e.data.l[4] = None; - XSendEvent(event->display, event->data.l[0], False, NoEventMask, (XEvent*)&e); + return accept ? effect : 0; }
/************************************************************************** @@ -806,3 +760,17 @@ static IDataObjectVtbl xdndDataObjectVtbl = };
static IDataObject XDNDDataObject = { &xdndDataObjectVtbl }; + +UINT handle_dnd_event( void *params ) +{ + + switch (*(UINT *)params) + { + case DND_POSITION_EVENT: + return handle_position_event( params ); + + default: + ERR( "invalid event\n" ); + return 0; + } +}