From: Rémi Bernon rbernon@codeweavers.com
And use it to post WM_DROPFILES message. --- dlls/user32/clipboard.c | 13 +++++++++++++ dlls/user32/user_main.c | 8 ++++++++ dlls/user32/user_private.h | 2 ++ dlls/win32u/clipboard.c | 35 ++++++++++++++++++++++++++++++++++ dlls/win32u/message.c | 3 +++ dlls/win32u/ntuser_private.h | 4 ++++ dlls/winex11.drv/dllmain.c | 1 - dlls/winex11.drv/event.c | 17 +++++------------ dlls/winex11.drv/unixlib.h | 11 ----------- dlls/winex11.drv/x11drv.h | 1 - dlls/winex11.drv/x11drv_dll.h | 1 - dlls/winex11.drv/x11drv_main.c | 2 -- dlls/winex11.drv/xdnd.c | 21 -------------------- dlls/wow64win/user.c | 25 ++++++++++++++++++++++++ include/ntuser.h | 29 ++++++++++++++++++++++++++++ 15 files changed, 124 insertions(+), 49 deletions(-)
diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c index 72c7720dc17..0ec42543b34 100644 --- a/dlls/user32/clipboard.c +++ b/dlls/user32/clipboard.c @@ -629,3 +629,16 @@ HANDLE WINAPI GetClipboardData( UINT format ) LeaveCriticalSection( &clipboard_cs ); return ret; } + +void drag_drop_post( HWND hwnd, UINT drop_size, const DROPFILES *drop ) +{ + HDROP handle; + + if ((handle = GlobalAlloc( GMEM_SHARE, drop_size ))) + { + DROPFILES *ptr = GlobalLock( handle ); + memcpy( ptr, drop, drop_size ); + GlobalUnlock( handle ); + PostMessageW( hwnd, WM_DROPFILES, (WPARAM)handle, 0 ); + } +} diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 20b3fa8b1f6..ec307a840f1 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -166,6 +166,13 @@ static NTSTATUS WINAPI User32CallDispatchCallback( void *args, ULONG size ) return callback( params, size ); }
+static NTSTATUS WINAPI User32DragDropPost( void *args, ULONG size ) +{ + const struct drag_drop_post_params *params = args; + drag_drop_post( params->hwnd, params->drop_size, (DROPFILES *)¶ms->drop ); + return STATUS_SUCCESS; +} + static KERNEL_CALLBACK_PROC kernel_callback_table[NtUserCallCount] = { User32CallDispatchCallback, @@ -188,6 +195,7 @@ static KERNEL_CALLBACK_PROC kernel_callback_table[NtUserCallCount] = User32PostDDEMessage, User32RenderSsynthesizedFormat, User32UnpackDDEMessage, + User32DragDropPost, };
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index a9d6a20ddf1..90e76fa16af 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -26,6 +26,7 @@ #include "winbase.h" #include "wingdi.h" #include "ntuser.h" +#include "shlobj.h" #include "winreg.h" #include "winnls.h" #include "wine/heap.h" @@ -51,6 +52,7 @@ extern BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM const void *buffer, size_t size ); extern void free_cached_data( UINT format, HANDLE handle ); extern HANDLE render_synthesized_format( UINT format, UINT from ); +extern void drag_drop_post( HWND hwnd, UINT drop_size, const DROPFILES *drop ); extern void unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, void *buffer, BOOL ansi );
diff --git a/dlls/win32u/clipboard.c b/dlls/win32u/clipboard.c index 6cf484a56ca..f9fbbcd9030 100644 --- a/dlls/win32u/clipboard.c +++ b/dlls/win32u/clipboard.c @@ -754,3 +754,38 @@ HANDLE WINAPI NtUserGetClipboardData( UINT format, struct get_clipboard_params * return 0; } } + +LRESULT drag_drop_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void *data ) +{ + void *ret_ptr; + ULONG ret_len; + + TRACE( "hwnd %p, msg %#x, wparam %#zx, lparam %#lx, data %p\n", hwnd, msg, wparam, lparam, data ); + + switch (msg) + { + case WINE_DRAG_DROP_POST: + { + struct drag_drop_post_params *params; + const DROPFILES *drop = (DROPFILES *)lparam; + UINT drop_size = wparam, size; + NTSTATUS status; + + size = offsetof(struct drag_drop_post_params, drop) + drop_size; + if (!(params = malloc( size ))) return STATUS_NO_MEMORY; + params->hwnd = hwnd; + params->drop_size = drop_size; + memcpy( ¶ms->drop, drop, drop_size ); + + status = KeUserModeCallback( NtUserDragDropPost, params, size, &ret_ptr, &ret_len ); + free( params ); + return status; + } + + default: + FIXME( "Unknown NtUserDragDropCall msg %#x\n", msg ); + break; + } + + return -1; +} diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index c5913054f48..fd41bd670ce 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -4426,6 +4426,9 @@ LRESULT WINAPI NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa case NtUserSystemTrayCall: return system_tray_call( hwnd, msg, wparam, lparam, result_info );
+ case NtUserDragDropCall: + return drag_drop_call( hwnd, msg, wparam, lparam, result_info ); + default: FIXME( "%p %x %lx %lx %p %x %x\n", hwnd, msg, (long)wparam, lparam, result_info, (int)type, ansi ); } diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index f7d84e12cd1..dbf792bc3d2 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -24,6 +24,7 @@
#include "ntuser.h" #include "shellapi.h" +#include "shlobj.h" #include "wine/list.h" #include "wine/vulkan.h"
@@ -216,6 +217,9 @@ extern void register_desktop_class(void); extern LRESULT ime_driver_call( HWND hwnd, enum wine_ime_call call, WPARAM wparam, LPARAM lparam, struct ime_driver_call_params *params );
+/* clipboard.c */ +extern LRESULT drag_drop_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void *data ); + /* cursoricon.c */ HICON alloc_cursoricon_handle( BOOL is_icon );
diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index 14336adf583..08ef36bdcde 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -31,7 +31,6 @@ BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) { .dnd_enter_event_callback = (UINT_PTR)x11drv_dnd_enter_event, .dnd_position_event_callback = (UINT_PTR)x11drv_dnd_position_event, - .dnd_post_drop_callback = (UINT_PTR)x11drv_dnd_post_drop, .dnd_drop_event_callback = (UINT_PTR)x11drv_dnd_drop_event, .dnd_leave_event_callback = (UINT_PTR)x11drv_dnd_leave_event, .foreign_window_proc = (UINT_PTR)foreign_window_proc, diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 34a364e11e3..3280dce0f10 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1436,17 +1436,10 @@ static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt ) return hQueryWnd; }
-static void post_drop( HWND hwnd, DROPFILES *drop, ULONG size ) +static void drag_drop_post( HWND hwnd, DROPFILES *drop, ULONG size ) { - struct dnd_post_drop_params *params; - void *ret_ptr; - ULONG ret_len; - if (!(params = malloc( sizeof(*params) + size - sizeof(*drop) ))) return; - memcpy( ¶ms->drop, drop, size ); - params->drop.fWide = HandleToUlong( hwnd ); /* abuse fWide to pass window handle */ - params->dispatch.callback = dnd_post_drop_callback; - KeUserDispatchCallback( ¶ms->dispatch, size, &ret_ptr, &ret_len ); - free( params ); + NtUserMessageCall( hwnd, WINE_DRAG_DROP_POST, size, (LPARAM)drop, NULL, + NtUserDragDropCall, FALSE ); }
/********************************************************************** @@ -1498,7 +1491,7 @@ static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
if ((drop = file_list_to_drop_files( p_data, get_property_size( format, data_length ), &drop_size ))) { - post_drop( hWnd, drop, drop_size ); + drag_drop_post( hWnd, drop, drop_size ); free( drop ); } } @@ -1560,7 +1553,7 @@ static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event ) release_win_data( win_data ); }
- post_drop( hWnd, drop, drop_size ); + drag_drop_post( hWnd, drop, drop_size ); free( drop ); }
diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index 522411f8e55..170cd4f80fc 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -89,14 +89,3 @@ struct dnd_drop_event_params struct dispatch_callback_params dispatch; ULONG hwnd; }; - -/* x11drv_dnd_post_drop params */ -struct dnd_post_drop_params -{ - struct dispatch_callback_params dispatch; - UINT32 __pad; - DROPFILES drop; - char data[]; -}; - -C_ASSERT(sizeof(struct dnd_post_drop_params) == offsetof(struct dnd_post_drop_params, data[0])); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 2ecf3cb54cd..7fb1d601690 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -436,7 +436,6 @@ extern Display *clipboard_display; extern UINT64 client_foreign_window_proc; extern UINT64 dnd_enter_event_callback; extern UINT64 dnd_position_event_callback; -extern UINT64 dnd_post_drop_callback; extern UINT64 dnd_drop_event_callback; extern UINT64 dnd_leave_event_callback;
diff --git a/dlls/winex11.drv/x11drv_dll.h b/dlls/winex11.drv/x11drv_dll.h index bc68c3996c3..3ed9fea6a5a 100644 --- a/dlls/winex11.drv/x11drv_dll.h +++ b/dlls/winex11.drv/x11drv_dll.h @@ -29,7 +29,6 @@
extern NTSTATUS WINAPI x11drv_dnd_enter_event( void *params, ULONG size ); extern NTSTATUS WINAPI x11drv_dnd_position_event( void *params, ULONG size ); -extern NTSTATUS WINAPI x11drv_dnd_post_drop( void *data, ULONG size ); extern NTSTATUS WINAPI x11drv_dnd_drop_event( void *params, ULONG size ); extern NTSTATUS WINAPI x11drv_dnd_leave_event( void *params, ULONG size );
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 3f8e48a7a8d..77169bf287f 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -88,7 +88,6 @@ char *process_name = NULL; UINT64 client_foreign_window_proc = 0; UINT64 dnd_enter_event_callback = 0; UINT64 dnd_position_event_callback = 0; -UINT64 dnd_post_drop_callback = 0; UINT64 dnd_drop_event_callback = 0; UINT64 dnd_leave_event_callback = 0;
@@ -650,7 +649,6 @@ static NTSTATUS x11drv_init( void *arg )
dnd_enter_event_callback = params->dnd_enter_event_callback; dnd_position_event_callback = params->dnd_position_event_callback; - dnd_post_drop_callback = params->dnd_post_drop_callback; dnd_drop_event_callback = params->dnd_drop_event_callback; dnd_leave_event_callback = params->dnd_leave_event_callback; client_foreign_window_proc = params->foreign_window_proc; diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index 174b764aa63..d9f8380b95e 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -744,24 +744,3 @@ NTSTATUS WINAPI x11drv_dnd_enter_event( void *args, ULONG size ) if (previous) IDataObject_Release( previous ); return STATUS_SUCCESS; } - - -NTSTATUS WINAPI x11drv_dnd_post_drop( void *args, ULONG size ) -{ - UINT drop_size = size - offsetof(struct dnd_post_drop_params, drop); - struct dnd_post_drop_params *params = args; - HDROP handle; - - if ((handle = GlobalAlloc( GMEM_SHARE, drop_size ))) - { - DROPFILES *ptr = GlobalLock( handle ); - HWND hwnd; - memcpy( ptr, ¶ms->drop, drop_size ); - hwnd = UlongToHandle( ptr->fWide ); - ptr->fWide = TRUE; - GlobalUnlock( handle ); - PostMessageW( hwnd, WM_DROPFILES, (WPARAM)handle, 0 ); - } - - return STATUS_SUCCESS; -} diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 33bd65c5fea..f7e311990bc 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -26,6 +26,7 @@ #include "winbase.h" #include "ntuser.h" #include "shellapi.h" +#include "shlobj.h" #include "wow64win_private.h" #include "wine/debug.h"
@@ -1450,6 +1451,26 @@ static NTSTATUS WINAPI wow64_NtUserCallDispatchCallback( void *arg, ULONG size ) return dispatch_callback( NtUserCallDispatchCallback, arg, size ); }
+static NTSTATUS WINAPI wow64_NtUserDragDropPost( void *arg, ULONG size ) +{ + struct drag_drop_post_params32 + { + ULONG hwnd; + UINT drop_size; + struct drop_files drop; + BYTE files[]; + }; + const struct drag_drop_post_params *params = arg; + struct drag_drop_post_params32 *params32; + + size = offsetof(struct drag_drop_post_params32, drop) + params->drop_size; + if (!(params32 = Wow64AllocateTemp( size ))) return STATUS_NO_MEMORY; + params32->hwnd = HandleToUlong( params->hwnd ); + params32->drop_size = params->drop_size; + memcpy( ¶ms32->drop, ¶ms->drop, params->drop_size ); + return dispatch_callback( NtUserDragDropPost, params32, size ); +} + ntuser_callback user_callbacks[] = { /* user32 callbacks */ @@ -1473,6 +1494,7 @@ ntuser_callback user_callbacks[] = wow64_NtUserPostDDEMessage, wow64_NtUserRenderSynthesizedFormat, wow64_NtUserUnpackDDEMessage, + wow64_NtUserDragDropPost, };
C_ASSERT( ARRAYSIZE(user_callbacks) == NtUserCallCount ); @@ -3619,6 +3641,9 @@ NTSTATUS WINAPI wow64_NtUserMessageCall( UINT *args ) default: return NtUserMessageCall( hwnd, msg, wparam, lparam, result_info, type, ansi ); } + + case NtUserDragDropCall: + return NtUserMessageCall( hwnd, msg, wparam, lparam, result_info, type, ansi ); }
return message_call_32to64( hwnd, msg, wparam, lparam, result_info, type, ansi ); diff --git a/include/ntuser.h b/include/ntuser.h index 69dd1e2f434..6282f995ead 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -73,6 +73,7 @@ enum NtUserPostDDEMessage, NtUserRenderSynthesizedFormat, NtUserUnpackDDEMessage, + NtUserDragDropPost, NtUserCallCount };
@@ -299,6 +300,27 @@ struct unpack_dde_message_result LPARAM lparam; };
+/* NtUserDragDropPost params */ + +/* avoid including shlobj.h */ +struct drop_files +{ + DWORD pFiles; + POINT pt; + BOOL fNC; + BOOL fWide; +}; + +struct drag_drop_post_params +{ + HWND hwnd; + UINT drop_size; + struct drop_files drop; + BYTE files[]; +}; + +C_ASSERT( sizeof(struct drag_drop_post_params) == offsetof(struct drag_drop_post_params, files[0]) ); + /* DPI awareness contexts */ #define MAKE_NTUSER_DPI_CONTEXT( awareness, version, dpi, flags ) ((awareness) | ((version) << 4) | ((dpi) << 8) | (flags)) #define NTUSER_DPI_CONTEXT_GET_AWARENESS( ctx ) ((ctx) & 0x0f) @@ -349,6 +371,7 @@ enum NtUserSpyExit = 0x0304, NtUserImeDriverCall = 0x0305, NtUserSystemTrayCall = 0x0306, + NtUserDragDropCall = 0x0307, };
/* NtUserThunkedMenuItemInfo codes */ @@ -568,6 +591,12 @@ enum wine_systray_call WINE_SYSTRAY_DOCK_REMOVE, };
+/* NtUserDragDropCall calls */ +enum wine_drag_drop_call +{ + WINE_DRAG_DROP_POST, +}; + #define WM_SYSTIMER 0x0118
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 3280dce0f10..58e743a4fec 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1443,11 +1443,11 @@ static void drag_drop_post( HWND hwnd, DROPFILES *drop, ULONG size ) }
/********************************************************************** - * EVENT_DropFromOffix + * drop_dnd_files * * don't know if it still works (last Changelog is from 96/11/04) */ -static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event ) +static void drop_dnd_files( HWND hWnd, XClientMessageEvent *event, POINT pos ) { struct x11drv_win_data *data; POINT pt; @@ -1500,14 +1500,14 @@ static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event ) }
/********************************************************************** - * EVENT_DropURLs + * drop_dnd_urls * * drop items are separated by \n * each item is prefixed by its mime type * * event->data.l[3], event->data.l[4] contains drop x,y position */ -static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event ) +static void drop_dnd_urls( HWND hWnd, XClientMessageEvent *event, POINT pos ) { struct x11drv_win_data *win_data; unsigned long data_length; @@ -1625,18 +1625,22 @@ static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) { Window root, child; - int root_x, root_y, child_x, child_y; - unsigned int u; + int root_x, root_y; + unsigned int mask; + POINT pos;
/* query window (drag&drop event contains only drag window) */ - XQueryPointer( event->display, root_window, &root, &child, - &root_x, &root_y, &child_x, &child_y, &u); + XQueryPointer( event->display, root_window, &root, &child, &root_x, &root_y, + (int *)&pos.x, (int *)&pos.y, &mask ); + pos = root_to_virtual_screen( pos.x, pos.y ); + if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0; if (!hwnd) return; + if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) - EVENT_DropFromOffiX(hwnd, event); + drop_dnd_files( hwnd, event, pos ); else if (event->data.l[0] == DndURL) - EVENT_DropURLs(hwnd, event); + drop_dnd_urls( hwnd, event, pos ); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 114 +++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 66 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 58e743a4fec..5b9dacd6cc4 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1447,22 +1447,21 @@ static void drag_drop_post( HWND hwnd, DROPFILES *drop, ULONG size ) * * don't know if it still works (last Changelog is from 96/11/04) */ -static void drop_dnd_files( HWND hWnd, XClientMessageEvent *event, POINT pos ) +static void drop_dnd_files( HWND hWnd, XClientMessageEvent *event, POINT pos, unsigned char *data, size_t size ) { - struct x11drv_win_data *data; + struct x11drv_win_data *win_data; POINT pt; - unsigned long data_length; unsigned long aux_long; - unsigned char* p_data = NULL; - Atom atom_aux; - int x, y, cx, cy, dummy, format; + int x, y, cx, cy, dummy; Window win, w_aux_root, w_aux_child; + size_t drop_size; + DROPFILES *drop;
- if (!(data = get_win_data( hWnd ))) return; - cx = data->rects.visible.right - data->rects.visible.left; - cy = data->rects.visible.bottom - data->rects.visible.top; - win = data->whole_window; - release_win_data( data ); + if (!(win_data = get_win_data( hWnd ))) return; + cx = win_data->rects.visible.right - win_data->rects.visible.left; + cy = win_data->rects.visible.bottom - win_data->rects.visible.top; + win = win_data->whole_window; + release_win_data( win_data );
XQueryPointer( event->display, win, &w_aux_root, &w_aux_child, &x, &y, &dummy, &dummy, (unsigned int*)&aux_long); @@ -1479,24 +1478,11 @@ static void drop_dnd_files( HWND hWnd, XClientMessageEvent *event, POINT pos ) if (!find_drop_window( hWnd, &pt )) return; }
- XGetWindowProperty( event->display, DefaultRootWindow(event->display), - x11drv_atom(DndSelection), 0, 65535, FALSE, - AnyPropertyType, &atom_aux, &format, - &data_length, &aux_long, &p_data); - - if (!aux_long && p_data) /* don't bother if > 64K */ + if ((drop = file_list_to_drop_files( data, size, &drop_size ))) { - size_t drop_size; - DROPFILES *drop; - - if ((drop = file_list_to_drop_files( p_data, get_property_size( format, data_length ), &drop_size ))) - { - drag_drop_post( hWnd, drop, drop_size ); - free( drop ); - } + drag_drop_post( hWnd, drop, drop_size ); + free( drop ); } - - if (p_data) XFree(p_data); }
/********************************************************************** @@ -1507,59 +1493,42 @@ static void drop_dnd_files( HWND hWnd, XClientMessageEvent *event, POINT pos ) * * event->data.l[3], event->data.l[4] contains drop x,y position */ -static void drop_dnd_urls( HWND hWnd, XClientMessageEvent *event, POINT pos ) +static void drop_dnd_urls( HWND hWnd, XClientMessageEvent *event, POINT pos, unsigned char *data, size_t size ) { struct x11drv_win_data *win_data; - unsigned long data_length; - unsigned long aux_long; - unsigned char *p_data = NULL; /* property data */ int x, y; - int format; union { Atom atom_aux; int i; Window w_aux; unsigned int u; } u; /* unused */ + size_t drop_size; + DROPFILES *drop;
if (!(NtUserGetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
- XGetWindowProperty( event->display, DefaultRootWindow(event->display), - x11drv_atom(DndSelection), 0, 65535, FALSE, - AnyPropertyType, &u.atom_aux, &format, - &data_length, &aux_long, &p_data); - if (aux_long) - WARN("property too large, truncated!\n"); - TRACE("urls=%s\n", p_data); - - if (!aux_long && p_data) /* don't bother if > 64K */ + if ((drop = uri_list_to_drop_files( data, size, &drop_size ))) { - size_t drop_size; - DROPFILES *drop; + XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux, + &x, &y, &u.i, &u.i, &u.u); + drop->pt = root_to_virtual_screen( x, y );
- if ((drop = uri_list_to_drop_files( p_data, get_property_size( format, data_length ), &drop_size ))) + if ((win_data = get_win_data( hWnd ))) { - XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux, - &x, &y, &u.i, &u.i, &u.u); - drop->pt = root_to_virtual_screen( x, y ); - - if ((win_data = get_win_data( hWnd ))) - { - drop->fNC = - (drop->pt.x < (win_data->rects.client.left - win_data->rects.visible.left) || - drop->pt.y < (win_data->rects.client.top - win_data->rects.visible.top) || - drop->pt.x > (win_data->rects.client.right - win_data->rects.visible.left) || - drop->pt.y > (win_data->rects.client.bottom - win_data->rects.visible.top) ); - release_win_data( win_data ); - } - - drag_drop_post( hWnd, drop, drop_size ); - free( drop ); + drop->fNC = + (drop->pt.x < (win_data->rects.client.left - win_data->rects.visible.left) || + drop->pt.y < (win_data->rects.client.top - win_data->rects.visible.top) || + drop->pt.x > (win_data->rects.client.right - win_data->rects.visible.left) || + drop->pt.y > (win_data->rects.client.bottom - win_data->rects.visible.top) ); + release_win_data( win_data ); }
+ drag_drop_post( hWnd, drop, drop_size ); free( drop ); } - if (p_data) XFree( p_data ); + + free( drop ); }
@@ -1624,10 +1593,14 @@ static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) */ static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) { + unsigned long count, remaining; Window root, child; - int root_x, root_y; + int root_x, root_y, format; + unsigned char *data; unsigned int mask; + size_t size; POINT pos; + Atom type;
/* query window (drag&drop event contains only drag window) */ XQueryPointer( event->display, root_window, &root, &child, &root_x, &root_y, @@ -1637,10 +1610,19 @@ static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0; if (!hwnd) return;
- if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) - drop_dnd_files( hwnd, event, pos ); - else if (event->data.l[0] == DndURL) - drop_dnd_urls( hwnd, event, pos ); + if (XGetWindowProperty( event->display, DefaultRootWindow(event->display), x11drv_atom(DndSelection), 0, 65535, + False, AnyPropertyType, &type, &format, &count, &remaining, &data ) || !data) + return; + + if (!remaining /* don't bother if > 64K */ && (size = get_property_size( format, count ))) + { + if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) + drop_dnd_files( hwnd, event, pos, data, size ); + else if (event->data.l[0] == DndURL) + drop_dnd_urls( hwnd, event, pos, data, size ); + } + + XFree( data ); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/user32/clipboard.c | 33 +++++++++++ dlls/winex11.drv/event.c | 125 ++++----------------------------------- 2 files changed, 46 insertions(+), 112 deletions(-)
diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c index 0ec42543b34..b1d5f5805e8 100644 --- a/dlls/user32/clipboard.c +++ b/dlls/user32/clipboard.c @@ -630,10 +630,43 @@ HANDLE WINAPI GetClipboardData( UINT format ) return ret; }
+/* 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 ) +{ + /* MUST to be GetParent, not GetAncestor, because the owner window (with WS_EX_ACCEPTFILES) + * of a window with WS_POPUP is a valid drop target. GetParent works exactly this way! */ + while (hwnd && !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) hwnd = GetParent( hwnd ); + return hwnd; +} + void drag_drop_post( HWND hwnd, UINT drop_size, const DROPFILES *drop ) { + POINT point = drop->pt; HDROP handle;
+ hwnd = window_accepting_files( window_from_point_dnd( hwnd, point ) ); if ((handle = GlobalAlloc( GMEM_SHARE, drop_size ))) { DROPFILES *ptr = GlobalLock( handle ); diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 5b9dacd6cc4..abc9a3d420c 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1400,135 +1400,36 @@ void X11DRV_SetFocus( HWND hwnd ) release_win_data( data ); }
- -static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt ) -{ - UINT dpi = NtUserGetWinMonitorDpi( hQueryWnd, MDT_DEFAULT ); - RECT tempRect; - - if (!NtUserIsWindowEnabled(hQueryWnd)) return 0; - - NtUserGetWindowRect( hQueryWnd, &tempRect, dpi ); - - if(!PtInRect(&tempRect, *lpPt)) return 0; - - if (!(NtUserGetWindowLongW( hQueryWnd, GWL_STYLE ) & WS_MINIMIZE)) - { - POINT pt = *lpPt; - NtUserMapWindowPoints( 0, hQueryWnd, &pt, 1, 0 /* per-monitor DPI */ ); - NtUserGetClientRect( hQueryWnd, &tempRect, dpi ); - - if (PtInRect( &tempRect, pt)) - { - HWND ret = child_window_from_point( hQueryWnd, pt.x, pt.y, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED ); - if (ret && ret != hQueryWnd) - { - ret = find_drop_window( ret, lpPt ); - if (ret) return ret; - } - } - } - - if(!(NtUserGetWindowLongW( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0; - - NtUserMapWindowPoints( 0, hQueryWnd, lpPt, 1, 0 /* per-monitor DPI */ ); - - return hQueryWnd; -} - static void drag_drop_post( HWND hwnd, DROPFILES *drop, ULONG size ) { NtUserMessageCall( hwnd, WINE_DRAG_DROP_POST, size, (LPARAM)drop, NULL, NtUserDragDropCall, FALSE ); }
-/********************************************************************** - * drop_dnd_files - * - * don't know if it still works (last Changelog is from 96/11/04) - */ -static void drop_dnd_files( HWND hWnd, XClientMessageEvent *event, POINT pos, unsigned char *data, size_t size ) +static void drop_dnd_files( HWND hWnd, POINT pos, unsigned char *data, size_t size ) { - struct x11drv_win_data *win_data; - POINT pt; - unsigned long aux_long; - int x, y, cx, cy, dummy; - Window win, w_aux_root, w_aux_child; size_t drop_size; DROPFILES *drop;
- if (!(win_data = get_win_data( hWnd ))) return; - cx = win_data->rects.visible.right - win_data->rects.visible.left; - cy = win_data->rects.visible.bottom - win_data->rects.visible.top; - win = win_data->whole_window; - release_win_data( win_data ); - - XQueryPointer( event->display, win, &w_aux_root, &w_aux_child, - &x, &y, &dummy, &dummy, (unsigned int*)&aux_long); - pt = root_to_virtual_screen( x, y ); - - /* find out drop point and drop window */ - if (pt.x < 0 || pt.y < 0 || pt.x > cx || pt.y > cy) - { - if (!(NtUserGetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return; - pt.x = pt.y = 0; - } - else - { - if (!find_drop_window( hWnd, &pt )) return; - } - if ((drop = file_list_to_drop_files( data, size, &drop_size ))) { + drop->pt = pos; drag_drop_post( hWnd, drop, drop_size ); free( drop ); } }
-/********************************************************************** - * drop_dnd_urls - * - * drop items are separated by \n - * each item is prefixed by its mime type - * - * event->data.l[3], event->data.l[4] contains drop x,y position - */ -static void drop_dnd_urls( HWND hWnd, XClientMessageEvent *event, POINT pos, unsigned char *data, size_t size ) +static void drop_dnd_urls( HWND hWnd, POINT pos, unsigned char *data, size_t size ) { - struct x11drv_win_data *win_data; - int x, y; - union { - Atom atom_aux; - int i; - Window w_aux; - unsigned int u; - } u; /* unused */ - size_t drop_size; - DROPFILES *drop; - - if (!(NtUserGetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return; - - if ((drop = uri_list_to_drop_files( data, size, &drop_size ))) - { - XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux, - &x, &y, &u.i, &u.i, &u.u); - drop->pt = root_to_virtual_screen( x, y ); - - if ((win_data = get_win_data( hWnd ))) - { - drop->fNC = - (drop->pt.x < (win_data->rects.client.left - win_data->rects.visible.left) || - drop->pt.y < (win_data->rects.client.top - win_data->rects.visible.top) || - drop->pt.x > (win_data->rects.client.right - win_data->rects.visible.left) || - drop->pt.y > (win_data->rects.client.bottom - win_data->rects.visible.top) ); - release_win_data( win_data ); - } - - drag_drop_post( hWnd, drop, drop_size ); - free( drop ); - } + size_t drop_size; + DROPFILES *drop;
- free( drop ); + if ((drop = uri_list_to_drop_files( data, size, &drop_size ))) + { + drop->pt = pos; + drag_drop_post( hWnd, drop, drop_size ); + free( drop ); + } }
@@ -1617,9 +1518,9 @@ static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) if (!remaining /* don't bother if > 64K */ && (size = get_property_size( format, count ))) { if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) - drop_dnd_files( hwnd, event, pos, data, size ); + drop_dnd_files( hwnd, pos, data, size ); else if (event->data.l[0] == DndURL) - drop_dnd_urls( hwnd, event, pos, data, size ); + drop_dnd_urls( hwnd, pos, data, size ); }
XFree( data );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/user32/Makefile.in | 4 +- dlls/user32/clipboard.c | 625 +++++++++++++++++++++++++++ dlls/user32/user_main.c | 30 ++ dlls/user32/user_private.h | 4 + dlls/win32u/clipboard.c | 26 ++ dlls/winex11.drv/Makefile.in | 2 - dlls/winex11.drv/dllmain.c | 4 - dlls/winex11.drv/event.c | 64 +-- dlls/winex11.drv/unixlib.h | 44 -- dlls/winex11.drv/x11drv.h | 4 - dlls/winex11.drv/x11drv_dll.h | 5 - dlls/winex11.drv/x11drv_main.c | 8 - dlls/winex11.drv/xdnd.c | 746 --------------------------------- dlls/wow64win/user.c | 50 +++ include/ntuser.h | 30 ++ 15 files changed, 799 insertions(+), 847 deletions(-) delete mode 100644 dlls/winex11.drv/xdnd.c
diff --git a/dlls/user32/Makefile.in b/dlls/user32/Makefile.in index 5f624559931..69e1fa24e15 100644 --- a/dlls/user32/Makefile.in +++ b/dlls/user32/Makefile.in @@ -1,9 +1,9 @@ EXTRADEFS = -D_USER32_ MODULE = user32.dll IMPORTLIB = user32 -IMPORTS = $(PNG_PE_LIBS) gdi32 sechost advapi32 kernelbase win32u +IMPORTS = $(PNG_PE_LIBS) gdi32 sechost advapi32 kernelbase win32u uuid EXTRAINCL = $(PNG_PE_CFLAGS) -DELAYIMPORTS = imm32 +DELAYIMPORTS = imm32 combase
SOURCES = \ button.c \ diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c index b1d5f5805e8..2e8a6614a76 100644 --- a/dlls/user32/clipboard.c +++ b/dlls/user32/clipboard.c @@ -23,9 +23,12 @@ * */
+#define COBJMACROS #include <assert.h> #include "user_private.h" #include "winnls.h" +#include "objidl.h" +#include "shlobj.h" #include "wine/server.h" #include "wine/debug.h"
@@ -40,6 +43,8 @@ static CRITICAL_SECTION_DEBUG critsect_debug = 0, 0, { (DWORD_PTR)(__FILE__ ": clipboard_cs") } }; static CRITICAL_SECTION clipboard_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; +static IDataObject *dnd_data_object; +
/* platform-independent version of METAFILEPICT */ struct metafile_pict @@ -630,6 +635,446 @@ HANDLE WINAPI GetClipboardData( UINT format ) return ret; }
+static struct format_entry *next_format( struct format_entry *entry ) +{ + return (struct format_entry *)&entry->data[(entry->size + 7) & ~7]; +} + +struct data_object +{ + IDataObject IDataObject_iface; + LONG refcount; + + HWND target_hwnd; /* the last window the mouse was over */ + POINT target_pos; + DWORD target_effect; + IDropTarget *drop_target; + + struct format_entry *entries_end; + struct format_entry entries[]; +}; + +static struct data_object *data_object_from_IDataObject( IDataObject *iface ) +{ + return CONTAINING_RECORD( iface, struct data_object, IDataObject_iface ); +} + +struct format_iterator +{ + IEnumFORMATETC IEnumFORMATETC_iface; + LONG refcount; + + struct format_entry *entry; + IDataObject *object; +}; + +static inline struct format_iterator *format_iterator_from_IEnumFORMATETC( IEnumFORMATETC *iface ) +{ + return CONTAINING_RECORD(iface, struct format_iterator, IEnumFORMATETC_iface); +} + +static HRESULT WINAPI format_iterator_QueryInterface( IEnumFORMATETC *iface, REFIID iid, void **obj ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + + TRACE( "iterator %p, iid %s, obj %p\n", iterator, debugstr_guid(iid), obj ); + + if (IsEqualIID( iid, &IID_IUnknown ) || IsEqualIID( iid, &IID_IEnumFORMATETC )) + { + IEnumFORMATETC_AddRef( &iterator->IEnumFORMATETC_iface ); + *obj = &iterator->IEnumFORMATETC_iface; + return S_OK; + } + + *obj = NULL; + WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid) ); + return E_NOINTERFACE; +} + +static ULONG WINAPI format_iterator_AddRef( IEnumFORMATETC *iface ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + ULONG ref = InterlockedIncrement( &iterator->refcount ); + TRACE( "iterator %p increasing refcount to %lu.\n", iterator, ref ); + return ref; +} + +static ULONG WINAPI format_iterator_Release(IEnumFORMATETC *iface) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + ULONG ref = InterlockedDecrement( &iterator->refcount ); + + TRACE( "iterator %p increasing refcount to %lu.\n", iterator, ref ); + + if (!ref) + { + IDataObject_Release( iterator->object ); + free( iterator ); + } + + return ref; +} + +static HRESULT WINAPI format_iterator_Next( IEnumFORMATETC *iface, ULONG count, FORMATETC *formats, ULONG *ret ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + struct data_object *object = data_object_from_IDataObject( iterator->object ); + struct format_entry *entry; + UINT i; + + TRACE( "iterator %p, count %lu, formats %p, ret %p\n", iterator, count, formats, ret ); + + for (entry = iterator->entry, i = 0; entry < object->entries_end && i < count; entry = next_format( entry ), i++) + { + formats[i].cfFormat = entry->format; + formats[i].ptd = NULL; + formats[i].dwAspect = DVASPECT_CONTENT; + formats[i].lindex = -1; + formats[i].tymed = TYMED_HGLOBAL; + } + + iterator->entry = entry; + if (ret) *ret = i; + return (i == count) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI format_iterator_Skip( IEnumFORMATETC *iface, ULONG count ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + struct data_object *object = data_object_from_IDataObject( iterator->object ); + struct format_entry *entry; + + TRACE( "iterator %p, count %lu\n", iterator, count ); + + for (entry = iterator->entry; entry < object->entries_end; entry = next_format( entry )) + if (!count--) break; + + iterator->entry = entry; + return count ? S_FALSE : S_OK; +} + +static HRESULT WINAPI format_iterator_Reset( IEnumFORMATETC *iface ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + struct data_object *object = data_object_from_IDataObject( iterator->object ); + + TRACE( "iterator %p\n", iterator ); + iterator->entry = object->entries; + return S_OK; +} + +static HRESULT format_iterator_create( IDataObject *object, IEnumFORMATETC **out ); + +static HRESULT WINAPI format_iterator_Clone( IEnumFORMATETC *iface, IEnumFORMATETC **out ) +{ + struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); + TRACE( "iterator %p, out %p\n", iterator, out ); + return format_iterator_create( iterator->object, out ); +} + +static const IEnumFORMATETCVtbl format_iterator_vtbl = +{ + format_iterator_QueryInterface, + format_iterator_AddRef, + format_iterator_Release, + format_iterator_Next, + format_iterator_Skip, + format_iterator_Reset, + format_iterator_Clone, +}; + +static HRESULT format_iterator_create( IDataObject *object, IEnumFORMATETC **out ) +{ + struct format_iterator *iterator; + + if (!(iterator = calloc( 1, sizeof(*iterator) ))) return E_OUTOFMEMORY; + iterator->IEnumFORMATETC_iface.lpVtbl = &format_iterator_vtbl; + iterator->refcount = 1; + IDataObject_AddRef( (iterator->object = object) ); + iterator->entry = data_object_from_IDataObject(object)->entries; + + *out = &iterator->IEnumFORMATETC_iface; + TRACE( "created object %p iterator %p\n", object, iterator ); + return S_OK; +} + +static HRESULT WINAPI data_object_QueryInterface( IDataObject *iface, REFIID iid, void **obj ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + + TRACE( "object %p, iid %s, obj %p\n", object, debugstr_guid(iid), obj ); + + if (IsEqualIID( iid, &IID_IUnknown ) || IsEqualIID( iid, &IID_IDataObject )) + { + IDataObject_AddRef( &object->IDataObject_iface ); + *obj = &object->IDataObject_iface; + return S_OK; + } + + *obj = NULL; + WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid) ); + return E_NOINTERFACE; +} + +static ULONG WINAPI data_object_AddRef( IDataObject *iface ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + ULONG ref = InterlockedIncrement( &object->refcount ); + TRACE( "object %p increasing refcount to %lu.\n", object, ref ); + return ref; +} + +static ULONG WINAPI data_object_Release( IDataObject *iface ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + ULONG ref = InterlockedDecrement( &object->refcount ); + + TRACE( "object %p decreasing refcount to %lu.\n", object, ref ); + + if (!ref) + { + if (object->drop_target) + { + HRESULT hr = IDropTarget_DragLeave( object->drop_target ); + if (FAILED(hr)) WARN( "IDropTarget_DragLeave returned %#lx\n", hr ); + IDropTarget_Release( object->drop_target ); + } + + free( object ); + } + + return ref; +} + +static HRESULT WINAPI data_object_GetData( IDataObject *iface, FORMATETC *format, STGMEDIUM *medium ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + struct format_entry *iter; + HRESULT hr; + + TRACE( "object %p, format %p (%s), medium %p\n", object, format, debugstr_format(format->cfFormat), medium ); + + if (FAILED(hr = IDataObject_QueryGetData( iface, format ))) return hr; + + for (iter = object->entries; iter < object->entries_end; iter = next_format( iter )) + { + if (iter->format == format->cfFormat) + { + medium->tymed = TYMED_HGLOBAL; + medium->hGlobal = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, iter->size ); + if (medium->hGlobal == NULL) return E_OUTOFMEMORY; + memcpy( GlobalLock( medium->hGlobal ), iter->data, iter->size ); + GlobalUnlock( medium->hGlobal ); + medium->pUnkForRelease = 0; + return S_OK; + } + } + + return DATA_E_FORMATETC; +} + +static HRESULT WINAPI data_object_GetDataHere( IDataObject *iface, FORMATETC *format, STGMEDIUM *medium ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + FIXME( "object %p, format %p, medium %p stub!\n", object, format, medium ); + return DATA_E_FORMATETC; +} + +static HRESULT WINAPI data_object_QueryGetData( IDataObject *iface, FORMATETC *format ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + struct format_entry *iter; + + TRACE( "object %p, format %p (%s)\n", object, format, debugstr_format(format->cfFormat) ); + + if (format->tymed && !(format->tymed & TYMED_HGLOBAL)) + { + FIXME("only HGLOBAL medium types supported right now\n"); + return DV_E_TYMED; + } + /* Windows Explorer ignores .dwAspect and .lindex for CF_HDROP, + * and we have no way to implement them on XDnD anyway, so ignore them too. + */ + + for (iter = object->entries; iter < object->entries_end; iter = next_format( iter )) + { + if (iter->format == format->cfFormat) + { + TRACE("application found %s\n", debugstr_format(format->cfFormat)); + return S_OK; + } + } + TRACE("application didn't find %s\n", debugstr_format(format->cfFormat)); + return DV_E_FORMATETC; +} + +static HRESULT WINAPI data_object_GetCanonicalFormatEtc( IDataObject *iface, FORMATETC *format, FORMATETC *out ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + FIXME( "object %p, format %p, out %p stub!\n", object, format, out ); + out->ptd = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI data_object_SetData( IDataObject *iface, FORMATETC *format, STGMEDIUM *medium, BOOL release ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + FIXME( "object %p, format %p, medium %p, release %u stub!\n", object, format, medium, release ); + return E_NOTIMPL; +} + +static HRESULT WINAPI data_object_EnumFormatEtc( IDataObject *iface, DWORD direction, IEnumFORMATETC **out ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + + TRACE( "object %p, direction %lu, out %p\n", object, direction, out ); + + if (direction != DATADIR_GET) + { + FIXME("only the get direction is implemented\n"); + return E_NOTIMPL; + } + + return format_iterator_create( iface, out ); +} + +static HRESULT WINAPI data_object_DAdvise( IDataObject *iface, FORMATETC *format, DWORD flags, + IAdviseSink *sink, DWORD *connection ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + FIXME( "object %p, format %p, flags %#lx, sink %p, connection %p stub!\n", + object, format, flags, sink, connection ); + return OLE_E_ADVISENOTSUPPORTED; +} + +static HRESULT WINAPI data_object_DUnadvise( IDataObject *iface, DWORD connection ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + FIXME( "object %p, connection %lu stub!\n", object, connection ); + return OLE_E_ADVISENOTSUPPORTED; +} + +static HRESULT WINAPI data_object_EnumDAdvise( IDataObject *iface, IEnumSTATDATA **advise ) +{ + struct data_object *object = data_object_from_IDataObject( iface ); + FIXME( "object %p, advise %p stub!\n", object, advise ); + return OLE_E_ADVISENOTSUPPORTED; +} + +static IDataObjectVtbl data_object_vtbl = +{ + data_object_QueryInterface, + data_object_AddRef, + data_object_Release, + data_object_GetData, + data_object_GetDataHere, + data_object_QueryGetData, + data_object_GetCanonicalFormatEtc, + data_object_SetData, + data_object_EnumFormatEtc, + data_object_DAdvise, + data_object_DUnadvise, + data_object_EnumDAdvise, +}; + +static HRESULT data_object_create( UINT entries_size, const struct format_entry *entries, IDataObject **out ) +{ + struct data_object *object; + + if (!(object = calloc( 1, sizeof(*object) + entries_size ))) return E_OUTOFMEMORY; + object->IDataObject_iface.lpVtbl = &data_object_vtbl; + object->refcount = 1; + + object->entries_end = (struct format_entry *)((char *)object->entries + entries_size); + memcpy( object->entries, entries, entries_size ); + *out = &object->IDataObject_iface; + + return S_OK; +} + +static struct data_object *get_data_object( BOOL clear ) +{ + IDataObject *iface; + + EnterCriticalSection( &clipboard_cs ); + if ((iface = dnd_data_object)) + { + if (clear) dnd_data_object = NULL; + else IDataObject_AddRef( iface ); + } + LeaveCriticalSection( &clipboard_cs ); + + if (!iface) return NULL; + return data_object_from_IDataObject( iface ); +} + +/* Based on functions in dlls/ole32/ole2.c */ +static HANDLE get_droptarget_local_handle(HWND hwnd) +{ + static const WCHAR prop_marshalleddroptarget[] = + {'W','i','n','e','M','a','r','s','h','a','l','l','e','d','D','r','o','p','T','a','r','g','e','t',0}; + HANDLE handle; + HANDLE local_handle = 0; + + handle = GetPropW(hwnd, prop_marshalleddroptarget); + if (handle) + { + DWORD pid; + HANDLE process; + + GetWindowThreadProcessId(hwnd, &pid); + process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid); + if (process) + { + DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS); + CloseHandle(process); + } + } + return local_handle; +} + +static HRESULT create_stream_from_map(HANDLE map, IStream **stream) +{ + HRESULT hr = E_OUTOFMEMORY; + HGLOBAL hmem; + void *data; + MEMORY_BASIC_INFORMATION info; + + data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); + if(!data) return hr; + + VirtualQuery(data, &info, sizeof(info)); + TRACE("size %d\n", (int)info.RegionSize); + + hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize); + if(hmem) + { + memcpy(GlobalLock(hmem), data, info.RegionSize); + GlobalUnlock(hmem); + hr = CreateStreamOnHGlobal(hmem, TRUE, stream); + } + UnmapViewOfFile(data); + return hr; +} + +static IDropTarget* get_droptarget_pointer(HWND hwnd) +{ + IDropTarget *droptarget = NULL; + HANDLE map; + IStream *stream; + + map = get_droptarget_local_handle(hwnd); + if(!map) return NULL; + + if(SUCCEEDED(create_stream_from_map(map, &stream))) + { + CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget); + IStream_Release(stream); + } + CloseHandle(map); + return droptarget; +} + /* 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 @@ -661,6 +1106,186 @@ static HWND window_accepting_files( HWND hwnd ) return hwnd; }
+BOOL drag_drop_enter( UINT entries_size, const struct format_entry *entries ) +{ + IDataObject *object, *previous; + + TRACE( "entries_size %u, entries %p\n", entries_size, entries ); + + if (FAILED(data_object_create( entries_size, entries, &object ))) return FALSE; + + EnterCriticalSection( &clipboard_cs ); + previous = dnd_data_object; + dnd_data_object = object; + LeaveCriticalSection( &clipboard_cs ); + + if (previous) IDataObject_Release( previous ); + return TRUE; +} + +void drag_drop_leave(void) +{ + struct data_object *object; + + TRACE("DND Operation canceled\n"); + + if ((object = get_data_object( TRUE ))) IDataObject_Release( &object->IDataObject_iface ); +} + +DWORD drag_drop_drag( HWND hwnd, POINT point, DWORD effect ) +{ + int accept = 0; /* Assume we're not accepting */ + POINTL pointl = {.x = point.x, .y = point.y}; + struct data_object *object; + HRESULT hr; + + TRACE( "hwnd %p, point %s, effect %#lx\n", hwnd, wine_dbgstr_point(&point), effect ); + + if (!(object = get_data_object( FALSE ))) return DROPEFFECT_NONE; + object->target_pos = point; + hwnd = window_from_point_dnd( hwnd, object->target_pos ); + + if (!object->drop_target || object->target_hwnd != hwnd) + { + /* Notify OLE of DragEnter. Result determines if we accept */ + HWND dropTargetWindow; + + if (object->drop_target) + { + hr = IDropTarget_DragLeave( object->drop_target ); + if (FAILED(hr)) WARN( "IDropTarget_DragLeave returned %#lx\n", hr ); + IDropTarget_Release( object->drop_target ); + object->drop_target = NULL; + } + + dropTargetWindow = hwnd; + do { object->drop_target = get_droptarget_pointer( dropTargetWindow ); } + while (!object->drop_target && !!(dropTargetWindow = GetParent( dropTargetWindow ))); + object->target_hwnd = hwnd; + + if (object->drop_target) + { + DWORD effect_ignore = effect; + hr = IDropTarget_DragEnter( object->drop_target, &object->IDataObject_iface, + MK_LBUTTON, pointl, &effect_ignore ); + if (hr == S_OK) TRACE( "the application accepted the drop (effect = %ld)\n", effect_ignore ); + else + { + WARN( "IDropTarget_DragEnter returned %#lx\n", hr ); + IDropTarget_Release( object->drop_target ); + object->drop_target = NULL; + } + } + } + else if (object->drop_target) + { + hr = IDropTarget_DragOver( object->drop_target, MK_LBUTTON, pointl, &effect ); + if (hr == S_OK) object->target_effect = effect; + else WARN( "IDropTarget_DragOver returned %#lx\n", hr ); + } + + if (object->drop_target && object->target_effect != DROPEFFECT_NONE) + accept = 1; + else + { + /* fallback search for window able to accept these files. */ + FORMATETC format = {.cfFormat = CF_HDROP}; + + if (window_accepting_files(hwnd) && SUCCEEDED(IDataObject_QueryGetData( &object->IDataObject_iface, &format ))) + { + accept = 1; + effect = DROPEFFECT_COPY; + } + } + + if (!accept) effect = DROPEFFECT_NONE; + IDataObject_Release( &object->IDataObject_iface ); + + return effect; +} + +DWORD drag_drop_drop( HWND hwnd ) +{ + DWORD effect; + int accept = 0; /* Assume we're not accepting */ + struct data_object *object; + BOOL drop_file = TRUE; + + TRACE( "hwnd %p\n", hwnd ); + + if (!(object = get_data_object( TRUE ))) return DROPEFFECT_NONE; + effect = object->target_effect; + + /* Notify OLE of Drop */ + if (object->drop_target && effect != DROPEFFECT_NONE) + { + POINTL pointl = {object->target_pos.x, object->target_pos.y}; + HRESULT hr; + + hr = IDropTarget_Drop( object->drop_target, &object->IDataObject_iface, + MK_LBUTTON, pointl, &effect ); + if (hr == S_OK) + { + if (effect != DROPEFFECT_NONE) + { + TRACE("drop succeeded\n"); + accept = 1; + drop_file = FALSE; + } + else + TRACE("the application refused the drop\n"); + } + else if (FAILED(hr)) + WARN("drop failed, error 0x%08lx\n", hr); + else + { + WARN("drop returned 0x%08lx\n", hr); + drop_file = FALSE; + } + } + else if (object->drop_target) + { + HRESULT hr = IDropTarget_DragLeave( object->drop_target ); + if (FAILED(hr)) WARN( "IDropTarget_DragLeave returned %#lx\n", hr ); + IDropTarget_Release( object->drop_target ); + object->drop_target = NULL; + } + + if (drop_file) + { + /* Only send WM_DROPFILES if Drop didn't succeed or DROPEFFECT_NONE was set. + * Doing both causes winamp to duplicate the dropped files (#29081) */ + HWND hwnd_drop = window_accepting_files(window_from_point_dnd( hwnd, object->target_pos )); + FORMATETC format = {.cfFormat = CF_HDROP}; + STGMEDIUM medium; + + if (hwnd_drop && SUCCEEDED(IDataObject_GetData( &object->IDataObject_iface, &format, &medium ))) + { + DROPFILES *drop = GlobalLock( medium.hGlobal ); + void *files = (char *)drop + drop->pFiles; + RECT rect; + + drop->pt = object->target_pos; + drop->fNC = !ScreenToClient( hwnd, &drop->pt ) || !GetClientRect( hwnd, &rect ) || !PtInRect( &rect, drop->pt ); + TRACE( "Sending WM_DROPFILES: hwnd %p, pt %s, fNC %u, files %p (%s)\n", hwnd, + wine_dbgstr_point( &drop->pt), drop->fNC, files, debugstr_w(files) ); + GlobalUnlock( medium.hGlobal ); + + PostMessageW( hwnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0 ); + accept = 1; + effect = DROPEFFECT_COPY; + } + } + + TRACE("effectRequested(0x%lx) accept(%d) performed(0x%lx) at x(%ld),y(%ld)\n", + object->target_effect, accept, effect, object->target_pos.x, object->target_pos.y); + + if (!accept) effect = DROPEFFECT_NONE; + IDataObject_Release( &object->IDataObject_iface ); + + return effect; +} + void drag_drop_post( HWND hwnd, UINT drop_size, const DROPFILES *drop ) { POINT point = drop->pt; diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index ec307a840f1..ea869485c0a 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -166,6 +166,32 @@ static NTSTATUS WINAPI User32CallDispatchCallback( void *args, ULONG size ) return callback( params, size ); }
+static NTSTATUS WINAPI User32DragDropEnter( void *args, ULONG size ) +{ + if (!drag_drop_enter( size, args )) return STATUS_UNSUCCESSFUL; + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI User32DragDropLeave( void *args, ULONG size ) +{ + drag_drop_leave(); + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI User32DragDropDrag( void *args, ULONG size ) +{ + const struct drag_drop_drag_params *params = args; + UINT effect = drag_drop_drag( params->hwnd, params->point, params->effect ); + return NtCallbackReturn( &effect, sizeof(effect), STATUS_SUCCESS ); +} + +static NTSTATUS WINAPI User32DragDropDrop( void *args, ULONG size ) +{ + const struct drag_drop_drop_params *params = args; + UINT effect = drag_drop_drop( params->hwnd ); + return NtCallbackReturn( &effect, sizeof(effect), STATUS_SUCCESS ); +} + static NTSTATUS WINAPI User32DragDropPost( void *args, ULONG size ) { const struct drag_drop_post_params *params = args; @@ -195,6 +221,10 @@ static KERNEL_CALLBACK_PROC kernel_callback_table[NtUserCallCount] = User32PostDDEMessage, User32RenderSsynthesizedFormat, User32UnpackDDEMessage, + User32DragDropEnter, + User32DragDropLeave, + User32DragDropDrag, + User32DragDropDrop, User32DragDropPost, };
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 90e76fa16af..5d94c411450 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -52,6 +52,10 @@ extern BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM const void *buffer, size_t size ); extern void free_cached_data( UINT format, HANDLE handle ); extern HANDLE render_synthesized_format( UINT format, UINT from ); +extern BOOL drag_drop_enter( UINT entries_size, const struct format_entry *entries ); +extern void drag_drop_leave(void); +extern DWORD drag_drop_drag( HWND hwnd, POINT point, DWORD effect ); +extern DWORD drag_drop_drop( HWND hwnd ); extern void drag_drop_post( HWND hwnd, UINT drop_size, const DROPFILES *drop ); extern void unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, void *buffer, BOOL ansi ); diff --git a/dlls/win32u/clipboard.c b/dlls/win32u/clipboard.c index f9fbbcd9030..c1d8330b51f 100644 --- a/dlls/win32u/clipboard.c +++ b/dlls/win32u/clipboard.c @@ -764,6 +764,32 @@ LRESULT drag_drop_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void
switch (msg) { + case WINE_DRAG_DROP_ENTER: + return KeUserModeCallback( NtUserDragDropEnter, (struct format_entry *)lparam, wparam, &ret_ptr, &ret_len ); + case WINE_DRAG_DROP_LEAVE: + return KeUserModeCallback( NtUserDragDropLeave, 0, 0, &ret_ptr, &ret_len ); + case WINE_DRAG_DROP_DRAG: + { + struct drag_drop_drag_params params = + { + .hwnd = hwnd, + .point.x = LOWORD(wparam), + .point.y = HIWORD(wparam), + .effect = lparam, + }; + + if (KeUserModeCallback( NtUserDragDropDrag, ¶ms, sizeof(params), &ret_ptr, &ret_len ) || ret_len != sizeof(DWORD)) + return DROPEFFECT_NONE; + return *(DWORD *)ret_ptr; + } + case WINE_DRAG_DROP_DROP: + { + struct drag_drop_drop_params params = {.hwnd = hwnd}; + if (KeUserModeCallback( NtUserDragDropDrop, ¶ms, sizeof(params), &ret_ptr, &ret_len ) || ret_len != sizeof(DWORD)) + return DROPEFFECT_NONE; + return *(DWORD *)ret_ptr; + } + case WINE_DRAG_DROP_POST: { struct drag_drop_post_params *params; diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index 7b7282574d0..5e351b45dff 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -1,7 +1,6 @@ MODULE = winex11.drv UNIXLIB = winex11.so IMPORTS = uuid user32 gdi32 win32u -DELAYIMPORTS = combase UNIX_CFLAGS = $(X_CFLAGS) UNIX_LIBS = -lwin32u $(X_LIBS) $(PTHREAD_LIBS) -lm
@@ -26,7 +25,6 @@ SOURCES = \ window.c \ wintab.c \ x11drv_main.c \ - xdnd.c \ xim.c \ xinerama.c \ xrandr.c \ diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index 08ef36bdcde..a83718f3cc2 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -29,10 +29,6 @@ BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) { struct init_params params = { - .dnd_enter_event_callback = (UINT_PTR)x11drv_dnd_enter_event, - .dnd_position_event_callback = (UINT_PTR)x11drv_dnd_position_event, - .dnd_drop_event_callback = (UINT_PTR)x11drv_dnd_drop_event, - .dnd_leave_event_callback = (UINT_PTR)x11drv_dnd_leave_event, .foreign_window_proc = (UINT_PTR)foreign_window_proc, };
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index abc9a3d420c..19cbbae14c3 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1400,6 +1400,30 @@ void X11DRV_SetFocus( HWND hwnd ) release_win_data( data ); }
+static void drag_drop_enter( UINT entries_size, struct format_entry *entries ) +{ + NtUserMessageCall( 0, WINE_DRAG_DROP_ENTER, entries_size, (LPARAM)entries, NULL, + NtUserDragDropCall, FALSE ); +} + +static void drag_drop_leave(void) +{ + NtUserMessageCall( 0, WINE_DRAG_DROP_LEAVE, 0, 0, NULL, + NtUserDragDropCall, FALSE ); +} + +static DWORD drag_drop_drag( HWND hwnd, POINT point, DWORD effect ) +{ + return NtUserMessageCall( hwnd, WINE_DRAG_DROP_DRAG, MAKELONG(point.x, point.y), effect, NULL, + NtUserDragDropCall, FALSE ); +} + +static DWORD drag_drop_drop( HWND hwnd ) +{ + return NtUserMessageCall( hwnd, WINE_DRAG_DROP_DROP, 0, 0, NULL, + NtUserDragDropCall, FALSE ); +} + static void drag_drop_post( HWND hwnd, DROPFILES *drop, ULONG size ) { NtUserMessageCall( hwnd, WINE_DRAG_DROP_POST, size, (LPARAM)drop, NULL, @@ -1534,7 +1558,6 @@ static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) */ static void handle_xdnd_enter_event( HWND hWnd, XClientMessageEvent *event ) { - struct dnd_enter_event_params *params; struct format_entry *data; unsigned long count = 0; Atom *xdndtypes; @@ -1590,15 +1613,7 @@ static void handle_xdnd_enter_event( HWND hWnd, XClientMessageEvent *event )
data = import_xdnd_selection( event->display, event->window, x11drv_atom(XdndSelection), xdndtypes, count, &size ); - if (data && (params = malloc( sizeof(*params) + size ))) - { - void *ret_ptr; - ULONG ret_len; - memcpy( params->entries, data, size ); - params->dispatch.callback = dnd_enter_event_callback; - KeUserDispatchCallback( ¶ms->dispatch, sizeof(*params) + size, &ret_ptr, &ret_len ); - free( params ); - } + if (data) drag_drop_enter( size, data ); free( data );
if (event->data.l[1] & 1) @@ -1644,23 +1659,16 @@ static long drop_effect_to_xdnd_action( UINT effect )
static void handle_xdnd_position_event( HWND hwnd, XClientMessageEvent *event ) { - struct dnd_position_event_params params; XClientMessageEvent e; - void *ret_ptr; - ULONG ret_len; + POINT point; UINT effect;
- params.dispatch.callback = dnd_position_event_callback; - params.hwnd = HandleToUlong( 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] ); - - if (KeUserDispatchCallback( ¶ms.dispatch, sizeof(params), &ret_ptr, &ret_len ) || ret_len != sizeof(effect)) - return; - effect = *(UINT *)ret_ptr; + point = root_to_virtual_screen( event->data.l[2] >> 16, event->data.l[2] & 0xFFFF ); + effect = xdnd_action_to_drop_effect( event->data.l[4] ); + effect = drag_drop_drag( hwnd, point, effect );
TRACE( "actionRequested(%ld) chosen(0x%x) at x(%d),y(%d)\n", - event->data.l[4], effect, (int)params.point.x, (int)params.point.y ); + event->data.l[4], effect, (int)point.x, (int)point.y );
/* * Let source know if we're accepting the drop by @@ -1682,15 +1690,10 @@ static void handle_xdnd_position_event( HWND hwnd, XClientMessageEvent *event )
static void handle_xdnd_drop_event( HWND hwnd, XClientMessageEvent *event ) { - struct dnd_drop_event_params params = {.dispatch.callback = dnd_drop_event_callback, .hwnd = HandleToULong(hwnd)}; XClientMessageEvent e; - void *ret_ptr; - ULONG ret_len; UINT effect;
- if (KeUserDispatchCallback( ¶ms.dispatch, sizeof(params), &ret_ptr, &ret_len ) || ret_len != sizeof(effect)) - return; - effect = *(UINT *)ret_ptr; + effect = drag_drop_drop( hwnd );
/* Tell the target we are finished. */ memset( &e, 0, sizeof(e) ); @@ -1708,10 +1711,7 @@ static void handle_xdnd_drop_event( HWND hwnd, XClientMessageEvent *event )
static void handle_xdnd_leave_event( HWND hwnd, XClientMessageEvent *event ) { - struct dispatch_callback_params params = {.callback = dnd_leave_event_callback}; - void *ret_ptr; - ULONG ret_len; - KeUserDispatchCallback( ¶ms, sizeof(params), &ret_ptr, &ret_len ); + drag_drop_leave(); }
diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index 170cd4f80fc..09f45575438 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -35,11 +35,6 @@ enum x11drv_funcs /* x11drv_init params */ struct init_params { - UINT64 dnd_enter_event_callback; - UINT64 dnd_position_event_callback; - UINT64 dnd_post_drop_callback; - UINT64 dnd_drop_event_callback; - UINT64 dnd_leave_event_callback; UINT64 foreign_window_proc; };
@@ -50,42 +45,3 @@ struct tablet_info_params UINT index; void *output; }; - -/* x11drv_xim_preedit_state params */ -struct xim_preedit_state_params -{ - HWND hwnd; - BOOL open; -}; - -struct format_entry -{ - UINT format; - UINT size; - char data[1]; -}; - -/* x11drv_dnd_enter_event params */ -struct dnd_enter_event_params -{ - struct dispatch_callback_params dispatch; - struct format_entry entries[]; -}; - -C_ASSERT(sizeof(struct dnd_enter_event_params) == offsetof(struct dnd_enter_event_params, entries[0])); - -/* x11drv_dnd_position_event params */ -struct dnd_position_event_params -{ - struct dispatch_callback_params dispatch; - ULONG hwnd; - POINT point; - DWORD effect; -}; - -/* x11drv_dnd_drop_event params */ -struct dnd_drop_event_params -{ - struct dispatch_callback_params dispatch; - ULONG hwnd; -}; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 7fb1d601690..77a2cb1a963 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -434,10 +434,6 @@ extern int xrender_error_base; extern char *process_name; extern Display *clipboard_display; extern UINT64 client_foreign_window_proc; -extern UINT64 dnd_enter_event_callback; -extern UINT64 dnd_position_event_callback; -extern UINT64 dnd_drop_event_callback; -extern UINT64 dnd_leave_event_callback;
/* atoms */
diff --git a/dlls/winex11.drv/x11drv_dll.h b/dlls/winex11.drv/x11drv_dll.h index 3ed9fea6a5a..064599948f0 100644 --- a/dlls/winex11.drv/x11drv_dll.h +++ b/dlls/winex11.drv/x11drv_dll.h @@ -27,11 +27,6 @@ #include "ntgdi.h" #include "unixlib.h"
-extern NTSTATUS WINAPI x11drv_dnd_enter_event( void *params, ULONG size ); -extern NTSTATUS WINAPI x11drv_dnd_position_event( void *params, ULONG size ); -extern NTSTATUS WINAPI x11drv_dnd_drop_event( void *params, ULONG size ); -extern NTSTATUS WINAPI x11drv_dnd_leave_event( void *params, ULONG size ); - extern LRESULT WINAPI foreign_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam );
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 77169bf287f..7e5073733b4 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -86,10 +86,6 @@ int alloc_system_colors = 256; int xrender_error_base = 0; char *process_name = NULL; UINT64 client_foreign_window_proc = 0; -UINT64 dnd_enter_event_callback = 0; -UINT64 dnd_position_event_callback = 0; -UINT64 dnd_drop_event_callback = 0; -UINT64 dnd_leave_event_callback = 0;
static x11drv_error_callback err_callback; /* current callback for error */ static Display *err_callback_display; /* display callback is set for */ @@ -647,10 +643,6 @@ static NTSTATUS x11drv_init( void *arg ) if (!XInitThreads()) ERR( "XInitThreads failed, trouble ahead\n" ); if (!(display = XOpenDisplay( NULL ))) return STATUS_UNSUCCESSFUL;
- dnd_enter_event_callback = params->dnd_enter_event_callback; - dnd_position_event_callback = params->dnd_position_event_callback; - dnd_drop_event_callback = params->dnd_drop_event_callback; - dnd_leave_event_callback = params->dnd_leave_event_callback; client_foreign_window_proc = params->foreign_window_proc;
fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */ diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c deleted file mode 100644 index d9f8380b95e..00000000000 --- a/dlls/winex11.drv/xdnd.c +++ /dev/null @@ -1,746 +0,0 @@ -/* - * XDND handler code - * - * Copyright 2003 Ulrich Czekalla - * Copyright 2007 Damjan Jovanovic - * - * 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 - */ - -#define COBJMACROS -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "x11drv_dll.h" -#include "shellapi.h" -#include "shlobj.h" - -#include "wine/debug.h" -#include "wine/list.h" - -WINE_DEFAULT_DEBUG_CHANNEL(xdnd); - -static IDataObject *xdnd_data_object; - -static CRITICAL_SECTION xdnd_cs; -static CRITICAL_SECTION_DEBUG critsect_debug = -{ - 0, 0, &xdnd_cs, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": xdnd_cs") } -}; -static CRITICAL_SECTION xdnd_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; - - -static struct format_entry *next_format( struct format_entry *entry ) -{ - return (struct format_entry *)&entry->data[(entry->size + 7) & ~7]; -} - -static const char *debugstr_format( int format ) -{ - WCHAR buffer[256]; - switch (format) - { -#define X(x) case x: return #x; - X(CF_TEXT) - X(CF_BITMAP) - X(CF_METAFILEPICT) - X(CF_SYLK) - X(CF_DIF) - X(CF_TIFF) - X(CF_OEMTEXT) - X(CF_DIB) - X(CF_PALETTE) - X(CF_PENDATA) - X(CF_RIFF) - X(CF_WAVE) - X(CF_UNICODETEXT) - X(CF_ENHMETAFILE) - X(CF_HDROP) - X(CF_LOCALE) - X(CF_DIBV5) -#undef X - } - - if (CF_PRIVATEFIRST <= format && format <= CF_PRIVATELAST) return "some private object"; - if (CF_GDIOBJFIRST <= format && format <= CF_GDIOBJLAST) return "some GDI object"; - GetClipboardFormatNameW( format, buffer, sizeof(buffer) ); - return debugstr_w( buffer ); -} - -struct data_object -{ - IDataObject IDataObject_iface; - LONG refcount; - - HWND target_hwnd; /* the last window the mouse was over */ - POINT target_pos; - DWORD target_effect; - IDropTarget *drop_target; - - struct format_entry *entries_end; - struct format_entry entries[]; -}; - -static struct data_object *data_object_from_IDataObject( IDataObject *iface ) -{ - return CONTAINING_RECORD( iface, struct data_object, IDataObject_iface ); -} - -struct format_iterator -{ - IEnumFORMATETC IEnumFORMATETC_iface; - LONG refcount; - - struct format_entry *entry; - IDataObject *object; -}; - -static inline struct format_iterator *format_iterator_from_IEnumFORMATETC( IEnumFORMATETC *iface ) -{ - return CONTAINING_RECORD(iface, struct format_iterator, IEnumFORMATETC_iface); -} - -static HRESULT WINAPI format_iterator_QueryInterface( IEnumFORMATETC *iface, REFIID iid, void **obj ) -{ - struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); - - TRACE( "iterator %p, iid %s, obj %p\n", iterator, debugstr_guid(iid), obj ); - - if (IsEqualIID( iid, &IID_IUnknown ) || IsEqualIID( iid, &IID_IEnumFORMATETC )) - { - IEnumFORMATETC_AddRef( &iterator->IEnumFORMATETC_iface ); - *obj = &iterator->IEnumFORMATETC_iface; - return S_OK; - } - - *obj = NULL; - WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid) ); - return E_NOINTERFACE; -} - -static ULONG WINAPI format_iterator_AddRef( IEnumFORMATETC *iface ) -{ - struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); - ULONG ref = InterlockedIncrement( &iterator->refcount ); - TRACE( "iterator %p increasing refcount to %lu.\n", iterator, ref ); - return ref; -} - -static ULONG WINAPI format_iterator_Release(IEnumFORMATETC *iface) -{ - struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); - ULONG ref = InterlockedDecrement( &iterator->refcount ); - - TRACE( "iterator %p increasing refcount to %lu.\n", iterator, ref ); - - if (!ref) - { - IDataObject_Release( iterator->object ); - free( iterator ); - } - - return ref; -} - -static HRESULT WINAPI format_iterator_Next( IEnumFORMATETC *iface, ULONG count, FORMATETC *formats, ULONG *ret ) -{ - struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); - struct data_object *object = data_object_from_IDataObject( iterator->object ); - struct format_entry *entry; - UINT i; - - TRACE( "iterator %p, count %lu, formats %p, ret %p\n", iterator, count, formats, ret ); - - for (entry = iterator->entry, i = 0; entry < object->entries_end && i < count; entry = next_format( entry ), i++) - { - formats[i].cfFormat = entry->format; - formats[i].ptd = NULL; - formats[i].dwAspect = DVASPECT_CONTENT; - formats[i].lindex = -1; - formats[i].tymed = TYMED_HGLOBAL; - } - - iterator->entry = entry; - if (ret) *ret = i; - return (i == count) ? S_OK : S_FALSE; -} - -static HRESULT WINAPI format_iterator_Skip( IEnumFORMATETC *iface, ULONG count ) -{ - struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); - struct data_object *object = data_object_from_IDataObject( iterator->object ); - struct format_entry *entry; - - TRACE( "iterator %p, count %lu\n", iterator, count ); - - for (entry = iterator->entry; entry < object->entries_end; entry = next_format( entry )) - if (!count--) break; - - iterator->entry = entry; - return count ? S_FALSE : S_OK; -} - -static HRESULT WINAPI format_iterator_Reset( IEnumFORMATETC *iface ) -{ - struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); - struct data_object *object = data_object_from_IDataObject( iterator->object ); - - TRACE( "iterator %p\n", iterator ); - iterator->entry = object->entries; - return S_OK; -} - -static HRESULT format_iterator_create( IDataObject *object, IEnumFORMATETC **out ); - -static HRESULT WINAPI format_iterator_Clone( IEnumFORMATETC *iface, IEnumFORMATETC **out ) -{ - struct format_iterator *iterator = format_iterator_from_IEnumFORMATETC( iface ); - TRACE( "iterator %p, out %p\n", iterator, out ); - return format_iterator_create( iterator->object, out ); -} - -static const IEnumFORMATETCVtbl format_iterator_vtbl = -{ - format_iterator_QueryInterface, - format_iterator_AddRef, - format_iterator_Release, - format_iterator_Next, - format_iterator_Skip, - format_iterator_Reset, - format_iterator_Clone, -}; - -static HRESULT format_iterator_create( IDataObject *object, IEnumFORMATETC **out ) -{ - struct format_iterator *iterator; - - if (!(iterator = calloc( 1, sizeof(*iterator) ))) return E_OUTOFMEMORY; - iterator->IEnumFORMATETC_iface.lpVtbl = &format_iterator_vtbl; - iterator->refcount = 1; - IDataObject_AddRef( (iterator->object = object) ); - iterator->entry = data_object_from_IDataObject(object)->entries; - - *out = &iterator->IEnumFORMATETC_iface; - TRACE( "created object %p iterator %p\n", object, iterator ); - return S_OK; -} - -static HRESULT WINAPI data_object_QueryInterface( IDataObject *iface, REFIID iid, void **obj ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - - TRACE( "object %p, iid %s, obj %p\n", object, debugstr_guid(iid), obj ); - - if (IsEqualIID( iid, &IID_IUnknown ) || IsEqualIID( iid, &IID_IDataObject )) - { - IDataObject_AddRef( &object->IDataObject_iface ); - *obj = &object->IDataObject_iface; - return S_OK; - } - - *obj = NULL; - WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid) ); - return E_NOINTERFACE; -} - -static ULONG WINAPI data_object_AddRef( IDataObject *iface ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - ULONG ref = InterlockedIncrement( &object->refcount ); - TRACE( "object %p increasing refcount to %lu.\n", object, ref ); - return ref; -} - -static ULONG WINAPI data_object_Release( IDataObject *iface ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - ULONG ref = InterlockedDecrement( &object->refcount ); - - TRACE( "object %p decreasing refcount to %lu.\n", object, ref ); - - if (!ref) - { - if (object->drop_target) - { - HRESULT hr = IDropTarget_DragLeave( object->drop_target ); - if (FAILED(hr)) WARN( "IDropTarget_DragLeave returned %#lx\n", hr ); - IDropTarget_Release( object->drop_target ); - } - - free( object ); - } - - return ref; -} - -static HRESULT WINAPI data_object_GetData( IDataObject *iface, FORMATETC *format, STGMEDIUM *medium ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - struct format_entry *iter; - HRESULT hr; - - TRACE( "object %p, format %p (%s), medium %p\n", object, format, debugstr_format(format->cfFormat), medium ); - - if (FAILED(hr = IDataObject_QueryGetData( iface, format ))) return hr; - - for (iter = object->entries; iter < object->entries_end; iter = next_format( iter )) - { - if (iter->format == format->cfFormat) - { - medium->tymed = TYMED_HGLOBAL; - medium->hGlobal = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, iter->size ); - if (medium->hGlobal == NULL) return E_OUTOFMEMORY; - memcpy( GlobalLock( medium->hGlobal ), iter->data, iter->size ); - GlobalUnlock( medium->hGlobal ); - medium->pUnkForRelease = 0; - return S_OK; - } - } - - return DATA_E_FORMATETC; -} - -static HRESULT WINAPI data_object_GetDataHere( IDataObject *iface, FORMATETC *format, STGMEDIUM *medium ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - FIXME( "object %p, format %p, medium %p stub!\n", object, format, medium ); - return DATA_E_FORMATETC; -} - -static HRESULT WINAPI data_object_QueryGetData( IDataObject *iface, FORMATETC *format ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - struct format_entry *iter; - - TRACE( "object %p, format %p (%s)\n", object, format, debugstr_format(format->cfFormat) ); - - if (format->tymed && !(format->tymed & TYMED_HGLOBAL)) - { - FIXME("only HGLOBAL medium types supported right now\n"); - return DV_E_TYMED; - } - /* Windows Explorer ignores .dwAspect and .lindex for CF_HDROP, - * and we have no way to implement them on XDnD anyway, so ignore them too. - */ - - for (iter = object->entries; iter < object->entries_end; iter = next_format( iter )) - { - if (iter->format == format->cfFormat) - { - TRACE("application found %s\n", debugstr_format(format->cfFormat)); - return S_OK; - } - } - TRACE("application didn't find %s\n", debugstr_format(format->cfFormat)); - return DV_E_FORMATETC; -} - -static HRESULT WINAPI data_object_GetCanonicalFormatEtc( IDataObject *iface, FORMATETC *format, FORMATETC *out ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - FIXME( "object %p, format %p, out %p stub!\n", object, format, out ); - out->ptd = NULL; - return E_NOTIMPL; -} - -static HRESULT WINAPI data_object_SetData( IDataObject *iface, FORMATETC *format, STGMEDIUM *medium, BOOL release ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - FIXME( "object %p, format %p, medium %p, release %u stub!\n", object, format, medium, release ); - return E_NOTIMPL; -} - -static HRESULT WINAPI data_object_EnumFormatEtc( IDataObject *iface, DWORD direction, IEnumFORMATETC **out ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - - TRACE( "object %p, direction %lu, out %p\n", object, direction, out ); - - if (direction != DATADIR_GET) - { - FIXME("only the get direction is implemented\n"); - return E_NOTIMPL; - } - - return format_iterator_create( iface, out ); -} - -static HRESULT WINAPI data_object_DAdvise( IDataObject *iface, FORMATETC *format, DWORD flags, - IAdviseSink *sink, DWORD *connection ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - FIXME( "object %p, format %p, flags %#lx, sink %p, connection %p stub!\n", - object, format, flags, sink, connection ); - return OLE_E_ADVISENOTSUPPORTED; -} - -static HRESULT WINAPI data_object_DUnadvise( IDataObject *iface, DWORD connection ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - FIXME( "object %p, connection %lu stub!\n", object, connection ); - return OLE_E_ADVISENOTSUPPORTED; -} - -static HRESULT WINAPI data_object_EnumDAdvise( IDataObject *iface, IEnumSTATDATA **advise ) -{ - struct data_object *object = data_object_from_IDataObject( iface ); - FIXME( "object %p, advise %p stub!\n", object, advise ); - return OLE_E_ADVISENOTSUPPORTED; -} - -static IDataObjectVtbl data_object_vtbl = -{ - data_object_QueryInterface, - data_object_AddRef, - data_object_Release, - data_object_GetData, - data_object_GetDataHere, - data_object_QueryGetData, - data_object_GetCanonicalFormatEtc, - data_object_SetData, - data_object_EnumFormatEtc, - data_object_DAdvise, - data_object_DUnadvise, - data_object_EnumDAdvise, -}; - -static HRESULT data_object_create( UINT entries_size, const struct format_entry *entries, IDataObject **out ) -{ - struct data_object *object; - - if (!(object = calloc( 1, sizeof(*object) + entries_size ))) return E_OUTOFMEMORY; - object->IDataObject_iface.lpVtbl = &data_object_vtbl; - object->refcount = 1; - - object->entries_end = (struct format_entry *)((char *)object->entries + entries_size); - memcpy( object->entries, entries, entries_size ); - *out = &object->IDataObject_iface; - - return S_OK; -} - -static struct data_object *get_data_object( BOOL clear ) -{ - IDataObject *iface; - - EnterCriticalSection( &xdnd_cs ); - if ((iface = xdnd_data_object)) - { - if (clear) xdnd_data_object = NULL; - else IDataObject_AddRef( iface ); - } - LeaveCriticalSection( &xdnd_cs ); - - if (!iface) return NULL; - return data_object_from_IDataObject( iface ); -} - -/* Based on functions in dlls/ole32/ole2.c */ -static HANDLE get_droptarget_local_handle(HWND hwnd) -{ - static const WCHAR prop_marshalleddroptarget[] = - {'W','i','n','e','M','a','r','s','h','a','l','l','e','d','D','r','o','p','T','a','r','g','e','t',0}; - HANDLE handle; - HANDLE local_handle = 0; - - handle = GetPropW(hwnd, prop_marshalleddroptarget); - if (handle) - { - DWORD pid; - HANDLE process; - - GetWindowThreadProcessId(hwnd, &pid); - process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid); - if (process) - { - DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS); - CloseHandle(process); - } - } - return local_handle; -} - -static HRESULT create_stream_from_map(HANDLE map, IStream **stream) -{ - HRESULT hr = E_OUTOFMEMORY; - HGLOBAL hmem; - void *data; - MEMORY_BASIC_INFORMATION info; - - data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); - if(!data) return hr; - - VirtualQuery(data, &info, sizeof(info)); - TRACE("size %d\n", (int)info.RegionSize); - - hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize); - if(hmem) - { - memcpy(GlobalLock(hmem), data, info.RegionSize); - GlobalUnlock(hmem); - hr = CreateStreamOnHGlobal(hmem, TRUE, stream); - } - UnmapViewOfFile(data); - return hr; -} - -static IDropTarget* get_droptarget_pointer(HWND hwnd) -{ - IDropTarget *droptarget = NULL; - HANDLE map; - IStream *stream; - - map = get_droptarget_local_handle(hwnd); - if(!map) return NULL; - - if(SUCCEEDED(create_stream_from_map(map, &stream))) - { - CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget); - IStream_Release(stream); - } - CloseHandle(map); - return droptarget; -} - - -/* 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)) - /* MUST to be GetParent, not GetAncestor, because the owner window - * (with WS_EX_ACCEPTFILES) of a window with WS_POPUP is a valid - * drop target. GetParent works exactly this way! - */ - hwnd = GetParent(hwnd); - return hwnd; -} - -/************************************************************************** - * x11drv_dnd_position_event - * - * Handle an XdndPosition event. - */ -NTSTATUS WINAPI x11drv_dnd_position_event( void *arg, ULONG size ) -{ - struct dnd_position_event_params *params = arg; - int accept = 0; /* Assume we're not accepting */ - DWORD effect = params->effect; - POINTL pointl = { .x = params->point.x, .y = params->point.y }; - struct data_object *object; - HWND targetWindow; - HRESULT hr; - - if (!(object = get_data_object( FALSE ))) return STATUS_INVALID_PARAMETER; - - object->target_pos = params->point; - targetWindow = window_from_point_dnd( UlongToHandle( params->hwnd ), object->target_pos ); - - if (!object->drop_target || object->target_hwnd != targetWindow) - { - /* Notify OLE of DragEnter. Result determines if we accept */ - HWND dropTargetWindow; - - if (object->drop_target) - { - hr = IDropTarget_DragLeave( object->drop_target ); - if (FAILED(hr)) WARN( "IDropTarget_DragLeave returned %#lx\n", hr ); - IDropTarget_Release( object->drop_target ); - object->drop_target = NULL; - } - - dropTargetWindow = targetWindow; - do { object->drop_target = get_droptarget_pointer( dropTargetWindow ); } - while (!object->drop_target && !!(dropTargetWindow = GetParent( dropTargetWindow ))); - object->target_hwnd = targetWindow; - - if (object->drop_target) - { - DWORD effect_ignore = effect; - hr = IDropTarget_DragEnter( object->drop_target, &object->IDataObject_iface, - MK_LBUTTON, pointl, &effect_ignore ); - if (hr == S_OK) TRACE( "the application accepted the drop (effect = %ld)\n", effect_ignore ); - else - { - WARN( "IDropTarget_DragEnter returned %#lx\n", hr ); - IDropTarget_Release( object->drop_target ); - object->drop_target = NULL; - } - } - } - else if (object->drop_target) - { - hr = IDropTarget_DragOver( object->drop_target, MK_LBUTTON, pointl, &effect ); - if (hr == S_OK) object->target_effect = effect; - else WARN( "IDropTarget_DragOver returned %#lx\n", hr ); - } - - if (object->drop_target && object->target_effect != DROPEFFECT_NONE) - accept = 1; - else - { - /* fallback search for window able to accept these files. */ - FORMATETC format = {.cfFormat = CF_HDROP}; - - if (window_accepting_files(targetWindow) && SUCCEEDED(IDataObject_QueryGetData( &object->IDataObject_iface, &format ))) - { - accept = 1; - effect = DROPEFFECT_COPY; - } - } - - if (!accept) effect = DROPEFFECT_NONE; - IDataObject_Release( &object->IDataObject_iface ); - - return NtCallbackReturn( &effect, sizeof(effect), STATUS_SUCCESS ); -} - -NTSTATUS WINAPI x11drv_dnd_drop_event( void *args, ULONG size ) -{ - struct dnd_drop_event_params *params = args; - HWND hwnd = UlongToHandle( params->hwnd ); - DWORD effect; - int accept = 0; /* Assume we're not accepting */ - struct data_object *object; - BOOL drop_file = TRUE; - - if (!(object = get_data_object( TRUE ))) return STATUS_INVALID_PARAMETER; - effect = object->target_effect; - - /* Notify OLE of Drop */ - if (object->drop_target && effect != DROPEFFECT_NONE) - { - POINTL pointl = {object->target_pos.x, object->target_pos.y}; - HRESULT hr; - - hr = IDropTarget_Drop( object->drop_target, &object->IDataObject_iface, - MK_LBUTTON, pointl, &effect ); - if (hr == S_OK) - { - if (effect != DROPEFFECT_NONE) - { - TRACE("drop succeeded\n"); - accept = 1; - drop_file = FALSE; - } - else - TRACE("the application refused the drop\n"); - } - else if (FAILED(hr)) - WARN("drop failed, error 0x%08lx\n", hr); - else - { - WARN("drop returned 0x%08lx\n", hr); - drop_file = FALSE; - } - } - else if (object->drop_target) - { - HRESULT hr = IDropTarget_DragLeave( object->drop_target ); - if (FAILED(hr)) WARN( "IDropTarget_DragLeave returned %#lx\n", hr ); - IDropTarget_Release( object->drop_target ); - object->drop_target = NULL; - } - - if (drop_file) - { - /* Only send WM_DROPFILES if Drop didn't succeed or DROPEFFECT_NONE was set. - * Doing both causes winamp to duplicate the dropped files (#29081) */ - HWND hwnd_drop = window_accepting_files(window_from_point_dnd( hwnd, object->target_pos )); - FORMATETC format = {.cfFormat = CF_HDROP}; - STGMEDIUM medium; - - if (hwnd_drop && SUCCEEDED(IDataObject_GetData( &object->IDataObject_iface, &format, &medium ))) - { - DROPFILES *drop = GlobalLock( medium.hGlobal ); - void *files = (char *)drop + drop->pFiles; - RECT rect; - - drop->pt = object->target_pos; - drop->fNC = !ScreenToClient( hwnd, &drop->pt ) || !GetClientRect( hwnd, &rect ) || !PtInRect( &rect, drop->pt ); - TRACE( "Sending WM_DROPFILES: hwnd %p, pt %s, fNC %u, files %p (%s)\n", hwnd, - wine_dbgstr_point( &drop->pt), drop->fNC, files, debugstr_w(files) ); - GlobalUnlock( medium.hGlobal ); - - PostMessageW( hwnd, WM_DROPFILES, (WPARAM)medium.hGlobal, 0 ); - accept = 1; - effect = DROPEFFECT_COPY; - } - } - - TRACE("effectRequested(0x%lx) accept(%d) performed(0x%lx) at x(%ld),y(%ld)\n", - object->target_effect, accept, effect, object->target_pos.x, object->target_pos.y); - - if (!accept) effect = DROPEFFECT_NONE; - IDataObject_Release( &object->IDataObject_iface ); - - return NtCallbackReturn( &effect, sizeof(effect), STATUS_SUCCESS ); -} - -/************************************************************************** - * x11drv_dnd_leave_event - * - * Handle an XdndLeave event. - */ -NTSTATUS WINAPI x11drv_dnd_leave_event( void *params, ULONG size ) -{ - struct data_object *object; - - TRACE("DND Operation canceled\n"); - - if ((object = get_data_object( TRUE ))) IDataObject_Release( &object->IDataObject_iface ); - return STATUS_SUCCESS; -} - - -/************************************************************************** - * x11drv_dnd_enter_event - */ -NTSTATUS WINAPI x11drv_dnd_enter_event( void *args, ULONG size ) -{ - UINT formats_size = size - offsetof(struct dnd_enter_event_params, entries); - struct dnd_enter_event_params *params = args; - IDataObject *object, *previous; - - if (FAILED(data_object_create( formats_size, params->entries, &object ))) return STATUS_NO_MEMORY; - - EnterCriticalSection( &xdnd_cs ); - previous = xdnd_data_object; - xdnd_data_object = object; - LeaveCriticalSection( &xdnd_cs ); - - if (previous) IDataObject_Release( previous ); - return STATUS_SUCCESS; -} diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index f7e311990bc..3685ed73bd0 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -1451,6 +1451,42 @@ static NTSTATUS WINAPI wow64_NtUserCallDispatchCallback( void *arg, ULONG size ) return dispatch_callback( NtUserCallDispatchCallback, arg, size ); }
+static NTSTATUS WINAPI wow64_NtUserDragDropEnter( void *arg, ULONG size ) +{ + return dispatch_callback( NtUserDragDropEnter, arg, size ); +} + +static NTSTATUS WINAPI wow64_NtUserDragDropLeave( void *arg, ULONG size ) +{ + return dispatch_callback( NtUserDragDropLeave, arg, size ); +} + +static NTSTATUS WINAPI wow64_NtUserDragDropDrag( void *arg, ULONG size ) +{ + const struct drag_drop_drag_params *params = arg; + struct + { + ULONG hwnd; + POINT point; + UINT effect; + } params32; + params32.hwnd = HandleToUlong( params->hwnd ); + params32.point = params->point; + params32.effect = params->effect; + return dispatch_callback( NtUserDragDropDrag, ¶ms32, sizeof(params32) ); +} + +static NTSTATUS WINAPI wow64_NtUserDragDropDrop( void *arg, ULONG size ) +{ + const struct drag_drop_drop_params *params = arg; + struct + { + ULONG hwnd; + } params32; + params32.hwnd = HandleToUlong( params->hwnd ); + return dispatch_callback( NtUserDragDropDrop, ¶ms32, sizeof(params32) ); +} + static NTSTATUS WINAPI wow64_NtUserDragDropPost( void *arg, ULONG size ) { struct drag_drop_post_params32 @@ -1494,6 +1530,10 @@ ntuser_callback user_callbacks[] = wow64_NtUserPostDDEMessage, wow64_NtUserRenderSynthesizedFormat, wow64_NtUserUnpackDDEMessage, + wow64_NtUserDragDropEnter, + wow64_NtUserDragDropLeave, + wow64_NtUserDragDropDrag, + wow64_NtUserDragDropDrop, wow64_NtUserDragDropPost, };
@@ -3643,6 +3683,16 @@ NTSTATUS WINAPI wow64_NtUserMessageCall( UINT *args ) }
case NtUserDragDropCall: + if (msg == WINE_DRAG_DROP_ENTER) + { + ULONG *data32 = result_info; + NTSTATUS status; + void *data; + + status = NtUserMessageCall( hwnd, msg, wparam, lparam, &data, type, ansi ); + if (!status) *data32 = HandleToUlong( data ); + return status; + } return NtUserMessageCall( hwnd, msg, wparam, lparam, result_info, type, ansi ); }
diff --git a/include/ntuser.h b/include/ntuser.h index 6282f995ead..a82dead4ef4 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -73,6 +73,10 @@ enum NtUserPostDDEMessage, NtUserRenderSynthesizedFormat, NtUserUnpackDDEMessage, + NtUserDragDropEnter, + NtUserDragDropLeave, + NtUserDragDropDrag, + NtUserDragDropDrop, NtUserDragDropPost, NtUserCallCount }; @@ -300,6 +304,28 @@ struct unpack_dde_message_result LPARAM lparam; };
+/* NtUserDragDropEnter params */ +struct format_entry +{ + UINT format; + UINT size; + char data[1]; +}; + +/* NtUserDragDropDrag params */ +struct drag_drop_drag_params +{ + HWND hwnd; + POINT point; + UINT effect; +}; + +/* NtUserDragDropDrop params */ +struct drag_drop_drop_params +{ + HWND hwnd; +}; + /* NtUserDragDropPost params */
/* avoid including shlobj.h */ @@ -594,6 +620,10 @@ enum wine_systray_call /* NtUserDragDropCall calls */ enum wine_drag_drop_call { + WINE_DRAG_DROP_ENTER, + WINE_DRAG_DROP_LEAVE, + WINE_DRAG_DROP_DRAG, + WINE_DRAG_DROP_DROP, WINE_DRAG_DROP_POST, };
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/clipboard.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/win32u/clipboard.c b/dlls/win32u/clipboard.c index c1d8330b51f..e8d16291cd1 100644 --- a/dlls/win32u/clipboard.c +++ b/dlls/win32u/clipboard.c @@ -777,7 +777,9 @@ LRESULT drag_drop_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void .point.y = HIWORD(wparam), .effect = lparam, }; + UINT raw_dpi;
+ params.point = map_dpi_point( params.point, get_win_monitor_dpi( hwnd, &raw_dpi ), get_thread_dpi() ); if (KeUserModeCallback( NtUserDragDropDrag, ¶ms, sizeof(params), &ret_ptr, &ret_len ) || ret_len != sizeof(DWORD)) return DROPEFFECT_NONE; return *(DWORD *)ret_ptr; @@ -796,6 +798,7 @@ LRESULT drag_drop_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void const DROPFILES *drop = (DROPFILES *)lparam; UINT drop_size = wparam, size; NTSTATUS status; + UINT raw_dpi;
size = offsetof(struct drag_drop_post_params, drop) + drop_size; if (!(params = malloc( size ))) return STATUS_NO_MEMORY; @@ -803,6 +806,7 @@ LRESULT drag_drop_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void params->drop_size = drop_size; memcpy( ¶ms->drop, drop, drop_size );
+ params->drop.pt = map_dpi_point( params->drop.pt, get_win_monitor_dpi( hwnd, &raw_dpi ), get_thread_dpi() ); status = KeUserModeCallback( NtUserDragDropPost, params, size, &ret_ptr, &ret_len ); free( params ); return status;