4 * Copyright 2003 Ulrich Czekalla
5 * Copyright 2007 Damjan Jovanovic
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
32 #define NONAMELESSUNION
41 #include "shlobj.h" /* DROPFILES */
45 #include "wine/unicode.h"
46 #include "wine/debug.h"
47 #include "wine/list.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(xdnd
);
51 /* Maximum wait time for selection notify */
52 #define SELECTION_RETRIES 500 /* wait for .1 seconds */
53 #define SELECTION_WAIT 1000 /* us */
55 typedef struct tagXDNDDATA
62 } XDNDDATA
, *LPXDNDDATA
;
64 static struct list xdndData
= LIST_INIT(xdndData
);
65 static POINT XDNDxy
= { 0, 0 };
66 static IDataObject XDNDDataObject
;
67 static BOOL XDNDAccepted
= FALSE
;
68 static DWORD XDNDDropEffect
= DROPEFFECT_NONE
;
69 /* the last window the mouse was over */
70 static HWND XDNDLastTargetWnd
;
71 /* might be an ancestor of XDNDLastTargetWnd */
72 static HWND XDNDLastDropTargetWnd
;
74 static void X11DRV_XDND_InsertXDNDData(int property
, int format
, void* data
, unsigned int len
);
75 static int X11DRV_XDND_DeconstructTextURIList(int property
, void* data
, int len
);
76 static int X11DRV_XDND_DeconstructTextPlain(int property
, void* data
, int len
);
77 static int X11DRV_XDND_DeconstructTextHTML(int property
, void* data
, int len
);
78 static int X11DRV_XDND_MapFormat(unsigned int property
, unsigned char *data
, int len
);
79 static void X11DRV_XDND_ResolveProperty(Display
*display
, Window xwin
, Time tm
,
80 Atom
*types
, unsigned long *count
);
81 static void X11DRV_XDND_SendDropFiles(HWND hwnd
);
82 static void X11DRV_XDND_FreeDragDropOp(void);
83 static unsigned int X11DRV_XDND_UnixToDos(char** lpdest
, char* lpsrc
, int len
);
84 static WCHAR
* X11DRV_XDND_URIToDOS(char *encodedURI
);
86 static CRITICAL_SECTION xdnd_cs
;
87 static CRITICAL_SECTION_DEBUG critsect_debug
=
90 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
91 0, 0, { (DWORD_PTR
)(__FILE__
": xdnd_cs") }
93 static CRITICAL_SECTION xdnd_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
96 /* Based on functions in dlls/ole32/ole2.c */
97 static HANDLE
get_droptarget_local_handle(HWND hwnd
)
99 static const WCHAR prop_marshalleddroptarget
[] =
100 {'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};
102 HANDLE local_handle
= 0;
104 handle
= GetPropW(hwnd
, prop_marshalleddroptarget
);
110 GetWindowThreadProcessId(hwnd
, &pid
);
111 process
= OpenProcess(PROCESS_DUP_HANDLE
, FALSE
, pid
);
114 DuplicateHandle(process
, handle
, GetCurrentProcess(), &local_handle
, 0, FALSE
, DUPLICATE_SAME_ACCESS
);
115 CloseHandle(process
);
121 static HRESULT
create_stream_from_map(HANDLE map
, IStream
**stream
)
123 HRESULT hr
= E_OUTOFMEMORY
;
126 MEMORY_BASIC_INFORMATION info
;
128 data
= MapViewOfFile(map
, FILE_MAP_READ
, 0, 0, 0);
131 VirtualQuery(data
, &info
, sizeof(info
));
132 TRACE("size %d\n", (int)info
.RegionSize
);
134 hmem
= GlobalAlloc(GMEM_MOVEABLE
, info
.RegionSize
);
137 memcpy(GlobalLock(hmem
), data
, info
.RegionSize
);
139 hr
= CreateStreamOnHGlobal(hmem
, TRUE
, stream
);
141 UnmapViewOfFile(data
);
145 static IDropTarget
* get_droptarget_pointer(HWND hwnd
)
147 IDropTarget
*droptarget
= NULL
;
151 map
= get_droptarget_local_handle(hwnd
);
152 if(!map
) return NULL
;
154 if(SUCCEEDED(create_stream_from_map(map
, &stream
)))
156 CoUnmarshalInterface(stream
, &IID_IDropTarget
, (void**)&droptarget
);
157 IStream_Release(stream
);
163 /**************************************************************************
164 * X11DRV_XDND_XdndActionToDROPEFFECT
166 static DWORD
X11DRV_XDND_XdndActionToDROPEFFECT(long action
)
168 /* In Windows, nothing but the given effects is allowed.
169 * In X the given action is just a hint, and you can always
170 * XdndActionCopy and XdndActionPrivate, so be more permissive. */
171 if (action
== x11drv_atom(XdndActionCopy
))
172 return DROPEFFECT_COPY
;
173 else if (action
== x11drv_atom(XdndActionMove
))
174 return DROPEFFECT_MOVE
| DROPEFFECT_COPY
;
175 else if (action
== x11drv_atom(XdndActionLink
))
176 return DROPEFFECT_LINK
| DROPEFFECT_COPY
;
177 else if (action
== x11drv_atom(XdndActionAsk
))
178 /* FIXME: should we somehow ask the user what to do here? */
179 return DROPEFFECT_COPY
| DROPEFFECT_MOVE
| DROPEFFECT_LINK
;
180 FIXME("unknown action %ld, assuming DROPEFFECT_COPY\n", action
);
181 return DROPEFFECT_COPY
;
184 /**************************************************************************
185 * X11DRV_XDND_DROPEFFECTToXdndAction
187 static long X11DRV_XDND_DROPEFFECTToXdndAction(DWORD effect
)
189 if (effect
== DROPEFFECT_COPY
)
190 return x11drv_atom(XdndActionCopy
);
191 else if (effect
== DROPEFFECT_MOVE
)
192 return x11drv_atom(XdndActionMove
);
193 else if (effect
== DROPEFFECT_LINK
)
194 return x11drv_atom(XdndActionLink
);
195 FIXME("unknown drop effect %u, assuming XdndActionCopy\n", effect
);
196 return x11drv_atom(XdndActionCopy
);
199 /**************************************************************************
200 * X11DRV_XDND_EnterEvent
202 * Handle an XdndEnter event.
204 void X11DRV_XDND_EnterEvent( HWND hWnd
, XClientMessageEvent
*event
)
208 unsigned long count
= 0;
210 version
= (event
->data
.l
[1] & 0xFF000000) >> 24;
211 TRACE("ver(%d) check-XdndTypeList(%ld) data=%ld,%ld,%ld,%ld,%ld\n",
212 version
, (event
->data
.l
[1] & 1),
213 event
->data
.l
[0], event
->data
.l
[1], event
->data
.l
[2],
214 event
->data
.l
[3], event
->data
.l
[4]);
216 if (version
> WINE_XDND_VERSION
)
218 TRACE("Ignores unsupported version\n");
222 XDNDAccepted
= FALSE
;
224 /* If the source supports more than 3 data types we retrieve
225 * the entire list. */
226 if (event
->data
.l
[1] & 1)
230 unsigned long bytesret
;
232 /* Request supported formats from source window */
233 XGetWindowProperty(event
->display
, event
->data
.l
[0], x11drv_atom(XdndTypeList
),
234 0, 65535, FALSE
, AnyPropertyType
, &acttype
, &actfmt
, &count
,
235 &bytesret
, (unsigned char**)&xdndtypes
);
240 xdndtypes
= (Atom
*) &event
->data
.l
[2];
247 for (i
= 0; i
< count
; i
++)
249 if (xdndtypes
[i
] != 0)
251 char * pn
= XGetAtomName(event
->display
, xdndtypes
[i
]);
252 TRACE("XDNDEnterAtom %ld: %s\n", xdndtypes
[i
], pn
);
258 /* Do a one-time data read and cache results */
259 X11DRV_XDND_ResolveProperty(event
->display
, event
->window
,
260 event
->data
.l
[1], xdndtypes
, &count
);
262 if (event
->data
.l
[1] & 1)
266 /**************************************************************************
267 * X11DRV_XDND_PositionEvent
269 * Handle an XdndPosition event.
271 void X11DRV_XDND_PositionEvent( HWND hWnd
, XClientMessageEvent
*event
)
273 XClientMessageEvent e
;
274 int accept
= 0; /* Assume we're not accepting */
275 IDropTarget
*dropTarget
= NULL
;
281 XDNDxy
= root_to_virtual_screen( event
->data
.l
[2] >> 16, event
->data
.l
[2] & 0xFFFF );
282 targetWindow
= WindowFromPoint(XDNDxy
);
286 effect
= X11DRV_XDND_XdndActionToDROPEFFECT(event
->data
.l
[4]);
288 if (!XDNDAccepted
|| XDNDLastTargetWnd
!= targetWindow
)
290 /* Notify OLE of DragEnter. Result determines if we accept */
291 HWND dropTargetWindow
;
293 if (XDNDLastDropTargetWnd
)
295 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
298 hr
= IDropTarget_DragLeave(dropTarget
);
300 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr
);
301 IDropTarget_Release(dropTarget
);
304 dropTargetWindow
= targetWindow
;
307 dropTarget
= get_droptarget_pointer(dropTargetWindow
);
308 } while (dropTarget
== NULL
&& (dropTargetWindow
= GetParent(dropTargetWindow
)) != NULL
);
309 XDNDLastTargetWnd
= targetWindow
;
310 XDNDLastDropTargetWnd
= dropTargetWindow
;
313 hr
= IDropTarget_DragEnter(dropTarget
, &XDNDDataObject
,
314 MK_LBUTTON
, pointl
, &effect
);
317 if (effect
!= DROPEFFECT_NONE
)
320 TRACE("the application accepted the drop\n");
323 TRACE("the application refused the drop\n");
326 WARN("IDropTarget_DragEnter failed, error 0x%08X\n", hr
);
327 IDropTarget_Release(dropTarget
);
330 if (XDNDAccepted
&& XDNDLastTargetWnd
== targetWindow
)
332 /* If drag accepted notify OLE of DragOver */
333 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
336 hr
= IDropTarget_DragOver(dropTarget
, MK_LBUTTON
, pointl
, &effect
);
338 XDNDDropEffect
= effect
;
340 WARN("IDropTarget_DragOver failed, error 0x%08X\n", hr
);
341 IDropTarget_Release(dropTarget
);
347 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)
350 TRACE("action req: %ld accept(%d) at x(%d),y(%d)\n",
351 event
->data
.l
[4], accept
, XDNDxy
.x
, XDNDxy
.y
);
354 * Let source know if we're accepting the drop by
355 * sending a status message.
357 e
.type
= ClientMessage
;
358 e
.display
= event
->display
;
359 e
.window
= event
->data
.l
[0];
360 e
.message_type
= x11drv_atom(XdndStatus
);
362 e
.data
.l
[0] = event
->window
;
363 e
.data
.l
[1] = accept
;
364 e
.data
.l
[2] = 0; /* Empty Rect */
365 e
.data
.l
[3] = 0; /* Empty Rect */
367 e
.data
.l
[4] = X11DRV_XDND_DROPEFFECTToXdndAction(effect
);
370 XSendEvent(event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
373 /**************************************************************************
374 * X11DRV_XDND_DropEvent
376 * Handle an XdndDrop event.
378 void X11DRV_XDND_DropEvent( HWND hWnd
, XClientMessageEvent
*event
)
380 XClientMessageEvent e
;
381 IDropTarget
*dropTarget
;
385 /* If we have a HDROP type we send a WM_ACCEPTFILES.*/
386 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)
387 X11DRV_XDND_SendDropFiles( hWnd
);
389 /* Notify OLE of Drop */
390 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
395 DWORD effect
= XDNDDropEffect
;
399 hr
= IDropTarget_Drop(dropTarget
, &XDNDDataObject
, MK_LBUTTON
,
403 if (effect
!= DROPEFFECT_NONE
)
404 TRACE("drop succeeded\n");
406 TRACE("the application refused the drop\n");
409 WARN("drop failed, error 0x%08X\n", hr
);
410 IDropTarget_Release(dropTarget
);
413 X11DRV_XDND_FreeDragDropOp();
415 /* Tell the target we are finished. */
416 memset(&e
, 0, sizeof(e
));
417 e
.type
= ClientMessage
;
418 e
.display
= event
->display
;
419 e
.window
= event
->data
.l
[0];
420 e
.message_type
= x11drv_atom(XdndFinished
);
422 e
.data
.l
[0] = event
->window
;
423 XSendEvent(event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
426 /**************************************************************************
427 * X11DRV_XDND_LeaveEvent
429 * Handle an XdndLeave event.
431 void X11DRV_XDND_LeaveEvent( HWND hWnd
, XClientMessageEvent
*event
)
433 IDropTarget
*dropTarget
;
435 TRACE("DND Operation canceled\n");
437 /* Notify OLE of DragLeave */
438 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
441 HRESULT hr
= IDropTarget_DragLeave(dropTarget
);
443 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr
);
444 IDropTarget_Release(dropTarget
);
447 X11DRV_XDND_FreeDragDropOp();
451 /**************************************************************************
452 * X11DRV_XDND_ResolveProperty
454 * Resolve all MIME types to windows clipboard formats. All data is cached.
456 static void X11DRV_XDND_ResolveProperty(Display
*display
, Window xwin
, Time tm
,
457 Atom
*types
, unsigned long *count
)
464 unsigned long bytesret
, icount
;
466 unsigned char* data
= NULL
;
467 XDNDDATA
*current
, *next
;
468 BOOL haveHDROP
= FALSE
;
470 TRACE("count(%ld)\n", *count
);
472 X11DRV_XDND_FreeDragDropOp(); /* Clear previously cached data */
474 for (i
= 0; i
< *count
; i
++)
476 TRACE("requesting atom %ld from xwin %ld\n", types
[i
], xwin
);
481 XConvertSelection(display
, x11drv_atom(XdndSelection
), types
[i
],
482 x11drv_atom(XdndTarget
), xwin
, /*tm*/CurrentTime
);
485 * Wait for SelectionNotify
487 for (j
= 0; j
< SELECTION_RETRIES
; j
++)
489 res
= XCheckTypedWindowEvent(display
, xwin
, SelectionNotify
, &xe
);
490 if (res
&& xe
.xselection
.selection
== x11drv_atom(XdndSelection
)) break;
492 usleep(SELECTION_WAIT
);
495 if (xe
.xselection
.property
== None
)
498 XGetWindowProperty(display
, xwin
, x11drv_atom(XdndTarget
), 0, 65535, FALSE
,
499 AnyPropertyType
, &acttype
, &actfmt
, &icount
, &bytesret
, &data
);
501 entries
+= X11DRV_XDND_MapFormat(types
[i
], data
, get_property_size( actfmt
, icount
));
505 /* On Windows when there is a CF_HDROP, there are no other CF_ formats.
506 * foobar2000 relies on this (spaces -> %20's without it).
508 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
510 if (current
->cf_win
== CF_HDROP
)
518 LIST_FOR_EACH_ENTRY_SAFE(current
, next
, &xdndData
, XDNDDATA
, entry
)
520 if (current
->cf_win
!= CF_HDROP
&& current
->cf_win
< CF_MAX
)
522 list_remove(¤t
->entry
);
523 HeapFree(GetProcessHeap(), 0, current
->data
);
524 HeapFree(GetProcessHeap(), 0, current
);
534 /**************************************************************************
535 * X11DRV_XDND_InsertXDNDData
537 * Cache available XDND property
539 static void X11DRV_XDND_InsertXDNDData(int property
, int format
, void* data
, unsigned int len
)
541 LPXDNDDATA current
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(XDNDDATA
));
545 EnterCriticalSection(&xdnd_cs
);
546 current
->cf_xdnd
= property
;
547 current
->cf_win
= format
;
548 current
->data
= data
;
550 list_add_tail(&xdndData
, ¤t
->entry
);
551 LeaveCriticalSection(&xdnd_cs
);
556 /**************************************************************************
557 * X11DRV_XDND_MapFormat
559 * Map XDND MIME format to windows clipboard format.
561 static int X11DRV_XDND_MapFormat(unsigned int property
, unsigned char *data
, int len
)
566 TRACE("%d: %s\n", property
, data
);
568 /* Always include the raw type */
569 xdata
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
570 memcpy(xdata
, data
, len
);
571 X11DRV_XDND_InsertXDNDData(property
, property
, xdata
, len
);
574 if (property
== x11drv_atom(text_uri_list
))
575 count
+= X11DRV_XDND_DeconstructTextURIList(property
, data
, len
);
576 else if (property
== x11drv_atom(text_plain
))
577 count
+= X11DRV_XDND_DeconstructTextPlain(property
, data
, len
);
578 else if (property
== x11drv_atom(text_html
))
579 count
+= X11DRV_XDND_DeconstructTextHTML(property
, data
, len
);
585 /**************************************************************************
586 * X11DRV_XDND_DeconstructTextURIList
588 * Interpret text/uri-list data and add records to <dndfmt> linked list
590 static int X11DRV_XDND_DeconstructTextURIList(int property
, void* data
, int len
)
592 char *uriList
= data
;
604 out
= HeapAlloc(GetProcessHeap(), 0, capacity
* sizeof(WCHAR
));
610 while (end
< len
&& uriList
[end
] != '\r')
612 if (end
< (len
- 1) && uriList
[end
+1] != '\n')
614 WARN("URI list line doesn't end in \\r\\n\n");
618 uri
= HeapAlloc(GetProcessHeap(), 0, end
- start
+ 1);
621 lstrcpynA(uri
, &uriList
[start
], end
- start
+ 1);
622 path
= X11DRV_XDND_URIToDOS(uri
);
623 TRACE("converted URI %s to DOS path %s\n", debugstr_a(uri
), debugstr_w(path
));
624 HeapFree(GetProcessHeap(), 0, uri
);
628 int pathSize
= strlenW(path
) + 1;
629 if (pathSize
> capacity
-size
)
631 capacity
= 2*capacity
+ pathSize
;
632 out
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, out
, (capacity
+ 1)*sizeof(WCHAR
));
636 memcpy(&out
[size
], path
, pathSize
* sizeof(WCHAR
));
639 HeapFree(GetProcessHeap(), 0, path
);
647 if (out
&& end
>= len
)
649 DROPFILES
*dropFiles
;
650 dropFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(DROPFILES
) + (size
+ 1)*sizeof(WCHAR
));
653 dropFiles
->pFiles
= sizeof(DROPFILES
);
654 dropFiles
->pt
.x
= XDNDxy
.x
;
655 dropFiles
->pt
.y
= XDNDxy
.y
;
657 dropFiles
->fWide
= TRUE
;
659 memcpy(((char*)dropFiles
) + dropFiles
->pFiles
, out
, (size
+ 1)*sizeof(WCHAR
));
660 X11DRV_XDND_InsertXDNDData(property
, CF_HDROP
, dropFiles
, sizeof(DROPFILES
) + (size
+ 1)*sizeof(WCHAR
));
664 HeapFree(GetProcessHeap(), 0, out
);
669 /**************************************************************************
670 * X11DRV_XDND_DeconstructTextPlain
672 * Interpret text/plain Data and add records to <dndfmt> linked list
674 static int X11DRV_XDND_DeconstructTextPlain(int property
, void* data
, int len
)
678 /* Always supply plain text */
679 X11DRV_XDND_UnixToDos(&dostext
, data
, len
);
680 X11DRV_XDND_InsertXDNDData(property
, CF_TEXT
, dostext
, strlen(dostext
));
682 TRACE("CF_TEXT (%d): %s\n", CF_TEXT
, dostext
);
688 /**************************************************************************
689 * X11DRV_XDND_DeconstructTextHTML
691 * Interpret text/html data and add records to <dndfmt> linked list
693 static int X11DRV_XDND_DeconstructTextHTML(int property
, void* data
, int len
)
697 X11DRV_XDND_UnixToDos(&dostext
, data
, len
);
699 X11DRV_XDND_InsertXDNDData(property
,
700 RegisterClipboardFormatA("UniformResourceLocator"), dostext
, strlen(dostext
));
702 TRACE("UniformResourceLocator: %s\n", dostext
);
708 /**************************************************************************
709 * X11DRV_XDND_SendDropFiles
711 static void X11DRV_XDND_SendDropFiles(HWND hwnd
)
713 LPXDNDDATA current
= NULL
;
716 EnterCriticalSection(&xdnd_cs
);
718 /* Find CF_HDROP type if any */
719 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
721 if (current
->cf_win
== CF_HDROP
)
730 HGLOBAL dropHandle
= GlobalAlloc(GMEM_FIXED
, current
->size
);
734 DROPFILES
*lpDrop
= GlobalLock(dropHandle
);
735 lpDrop
->pt
.x
= XDNDxy
.x
;
736 lpDrop
->pt
.y
= XDNDxy
.y
;
737 memcpy(lpDrop
, current
->data
, current
->size
);
738 TRACE("Sending WM_DROPFILES: hWnd(0x%p) %p(%s)\n", hwnd
,
739 ((char*)lpDrop
) + lpDrop
->pFiles
, debugstr_w((WCHAR
*)(((char*)lpDrop
) + lpDrop
->pFiles
)));
740 GlobalUnlock(dropHandle
);
742 if (!PostMessageW(hwnd
, WM_DROPFILES
, (WPARAM
)dropHandle
, 0))
743 GlobalFree(dropHandle
);
747 LeaveCriticalSection(&xdnd_cs
);
751 /**************************************************************************
752 * X11DRV_XDND_FreeDragDropOp
754 static void X11DRV_XDND_FreeDragDropOp(void)
761 EnterCriticalSection(&xdnd_cs
);
763 /** Free data cache */
764 LIST_FOR_EACH_ENTRY_SAFE(current
, next
, &xdndData
, XDNDDATA
, entry
)
766 list_remove(¤t
->entry
);
767 HeapFree(GetProcessHeap(), 0, current
->data
);
768 HeapFree(GetProcessHeap(), 0, current
);
771 XDNDxy
.x
= XDNDxy
.y
= 0;
772 XDNDLastTargetWnd
= NULL
;
773 XDNDLastDropTargetWnd
= NULL
;
774 XDNDAccepted
= FALSE
;
776 LeaveCriticalSection(&xdnd_cs
);
781 /**************************************************************************
782 * X11DRV_XDND_UnixToDos
784 static unsigned int X11DRV_XDND_UnixToDos(char** lpdest
, char* lpsrc
, int len
)
787 unsigned int destlen
, lines
;
789 for (i
= 0, lines
= 0; i
<= len
; i
++)
791 if (lpsrc
[i
] == '\n')
795 destlen
= len
+ lines
+ 1;
799 char* lpstr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, destlen
);
800 for (i
= 0, lines
= 0; i
<= len
; i
++)
802 if (lpsrc
[i
] == '\n')
803 lpstr
[++lines
+ i
] = '\r';
804 lpstr
[lines
+ i
] = lpsrc
[i
];
814 /**************************************************************************
815 * X11DRV_XDND_URIToDOS
817 static WCHAR
* X11DRV_XDND_URIToDOS(char *encodedURI
)
822 char *uri
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, strlen(encodedURI
) + 1);
825 for (i
= 0; encodedURI
[i
]; ++i
)
827 if (encodedURI
[i
] == '%')
829 if (encodedURI
[i
+1] && encodedURI
[i
+2])
833 buffer
[0] = encodedURI
[i
+1];
834 buffer
[1] = encodedURI
[i
+2];
836 sscanf(buffer
, "%x", &number
);
842 WARN("invalid URI encoding in %s\n", debugstr_a(encodedURI
));
843 HeapFree(GetProcessHeap(), 0, uri
);
848 uri
[j
++] = encodedURI
[i
];
851 /* Read http://www.freedesktop.org/wiki/Draganddropwarts and cry... */
852 if (strncmp(uri
, "file:/", 6) == 0)
858 /* file:///path/to/file (nautilus, thunar) */
859 ret
= wine_get_dos_file_name(&uri
[7]);
863 /* file://hostname/path/to/file (X file drag spec) */
865 char *path
= strchr(&uri
[7], '/');
869 if (strcmp(&uri
[7], "localhost") == 0)
872 ret
= wine_get_dos_file_name(path
);
874 else if (gethostname(hostname
, sizeof(hostname
)) == 0)
876 if (strcmp(hostname
, &uri
[7]) == 0)
879 ret
= wine_get_dos_file_name(path
);
887 /* file:/path/to/file (konqueror) */
888 ret
= wine_get_dos_file_name(&uri
[5]);
891 HeapFree(GetProcessHeap(), 0, uri
);
896 /**************************************************************************
897 * X11DRV_XDND_DescribeClipboardFormat
899 static void X11DRV_XDND_DescribeClipboardFormat(int cfFormat
, char *buffer
, int size
)
901 #define D(x) case x: lstrcpynA(buffer, #x, size); return;
924 if (CF_PRIVATEFIRST
<= cfFormat
&& cfFormat
<= CF_PRIVATELAST
)
926 lstrcpynA(buffer
, "some private object", size
);
929 if (CF_GDIOBJFIRST
<= cfFormat
&& cfFormat
<= CF_GDIOBJLAST
)
931 lstrcpynA(buffer
, "some GDI object", size
);
935 GetClipboardFormatNameA(cfFormat
, buffer
, size
);
939 /* The IDataObject singleton we feed to OLE follows */
941 static HRESULT WINAPI
XDNDDATAOBJECT_QueryInterface(IDataObject
*dataObject
,
942 REFIID riid
, void **ppvObject
)
944 TRACE("(%p, %s, %p)\n", dataObject
, debugstr_guid(riid
), ppvObject
);
945 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDataObject
))
947 *ppvObject
= dataObject
;
948 IDataObject_AddRef(dataObject
);
952 return E_NOINTERFACE
;
955 static ULONG WINAPI
XDNDDATAOBJECT_AddRef(IDataObject
*dataObject
)
957 TRACE("(%p)\n", dataObject
);
961 static ULONG WINAPI
XDNDDATAOBJECT_Release(IDataObject
*dataObject
)
963 TRACE("(%p)\n", dataObject
);
967 static HRESULT WINAPI
XDNDDATAOBJECT_GetData(IDataObject
*dataObject
,
968 FORMATETC
*formatEtc
,
972 char formatDesc
[1024];
974 TRACE("(%p, %p, %p)\n", dataObject
, formatEtc
, pMedium
);
975 X11DRV_XDND_DescribeClipboardFormat(formatEtc
->cfFormat
,
976 formatDesc
, sizeof(formatDesc
));
977 TRACE("application is looking for %s\n", formatDesc
);
979 hr
= IDataObject_QueryGetData(dataObject
, formatEtc
);
983 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
985 if (current
->cf_win
== formatEtc
->cfFormat
)
987 pMedium
->tymed
= TYMED_HGLOBAL
;
988 pMedium
->u
.hGlobal
= HeapAlloc(GetProcessHeap(), 0, current
->size
);
989 if (pMedium
->u
.hGlobal
== NULL
)
990 return E_OUTOFMEMORY
;
991 memcpy(pMedium
->u
.hGlobal
, current
->data
, current
->size
);
992 pMedium
->pUnkForRelease
= 0;
1000 static HRESULT WINAPI
XDNDDATAOBJECT_GetDataHere(IDataObject
*dataObject
,
1001 FORMATETC
*formatEtc
,
1004 FIXME("(%p, %p, %p): stub\n", dataObject
, formatEtc
, pMedium
);
1005 return DATA_E_FORMATETC
;
1008 static HRESULT WINAPI
XDNDDATAOBJECT_QueryGetData(IDataObject
*dataObject
,
1009 FORMATETC
*formatEtc
)
1011 char formatDesc
[1024];
1014 TRACE("(%p, %p={.tymed=0x%x, .dwAspect=%d, .cfFormat=%d}\n",
1015 dataObject
, formatEtc
, formatEtc
->tymed
, formatEtc
->dwAspect
, formatEtc
->cfFormat
);
1016 X11DRV_XDND_DescribeClipboardFormat(formatEtc
->cfFormat
, formatDesc
, sizeof(formatDesc
));
1018 if (formatEtc
->tymed
&& !(formatEtc
->tymed
& TYMED_HGLOBAL
))
1020 FIXME("only HGLOBAL medium types supported right now\n");
1023 if (formatEtc
->dwAspect
!= DVASPECT_CONTENT
)
1025 FIXME("only the content aspect is supported right now\n");
1029 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
1031 if (current
->cf_win
== formatEtc
->cfFormat
)
1033 TRACE("application found %s\n", formatDesc
);
1037 TRACE("application didn't find %s\n", formatDesc
);
1038 return DV_E_FORMATETC
;
1041 static HRESULT WINAPI
XDNDDATAOBJECT_GetCanonicalFormatEtc(IDataObject
*dataObject
,
1042 FORMATETC
*formatEtc
,
1043 FORMATETC
*formatEtcOut
)
1045 FIXME("(%p, %p, %p): stub\n", dataObject
, formatEtc
, formatEtcOut
);
1046 formatEtcOut
->ptd
= NULL
;
1050 static HRESULT WINAPI
XDNDDATAOBJECT_SetData(IDataObject
*dataObject
,
1051 FORMATETC
*formatEtc
,
1052 STGMEDIUM
*pMedium
, BOOL fRelease
)
1054 FIXME("(%p, %p, %p, %s): stub\n", dataObject
, formatEtc
,
1055 pMedium
, fRelease
?"TRUE":"FALSE");
1059 static HRESULT WINAPI
XDNDDATAOBJECT_EnumFormatEtc(IDataObject
*dataObject
,
1061 IEnumFORMATETC
**ppEnumFormatEtc
)
1066 TRACE("(%p, %u, %p)\n", dataObject
, dwDirection
, ppEnumFormatEtc
);
1068 if (dwDirection
!= DATADIR_GET
)
1070 FIXME("only the get direction is implemented\n");
1074 count
= list_count(&xdndData
);
1075 formats
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(FORMATETC
));
1081 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
1083 formats
[i
].cfFormat
= current
->cf_win
;
1084 formats
[i
].ptd
= NULL
;
1085 formats
[i
].dwAspect
= DVASPECT_CONTENT
;
1086 formats
[i
].lindex
= -1;
1087 formats
[i
].tymed
= TYMED_HGLOBAL
;
1090 hr
= SHCreateStdEnumFmtEtc(count
, formats
, ppEnumFormatEtc
);
1091 HeapFree(GetProcessHeap(), 0, formats
);
1095 return E_OUTOFMEMORY
;
1098 static HRESULT WINAPI
XDNDDATAOBJECT_DAdvise(IDataObject
*dataObject
,
1099 FORMATETC
*formatEtc
, DWORD advf
,
1100 IAdviseSink
*adviseSink
,
1101 DWORD
*pdwConnection
)
1103 FIXME("(%p, %p, %u, %p, %p): stub\n", dataObject
, formatEtc
, advf
,
1104 adviseSink
, pdwConnection
);
1105 return OLE_E_ADVISENOTSUPPORTED
;
1108 static HRESULT WINAPI
XDNDDATAOBJECT_DUnadvise(IDataObject
*dataObject
,
1111 FIXME("(%p, %u): stub\n", dataObject
, dwConnection
);
1112 return OLE_E_ADVISENOTSUPPORTED
;
1115 static HRESULT WINAPI
XDNDDATAOBJECT_EnumDAdvise(IDataObject
*dataObject
,
1116 IEnumSTATDATA
**pEnumAdvise
)
1118 FIXME("(%p, %p): stub\n", dataObject
, pEnumAdvise
);
1119 return OLE_E_ADVISENOTSUPPORTED
;
1122 static IDataObjectVtbl xdndDataObjectVtbl
=
1124 XDNDDATAOBJECT_QueryInterface
,
1125 XDNDDATAOBJECT_AddRef
,
1126 XDNDDATAOBJECT_Release
,
1127 XDNDDATAOBJECT_GetData
,
1128 XDNDDATAOBJECT_GetDataHere
,
1129 XDNDDATAOBJECT_QueryGetData
,
1130 XDNDDATAOBJECT_GetCanonicalFormatEtc
,
1131 XDNDDATAOBJECT_SetData
,
1132 XDNDDATAOBJECT_EnumFormatEtc
,
1133 XDNDDATAOBJECT_DAdvise
,
1134 XDNDDATAOBJECT_DUnadvise
,
1135 XDNDDATAOBJECT_EnumDAdvise
1138 static IDataObject XDNDDataObject
= { &xdndDataObjectVtbl
};