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 a 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 */
234 XGetWindowProperty(event
->display
, event
->data
.l
[0], x11drv_atom(XdndTypeList
),
235 0, 65535, FALSE
, AnyPropertyType
, &acttype
, &actfmt
, &count
,
236 &bytesret
, (unsigned char**)&xdndtypes
);
242 xdndtypes
= (Atom
*) &event
->data
.l
[2];
250 for (; i
< count
; i
++)
252 if (xdndtypes
[i
] != 0)
254 char * pn
= XGetAtomName(event
->display
, xdndtypes
[i
]);
255 TRACE("XDNDEnterAtom %ld: %s\n", xdndtypes
[i
], pn
);
262 /* Do a one-time data read and cache results */
263 X11DRV_XDND_ResolveProperty(event
->display
, event
->window
,
264 event
->data
.l
[1], xdndtypes
, &count
);
266 if (event
->data
.l
[1] & 1)
270 /**************************************************************************
271 * X11DRV_XDND_PositionEvent
273 * Handle an XdndPosition event.
275 void X11DRV_XDND_PositionEvent( HWND hWnd
, XClientMessageEvent
*event
)
277 XClientMessageEvent e
;
278 int accept
= 0; /* Assume we're not accepting */
279 IDropTarget
*dropTarget
= NULL
;
285 XDNDxy
.x
= event
->data
.l
[2] >> 16;
286 XDNDxy
.y
= event
->data
.l
[2] & 0xFFFF;
287 XDNDxy
.x
+= virtual_screen_rect
.left
;
288 XDNDxy
.y
+= virtual_screen_rect
.top
;
289 targetWindow
= WindowFromPoint(XDNDxy
);
293 effect
= X11DRV_XDND_XdndActionToDROPEFFECT(event
->data
.l
[4]);
295 if (!XDNDAccepted
|| XDNDLastTargetWnd
!= targetWindow
)
297 /* Notify OLE of DragEnter. Result determines if we accept */
298 HWND dropTargetWindow
;
300 if (XDNDLastDropTargetWnd
)
302 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
305 hr
= IDropTarget_DragLeave(dropTarget
);
307 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr
);
308 IDropTarget_Release(dropTarget
);
311 dropTargetWindow
= targetWindow
;
314 dropTarget
= get_droptarget_pointer(dropTargetWindow
);
315 } while (dropTarget
== NULL
&& (dropTargetWindow
= GetParent(dropTargetWindow
)) != NULL
);
316 XDNDLastTargetWnd
= targetWindow
;
317 XDNDLastDropTargetWnd
= dropTargetWindow
;
320 hr
= IDropTarget_DragEnter(dropTarget
, &XDNDDataObject
,
321 MK_LBUTTON
, pointl
, &effect
);
324 if (effect
!= DROPEFFECT_NONE
)
327 TRACE("the application accepted the drop\n");
330 TRACE("the application refused the drop\n");
333 WARN("IDropTarget_DragEnter failed, error 0x%08X\n", hr
);
334 IDropTarget_Release(dropTarget
);
337 if (XDNDAccepted
&& XDNDLastTargetWnd
== targetWindow
)
339 /* If drag accepted notify OLE of DragOver */
340 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
343 hr
= IDropTarget_DragOver(dropTarget
, MK_LBUTTON
, pointl
, &effect
);
345 XDNDDropEffect
= effect
;
347 WARN("IDropTarget_DragOver failed, error 0x%08X\n", hr
);
348 IDropTarget_Release(dropTarget
);
354 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)
357 TRACE("action req: %ld accept(%d) at x(%d),y(%d)\n",
358 event
->data
.l
[4], accept
, XDNDxy
.x
, XDNDxy
.y
);
361 * Let source know if we're accepting the drop by
362 * sending a status message.
364 e
.type
= ClientMessage
;
365 e
.display
= event
->display
;
366 e
.window
= event
->data
.l
[0];
367 e
.message_type
= x11drv_atom(XdndStatus
);
369 e
.data
.l
[0] = event
->window
;
370 e
.data
.l
[1] = accept
;
371 e
.data
.l
[2] = 0; /* Empty Rect */
372 e
.data
.l
[3] = 0; /* Empty Rect */
374 e
.data
.l
[4] = X11DRV_XDND_DROPEFFECTToXdndAction(effect
);
378 XSendEvent(event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
382 /**************************************************************************
383 * X11DRV_XDND_DropEvent
385 * Handle an XdndDrop event.
387 void X11DRV_XDND_DropEvent( HWND hWnd
, XClientMessageEvent
*event
)
389 XClientMessageEvent e
;
390 IDropTarget
*dropTarget
;
394 /* If we have a HDROP type we send a WM_ACCEPTFILES.*/
395 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)
396 X11DRV_XDND_SendDropFiles( hWnd
);
398 /* Notify OLE of Drop */
399 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
404 DWORD effect
= XDNDDropEffect
;
408 hr
= IDropTarget_Drop(dropTarget
, &XDNDDataObject
, MK_LBUTTON
,
412 if (effect
!= DROPEFFECT_NONE
)
413 TRACE("drop succeeded\n");
415 TRACE("the application refused the drop\n");
418 WARN("drop failed, error 0x%08X\n", hr
);
419 IDropTarget_Release(dropTarget
);
422 X11DRV_XDND_FreeDragDropOp();
424 /* Tell the target we are finished. */
425 memset(&e
, 0, sizeof(e
));
426 e
.type
= ClientMessage
;
427 e
.display
= event
->display
;
428 e
.window
= event
->data
.l
[0];
429 e
.message_type
= x11drv_atom(XdndFinished
);
431 e
.data
.l
[0] = event
->window
;
433 XSendEvent(event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
437 /**************************************************************************
438 * X11DRV_XDND_LeaveEvent
440 * Handle an XdndLeave event.
442 void X11DRV_XDND_LeaveEvent( HWND hWnd
, XClientMessageEvent
*event
)
444 IDropTarget
*dropTarget
;
446 TRACE("DND Operation canceled\n");
448 /* Notify OLE of DragLeave */
449 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
452 HRESULT hr
= IDropTarget_DragLeave(dropTarget
);
454 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr
);
455 IDropTarget_Release(dropTarget
);
458 X11DRV_XDND_FreeDragDropOp();
462 /**************************************************************************
463 * X11DRV_XDND_ResolveProperty
465 * Resolve all MIME types to windows clipboard formats. All data is cached.
467 static void X11DRV_XDND_ResolveProperty(Display
*display
, Window xwin
, Time tm
,
468 Atom
*types
, unsigned long *count
)
475 unsigned long bytesret
, icount
;
477 unsigned char* data
= NULL
;
478 XDNDDATA
*current
, *next
;
479 BOOL haveHDROP
= FALSE
;
481 TRACE("count(%ld)\n", *count
);
483 X11DRV_XDND_FreeDragDropOp(); /* Clear previously cached data */
485 for (i
= 0; i
< *count
; i
++)
487 TRACE("requesting atom %ld from xwin %ld\n", types
[i
], xwin
);
493 XConvertSelection(display
, x11drv_atom(XdndSelection
), types
[i
],
494 x11drv_atom(XdndTarget
), xwin
, /*tm*/CurrentTime
);
498 * Wait for SelectionNotify
500 for (j
= 0; j
< SELECTION_RETRIES
; j
++)
503 res
= XCheckTypedWindowEvent(display
, xwin
, SelectionNotify
, &xe
);
505 if (res
&& xe
.xselection
.selection
== x11drv_atom(XdndSelection
)) break;
507 usleep(SELECTION_WAIT
);
510 if (xe
.xselection
.property
== None
)
514 XGetWindowProperty(display
, xwin
, x11drv_atom(XdndTarget
), 0, 65535, FALSE
,
515 AnyPropertyType
, &acttype
, &actfmt
, &icount
, &bytesret
, &data
);
518 entries
+= X11DRV_XDND_MapFormat(types
[i
], data
, get_property_size( actfmt
, icount
));
524 /* On Windows when there is a CF_HDROP, there are no other CF_ formats.
525 * foobar2000 relies on this (spaces -> %20's without it).
527 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
529 if (current
->cf_win
== CF_HDROP
)
537 LIST_FOR_EACH_ENTRY_SAFE(current
, next
, &xdndData
, XDNDDATA
, entry
)
539 if (current
->cf_win
!= CF_HDROP
&& current
->cf_win
< CF_MAX
)
541 list_remove(¤t
->entry
);
542 HeapFree(GetProcessHeap(), 0, current
->data
);
543 HeapFree(GetProcessHeap(), 0, current
);
553 /**************************************************************************
554 * X11DRV_XDND_InsertXDNDData
556 * Cache available XDND property
558 static void X11DRV_XDND_InsertXDNDData(int property
, int format
, void* data
, unsigned int len
)
560 LPXDNDDATA current
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(XDNDDATA
));
564 EnterCriticalSection(&xdnd_cs
);
565 current
->cf_xdnd
= property
;
566 current
->cf_win
= format
;
567 current
->data
= data
;
569 list_add_tail(&xdndData
, ¤t
->entry
);
570 LeaveCriticalSection(&xdnd_cs
);
575 /**************************************************************************
576 * X11DRV_XDND_MapFormat
578 * Map XDND MIME format to windows clipboard format.
580 static int X11DRV_XDND_MapFormat(unsigned int property
, unsigned char *data
, int len
)
585 TRACE("%d: %s\n", property
, data
);
587 /* Always include the raw type */
588 xdata
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
589 memcpy(xdata
, data
, len
);
590 X11DRV_XDND_InsertXDNDData(property
, property
, xdata
, len
);
593 if (property
== x11drv_atom(text_uri_list
))
594 count
+= X11DRV_XDND_DeconstructTextURIList(property
, data
, len
);
595 else if (property
== x11drv_atom(text_plain
))
596 count
+= X11DRV_XDND_DeconstructTextPlain(property
, data
, len
);
597 else if (property
== x11drv_atom(text_html
))
598 count
+= X11DRV_XDND_DeconstructTextHTML(property
, data
, len
);
604 /**************************************************************************
605 * X11DRV_XDND_DeconstructTextURIList
607 * Interpret text/uri-list data and add records to <dndfmt> linked list
609 static int X11DRV_XDND_DeconstructTextURIList(int property
, void* data
, int len
)
611 char *uriList
= data
;
623 out
= HeapAlloc(GetProcessHeap(), 0, capacity
* sizeof(WCHAR
));
629 while (end
< len
&& uriList
[end
] != '\r')
631 if (end
< (len
- 1) && uriList
[end
+1] != '\n')
633 WARN("URI list line doesn't end in \\r\\n\n");
637 uri
= HeapAlloc(GetProcessHeap(), 0, end
- start
+ 1);
640 lstrcpynA(uri
, &uriList
[start
], end
- start
+ 1);
641 path
= X11DRV_XDND_URIToDOS(uri
);
642 TRACE("converted URI %s to DOS path %s\n", debugstr_a(uri
), debugstr_w(path
));
643 HeapFree(GetProcessHeap(), 0, uri
);
647 int pathSize
= strlenW(path
) + 1;
648 if (pathSize
> capacity
-size
)
650 capacity
= 2*capacity
+ pathSize
;
651 out
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, out
, (capacity
+ 1)*sizeof(WCHAR
));
655 memcpy(&out
[size
], path
, pathSize
* sizeof(WCHAR
));
658 HeapFree(GetProcessHeap(), 0, path
);
666 if (out
&& end
>= len
)
668 DROPFILES
*dropFiles
;
669 dropFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(DROPFILES
) + (size
+ 1)*sizeof(WCHAR
));
672 dropFiles
->pFiles
= sizeof(DROPFILES
);
673 dropFiles
->pt
.x
= XDNDxy
.x
;
674 dropFiles
->pt
.y
= XDNDxy
.y
;
676 dropFiles
->fWide
= TRUE
;
678 memcpy(((char*)dropFiles
) + dropFiles
->pFiles
, out
, (size
+ 1)*sizeof(WCHAR
));
679 X11DRV_XDND_InsertXDNDData(property
, CF_HDROP
, dropFiles
, sizeof(DROPFILES
) + (size
+ 1)*sizeof(WCHAR
));
683 HeapFree(GetProcessHeap(), 0, out
);
688 /**************************************************************************
689 * X11DRV_XDND_DeconstructTextPlain
691 * Interpret text/plain Data and add records to <dndfmt> linked list
693 static int X11DRV_XDND_DeconstructTextPlain(int property
, void* data
, int len
)
697 /* Always supply plain text */
698 X11DRV_XDND_UnixToDos(&dostext
, data
, len
);
699 X11DRV_XDND_InsertXDNDData(property
, CF_TEXT
, dostext
, strlen(dostext
));
701 TRACE("CF_TEXT (%d): %s\n", CF_TEXT
, dostext
);
707 /**************************************************************************
708 * X11DRV_XDND_DeconstructTextHTML
710 * Interpret text/html data and add records to <dndfmt> linked list
712 static int X11DRV_XDND_DeconstructTextHTML(int property
, void* data
, int len
)
716 X11DRV_XDND_UnixToDos(&dostext
, data
, len
);
718 X11DRV_XDND_InsertXDNDData(property
,
719 RegisterClipboardFormatA("UniformResourceLocator"), dostext
, strlen(dostext
));
721 TRACE("UniformResourceLocator: %s\n", dostext
);
727 /**************************************************************************
728 * X11DRV_XDND_SendDropFiles
730 static void X11DRV_XDND_SendDropFiles(HWND hwnd
)
732 LPXDNDDATA current
= NULL
;
735 EnterCriticalSection(&xdnd_cs
);
737 /* Find CF_HDROP type if any */
738 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
740 if (current
->cf_win
== CF_HDROP
)
749 DROPFILES
*lpDrop
= current
->data
;
753 lpDrop
->pt
.x
= XDNDxy
.x
;
754 lpDrop
->pt
.y
= XDNDxy
.y
;
756 TRACE("Sending WM_DROPFILES: hWnd(0x%p) %p(%s)\n", hwnd
,
757 ((char*)lpDrop
) + lpDrop
->pFiles
, debugstr_w((WCHAR
*)(((char*)lpDrop
) + lpDrop
->pFiles
)));
759 PostMessageW(hwnd
, WM_DROPFILES
, (WPARAM
)lpDrop
, 0L);
763 LeaveCriticalSection(&xdnd_cs
);
767 /**************************************************************************
768 * X11DRV_XDND_FreeDragDropOp
770 static void X11DRV_XDND_FreeDragDropOp(void)
777 EnterCriticalSection(&xdnd_cs
);
779 /** Free data cache */
780 LIST_FOR_EACH_ENTRY_SAFE(current
, next
, &xdndData
, XDNDDATA
, entry
)
782 list_remove(¤t
->entry
);
783 HeapFree(GetProcessHeap(), 0, current
);
786 XDNDxy
.x
= XDNDxy
.y
= 0;
787 XDNDLastTargetWnd
= NULL
;
788 XDNDLastDropTargetWnd
= NULL
;
789 XDNDAccepted
= FALSE
;
791 LeaveCriticalSection(&xdnd_cs
);
796 /**************************************************************************
797 * X11DRV_XDND_UnixToDos
799 static unsigned int X11DRV_XDND_UnixToDos(char** lpdest
, char* lpsrc
, int len
)
802 unsigned int destlen
, lines
;
804 for (i
= 0, lines
= 0; i
<= len
; i
++)
806 if (lpsrc
[i
] == '\n')
810 destlen
= len
+ lines
+ 1;
814 char* lpstr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, destlen
);
815 for (i
= 0, lines
= 0; i
<= len
; i
++)
817 if (lpsrc
[i
] == '\n')
818 lpstr
[++lines
+ i
] = '\r';
819 lpstr
[lines
+ i
] = lpsrc
[i
];
829 /**************************************************************************
830 * X11DRV_XDND_URIToDOS
832 static WCHAR
* X11DRV_XDND_URIToDOS(char *encodedURI
)
837 char *uri
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, strlen(encodedURI
) + 1);
840 for (i
= 0; encodedURI
[i
]; ++i
)
842 if (encodedURI
[i
] == '%')
844 if (encodedURI
[i
+1] && encodedURI
[i
+2])
848 buffer
[0] = encodedURI
[i
+1];
849 buffer
[1] = encodedURI
[i
+2];
851 sscanf(buffer
, "%x", &number
);
857 WARN("invalid URI encoding in %s\n", debugstr_a(encodedURI
));
858 HeapFree(GetProcessHeap(), 0, uri
);
863 uri
[j
++] = encodedURI
[i
];
866 /* Read http://www.freedesktop.org/wiki/Draganddropwarts and cry... */
867 if (strncmp(uri
, "file:/", 6) == 0)
873 /* file:///path/to/file (nautilus, thunar) */
874 ret
= wine_get_dos_file_name(&uri
[7]);
878 /* file://hostname/path/to/file (X file drag spec) */
880 char *path
= strchr(&uri
[7], '/');
884 if (strcmp(&uri
[7], "localhost") == 0)
887 ret
= wine_get_dos_file_name(path
);
889 else if (gethostname(hostname
, sizeof(hostname
)) == 0)
891 if (strcmp(hostname
, &uri
[7]) == 0)
894 ret
= wine_get_dos_file_name(path
);
902 /* file:/path/to/file (konqueror) */
903 ret
= wine_get_dos_file_name(&uri
[5]);
906 HeapFree(GetProcessHeap(), 0, uri
);
911 /**************************************************************************
912 * X11DRV_XDND_DescribeClipboardFormat
914 static void X11DRV_XDND_DescribeClipboardFormat(int cfFormat
, char *buffer
, int size
)
916 #define D(x) case x: lstrcpynA(buffer, #x, size); return;
939 if (CF_PRIVATEFIRST
<= cfFormat
&& cfFormat
<= CF_PRIVATELAST
)
941 lstrcpynA(buffer
, "some private object", size
);
944 if (CF_GDIOBJFIRST
<= cfFormat
&& cfFormat
<= CF_GDIOBJLAST
)
946 lstrcpynA(buffer
, "some GDI object", size
);
950 GetClipboardFormatNameA(cfFormat
, buffer
, size
);
954 /* The IDataObject singleton we feed to OLE follows */
956 static HRESULT WINAPI
XDNDDATAOBJECT_QueryInterface(IDataObject
*dataObject
,
957 REFIID riid
, void **ppvObject
)
959 TRACE("(%p, %s, %p)\n", dataObject
, debugstr_guid(riid
), ppvObject
);
960 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDataObject
))
962 *ppvObject
= dataObject
;
963 IDataObject_AddRef(dataObject
);
967 return E_NOINTERFACE
;
970 static ULONG WINAPI
XDNDDATAOBJECT_AddRef(IDataObject
*dataObject
)
972 TRACE("(%p)\n", dataObject
);
976 static ULONG WINAPI
XDNDDATAOBJECT_Release(IDataObject
*dataObject
)
978 TRACE("(%p)\n", dataObject
);
982 static HRESULT WINAPI
XDNDDATAOBJECT_GetData(IDataObject
*dataObject
,
983 FORMATETC
*formatEtc
,
987 char formatDesc
[1024];
989 TRACE("(%p, %p, %p)\n", dataObject
, formatEtc
, pMedium
);
990 X11DRV_XDND_DescribeClipboardFormat(formatEtc
->cfFormat
,
991 formatDesc
, sizeof(formatDesc
));
992 TRACE("application is looking for %s\n", formatDesc
);
994 hr
= IDataObject_QueryGetData(dataObject
, formatEtc
);
998 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
1000 if (current
->cf_win
== formatEtc
->cfFormat
)
1002 pMedium
->tymed
= TYMED_HGLOBAL
;
1003 pMedium
->u
.hGlobal
= HeapAlloc(GetProcessHeap(), 0, current
->size
);
1004 if (pMedium
->u
.hGlobal
== NULL
)
1005 return E_OUTOFMEMORY
;
1006 memcpy(pMedium
->u
.hGlobal
, current
->data
, current
->size
);
1007 pMedium
->pUnkForRelease
= 0;
1015 static HRESULT WINAPI
XDNDDATAOBJECT_GetDataHere(IDataObject
*dataObject
,
1016 FORMATETC
*formatEtc
,
1019 FIXME("(%p, %p, %p): stub\n", dataObject
, formatEtc
, pMedium
);
1020 return DATA_E_FORMATETC
;
1023 static HRESULT WINAPI
XDNDDATAOBJECT_QueryGetData(IDataObject
*dataObject
,
1024 FORMATETC
*formatEtc
)
1026 char formatDesc
[1024];
1029 TRACE("(%p, %p={.tymed=0x%x, .dwAspect=%d, .cfFormat=%d}\n",
1030 dataObject
, formatEtc
, formatEtc
->tymed
, formatEtc
->dwAspect
, formatEtc
->cfFormat
);
1031 X11DRV_XDND_DescribeClipboardFormat(formatEtc
->cfFormat
, formatDesc
, sizeof(formatDesc
));
1033 if (formatEtc
->tymed
&& !(formatEtc
->tymed
& TYMED_HGLOBAL
))
1035 FIXME("only HGLOBAL medium types supported right now\n");
1038 if (formatEtc
->dwAspect
!= DVASPECT_CONTENT
)
1040 FIXME("only the content aspect is supported right now\n");
1044 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
1046 if (current
->cf_win
== formatEtc
->cfFormat
)
1048 TRACE("application found %s\n", formatDesc
);
1052 TRACE("application didn't find %s\n", formatDesc
);
1053 return DV_E_FORMATETC
;
1056 static HRESULT WINAPI
XDNDDATAOBJECT_GetCanonicalFormatEtc(IDataObject
*dataObject
,
1057 FORMATETC
*formatEtc
,
1058 FORMATETC
*formatEtcOut
)
1060 FIXME("(%p, %p, %p): stub\n", dataObject
, formatEtc
, formatEtcOut
);
1061 formatEtcOut
->ptd
= NULL
;
1065 static HRESULT WINAPI
XDNDDATAOBJECT_SetData(IDataObject
*dataObject
,
1066 FORMATETC
*formatEtc
,
1067 STGMEDIUM
*pMedium
, BOOL fRelease
)
1069 FIXME("(%p, %p, %p, %s): stub\n", dataObject
, formatEtc
,
1070 pMedium
, fRelease
?"TRUE":"FALSE");
1074 static HRESULT WINAPI
XDNDDATAOBJECT_EnumFormatEtc(IDataObject
*dataObject
,
1076 IEnumFORMATETC
**ppEnumFormatEtc
)
1081 TRACE("(%p, %u, %p)\n", dataObject
, dwDirection
, ppEnumFormatEtc
);
1083 if (dwDirection
!= DATADIR_GET
)
1085 FIXME("only the get direction is implemented\n");
1089 count
= list_count(&xdndData
);
1090 formats
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(FORMATETC
));
1096 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
1098 formats
[i
].cfFormat
= current
->cf_win
;
1099 formats
[i
].ptd
= NULL
;
1100 formats
[i
].dwAspect
= DVASPECT_CONTENT
;
1101 formats
[i
].lindex
= -1;
1102 formats
[i
].tymed
= TYMED_HGLOBAL
;
1105 hr
= SHCreateStdEnumFmtEtc(count
, formats
, ppEnumFormatEtc
);
1106 HeapFree(GetProcessHeap(), 0, formats
);
1110 return E_OUTOFMEMORY
;
1113 static HRESULT WINAPI
XDNDDATAOBJECT_DAdvise(IDataObject
*dataObject
,
1114 FORMATETC
*formatEtc
, DWORD advf
,
1115 IAdviseSink
*adviseSink
,
1116 DWORD
*pdwConnection
)
1118 FIXME("(%p, %p, %u, %p, %p): stub\n", dataObject
, formatEtc
, advf
,
1119 adviseSink
, pdwConnection
);
1120 return OLE_E_ADVISENOTSUPPORTED
;
1123 static HRESULT WINAPI
XDNDDATAOBJECT_DUnadvise(IDataObject
*dataObject
,
1126 FIXME("(%p, %u): stub\n", dataObject
, dwConnection
);
1127 return OLE_E_ADVISENOTSUPPORTED
;
1130 static HRESULT WINAPI
XDNDDATAOBJECT_EnumDAdvise(IDataObject
*dataObject
,
1131 IEnumSTATDATA
**pEnumAdvise
)
1133 FIXME("(%p, %p): stub\n", dataObject
, pEnumAdvise
);
1134 return OLE_E_ADVISENOTSUPPORTED
;
1137 static IDataObjectVtbl xdndDataObjectVtbl
=
1139 XDNDDATAOBJECT_QueryInterface
,
1140 XDNDDATAOBJECT_AddRef
,
1141 XDNDDATAOBJECT_Release
,
1142 XDNDDATAOBJECT_GetData
,
1143 XDNDDATAOBJECT_GetDataHere
,
1144 XDNDDATAOBJECT_QueryGetData
,
1145 XDNDDATAOBJECT_GetCanonicalFormatEtc
,
1146 XDNDDATAOBJECT_SetData
,
1147 XDNDDATAOBJECT_EnumFormatEtc
,
1148 XDNDDATAOBJECT_DAdvise
,
1149 XDNDDATAOBJECT_DUnadvise
,
1150 XDNDDATAOBJECT_EnumDAdvise
1153 static IDataObject XDNDDataObject
= { &xdndDataObjectVtbl
};