From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Huw Davies huw@codeweavers.com --- dlls/winex11.drv/clipboard.c | 29 +++++++++++++++++------------ dlls/winex11.drv/x11drv.h | 14 +++++++++++--- dlls/winex11.drv/xdnd.c | 26 ++++++++++++++++++++++++-- 3 files changed, 52 insertions(+), 17 deletions(-)
diff --git a/dlls/winex11.drv/clipboard.c b/dlls/winex11.drv/clipboard.c index ec69778fc3c..92284d436dd 100644 --- a/dlls/winex11.drv/clipboard.c +++ b/dlls/winex11.drv/clipboard.c @@ -1096,21 +1096,21 @@ static void *import_selection( Display *display, Window win, Atom selection,
/************************************************************************** - * X11DRV_CLIPBOARD_ImportSelection + * import_xdnd_selection * * Import the X selection into the clipboard format registered for the given X target. */ -void X11DRV_CLIPBOARD_ImportSelection( Display *display, Window win, Atom selection, - Atom *targets, UINT count, - void (*callback)( UINT, HANDLE )) +struct format_entry *import_xdnd_selection( Display *display, Window win, Atom selection, + Atom *targets, UINT count, size_t *ret_size ) { + size_t size, buf_size = 0, entry_size; UINT i; - HANDLE handle; void *data; - size_t size; struct clipboard_format *format; + struct format_entry *ret = NULL, *entry;
register_x11_formats( targets, count ); + *ret_size = 0;
for (i = 0; i < count; i++) { @@ -1118,16 +1118,21 @@ void X11DRV_CLIPBOARD_ImportSelection( Display *display, Window win, Atom select if (!format->id) continue; if (!(data = import_selection( display, win, selection, format, &size ))) continue;
- if ((handle = GlobalAlloc( GMEM_FIXED, size ))) + entry_size = (FIELD_OFFSET( struct format_entry, data[size] ) + 7) & ~7; + if (buf_size < size + entry_size) { - void *ptr; - ptr = GlobalLock( handle ); - memcpy( ptr, data, size ); - GlobalUnlock( handle ); - callback( format->id, handle ); + if (!(ret = realloc( ret, *ret_size + entry_size + 1024 ))) continue; + buf_size = *ret_size + entry_size + 1024; /* extra space for following entries */ } + entry = (struct format_entry *)((char *)ret + *ret_size); + entry->format = format->id; + entry->size = size; + if (size) memcpy( entry->data, data, size ); + *ret_size += entry_size; free( data ); } + + return ret; }
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index a8d2f78aa6b..f6d28122fc3 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -297,9 +297,17 @@ extern void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ) DECL 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; -extern void X11DRV_CLIPBOARD_ImportSelection( Display *display, Window win, Atom selection, - Atom *targets, UINT count, - void (*callback)( UINT, HANDLE )) DECLSPEC_HIDDEN; + +struct format_entry +{ + UINT format; + UINT size; + char data[1]; +}; + +extern struct format_entry *import_xdnd_selection( Display *display, Window win, Atom selection, + Atom *targets, UINT count, + size_t *size ) DECLSPEC_HIDDEN;
/************************************************************************** * X11 GDI driver diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c index b9bba1ff872..aa46467f6f7 100644 --- a/dlls/winex11.drv/xdnd.c +++ b/dlls/winex11.drv/xdnd.c @@ -79,6 +79,12 @@ static CRITICAL_SECTION_DEBUG critsect_debug = 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]; +} + + /* Based on functions in dlls/ole32/ole2.c */ static HANDLE get_droptarget_local_handle(HWND hwnd) { @@ -523,15 +529,31 @@ void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event ) static void X11DRV_XDND_ResolveProperty(Display *display, Window xwin, Time tm, Atom *types, unsigned long count) { + struct format_entry *formats, *formats_end, *iter; XDNDDATA *current, *next; BOOL haveHDROP = FALSE; + size_t size;
TRACE("count(%ld)\n", count);
X11DRV_XDND_FreeDragDropOp(); /* Clear previously cached data */
- X11DRV_CLIPBOARD_ImportSelection( display, xwin, x11drv_atom(XdndSelection), - types, count, X11DRV_XDND_InsertXDNDData ); + formats = import_xdnd_selection( display, xwin, x11drv_atom(XdndSelection), types, count, &size ); + if (formats) + { + formats_end = (struct format_entry *)((char *)formats + size); + for (iter = formats; iter < formats_end; iter = next_format( iter )) + { + HANDLE handle; + if ((handle = GlobalAlloc( GMEM_FIXED, iter->size ))) + { + void *ptr = GlobalLock( handle ); + memcpy( ptr, iter->data, iter->size ); + GlobalUnlock( handle ); + X11DRV_XDND_InsertXDNDData( iter->format, handle ); + } + } + }
/* On Windows when there is a CF_HDROP, there are no other CF_ formats. * foobar2000 relies on this (spaces -> %20's without it).