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"
39 #include "shlobj.h" /* DROPFILES */
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45 #include "wine/list.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(xdnd
);
49 /* Maximum wait time for selection notify */
50 #define SELECTION_RETRIES 500 /* wait for .1 seconds */
51 #define SELECTION_WAIT 1000 /* us */
53 typedef struct tagXDNDDATA
60 } XDNDDATA
, *LPXDNDDATA
;
62 static struct list xdndData
= LIST_INIT(xdndData
);
63 static POINT XDNDxy
= { 0, 0 };
64 static IDataObject XDNDDataObject
;
65 static BOOL XDNDAccepted
= FALSE
;
66 static DWORD XDNDDropEffect
= DROPEFFECT_NONE
;
67 /* the last window the mouse was over */
68 static HWND XDNDLastTargetWnd
;
69 /* might be a ancestor of XDNDLastTargetWnd */
70 static HWND XDNDLastDropTargetWnd
;
72 static void X11DRV_XDND_InsertXDNDData(int property
, int format
, void* data
, unsigned int len
);
73 static int X11DRV_XDND_DeconstructTextURIList(int property
, void* data
, int len
);
74 static int X11DRV_XDND_DeconstructTextPlain(int property
, void* data
, int len
);
75 static int X11DRV_XDND_DeconstructTextHTML(int property
, void* data
, int len
);
76 static int X11DRV_XDND_MapFormat(unsigned int property
, unsigned char *data
, int len
);
77 static void X11DRV_XDND_ResolveProperty(Display
*display
, Window xwin
, Time tm
,
78 Atom
*types
, unsigned long *count
);
79 static void X11DRV_XDND_SendDropFiles(HWND hwnd
);
80 static void X11DRV_XDND_FreeDragDropOp(void);
81 static unsigned int X11DRV_XDND_UnixToDos(char** lpdest
, char* lpsrc
, int len
);
82 static WCHAR
* X11DRV_XDND_URIToDOS(char *encodedURI
);
84 static CRITICAL_SECTION xdnd_cs
;
85 static CRITICAL_SECTION_DEBUG critsect_debug
=
88 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
89 0, 0, { (DWORD_PTR
)(__FILE__
": xdnd_cs") }
91 static CRITICAL_SECTION xdnd_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
94 /* Based on functions in dlls/ole32/ole2.c */
95 static HANDLE
get_droptarget_local_handle(HWND hwnd
)
97 static const WCHAR prop_marshalleddroptarget
[] =
98 {'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};
100 HANDLE local_handle
= 0;
102 handle
= GetPropW(hwnd
, prop_marshalleddroptarget
);
108 GetWindowThreadProcessId(hwnd
, &pid
);
109 process
= OpenProcess(PROCESS_DUP_HANDLE
, FALSE
, pid
);
112 DuplicateHandle(process
, handle
, GetCurrentProcess(), &local_handle
, 0, FALSE
, DUPLICATE_SAME_ACCESS
);
113 CloseHandle(process
);
119 static HRESULT
create_stream_from_map(HANDLE map
, IStream
**stream
)
121 HRESULT hr
= E_OUTOFMEMORY
;
124 MEMORY_BASIC_INFORMATION info
;
126 data
= MapViewOfFile(map
, FILE_MAP_READ
, 0, 0, 0);
129 VirtualQuery(data
, &info
, sizeof(info
));
130 TRACE("size %d\n", (int)info
.RegionSize
);
132 hmem
= GlobalAlloc(GMEM_MOVEABLE
, info
.RegionSize
);
135 memcpy(GlobalLock(hmem
), data
, info
.RegionSize
);
137 hr
= CreateStreamOnHGlobal(hmem
, TRUE
, stream
);
139 UnmapViewOfFile(data
);
143 static IDropTarget
* get_droptarget_pointer(HWND hwnd
)
145 IDropTarget
*droptarget
= NULL
;
149 map
= get_droptarget_local_handle(hwnd
);
150 if(!map
) return NULL
;
152 if(SUCCEEDED(create_stream_from_map(map
, &stream
)))
154 CoUnmarshalInterface(stream
, &IID_IDropTarget
, (void**)&droptarget
);
155 IStream_Release(stream
);
161 /**************************************************************************
162 * X11DRV_XDND_XdndActionToDROPEFFECT
164 static DWORD
X11DRV_XDND_XdndActionToDROPEFFECT(long action
)
166 /* In Windows, nothing but the given effects is allowed.
167 * In X the given action is just a hint, and you can always
168 * XdndActionCopy and XdndActionPrivate, so be more permissive. */
169 if (action
== x11drv_atom(XdndActionCopy
))
170 return DROPEFFECT_COPY
;
171 else if (action
== x11drv_atom(XdndActionMove
))
172 return DROPEFFECT_MOVE
| DROPEFFECT_COPY
;
173 else if (action
== x11drv_atom(XdndActionLink
))
174 return DROPEFFECT_LINK
| DROPEFFECT_COPY
;
175 else if (action
== x11drv_atom(XdndActionAsk
))
176 /* FIXME: should we somehow ask the user what to do here? */
177 return DROPEFFECT_COPY
| DROPEFFECT_MOVE
| DROPEFFECT_LINK
;
178 FIXME("unknown action %ld, assuming DROPEFFECT_COPY\n", action
);
179 return DROPEFFECT_COPY
;
182 /**************************************************************************
183 * X11DRV_XDND_DROPEFFECTToXdndAction
185 static long X11DRV_XDND_DROPEFFECTToXdndAction(DWORD effect
)
187 if (effect
== DROPEFFECT_COPY
)
188 return x11drv_atom(XdndActionCopy
);
189 else if (effect
== DROPEFFECT_MOVE
)
190 return x11drv_atom(XdndActionMove
);
191 else if (effect
== DROPEFFECT_LINK
)
192 return x11drv_atom(XdndActionLink
);
193 FIXME("unknown drop effect %u, assuming XdndActionCopy\n", effect
);
194 return x11drv_atom(XdndActionCopy
);
197 /**************************************************************************
198 * X11DRV_XDND_EnterEvent
200 * Handle an XdndEnter event.
202 void X11DRV_XDND_EnterEvent( HWND hWnd
, XClientMessageEvent
*event
)
206 unsigned long count
= 0;
208 version
= (event
->data
.l
[1] & 0xFF000000) >> 24;
209 TRACE("ver(%d) check-XdndTypeList(%ld) data=%ld,%ld,%ld,%ld,%ld\n",
210 version
, (event
->data
.l
[1] & 1),
211 event
->data
.l
[0], event
->data
.l
[1], event
->data
.l
[2],
212 event
->data
.l
[3], event
->data
.l
[4]);
214 if (version
> WINE_XDND_VERSION
)
216 TRACE("Ignores unsupported version\n");
220 XDNDAccepted
= FALSE
;
222 /* If the source supports more than 3 data types we retrieve
223 * the entire list. */
224 if (event
->data
.l
[1] & 1)
228 unsigned long bytesret
;
230 /* Request supported formats from source window */
232 XGetWindowProperty(event
->display
, event
->data
.l
[0], x11drv_atom(XdndTypeList
),
233 0, 65535, FALSE
, AnyPropertyType
, &acttype
, &actfmt
, &count
,
234 &bytesret
, (unsigned char**)&xdndtypes
);
240 xdndtypes
= (Atom
*) &event
->data
.l
[2];
248 for (; i
< count
; i
++)
250 if (xdndtypes
[i
] != 0)
252 char * pn
= XGetAtomName(event
->display
, xdndtypes
[i
]);
253 TRACE("XDNDEnterAtom %ld: %s\n", xdndtypes
[i
], pn
);
260 /* Do a one-time data read and cache results */
261 X11DRV_XDND_ResolveProperty(event
->display
, event
->window
,
262 event
->data
.l
[1], xdndtypes
, &count
);
264 if (event
->data
.l
[1] & 1)
268 /**************************************************************************
269 * X11DRV_XDND_PositionEvent
271 * Handle an XdndPosition event.
273 void X11DRV_XDND_PositionEvent( HWND hWnd
, XClientMessageEvent
*event
)
275 XClientMessageEvent e
;
276 int accept
= 0; /* Assume we're not accepting */
277 IDropTarget
*dropTarget
= NULL
;
283 XDNDxy
.x
= event
->data
.l
[2] >> 16;
284 XDNDxy
.y
= event
->data
.l
[2] & 0xFFFF;
285 targetWindow
= WindowFromPoint(XDNDxy
);
289 effect
= X11DRV_XDND_XdndActionToDROPEFFECT(event
->data
.l
[4]);
291 if (!XDNDAccepted
|| XDNDLastTargetWnd
!= targetWindow
)
293 /* Notify OLE of DragEnter. Result determines if we accept */
294 HWND dropTargetWindow
;
296 if (XDNDLastDropTargetWnd
)
298 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
301 hr
= IDropTarget_DragLeave(dropTarget
);
303 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr
);
304 IDropTarget_Release(dropTarget
);
307 dropTargetWindow
= targetWindow
;
310 dropTarget
= get_droptarget_pointer(dropTargetWindow
);
311 } while (dropTarget
== NULL
&& (dropTargetWindow
= GetParent(dropTargetWindow
)) != NULL
);
312 XDNDLastTargetWnd
= targetWindow
;
313 XDNDLastDropTargetWnd
= dropTargetWindow
;
316 hr
= IDropTarget_DragEnter(dropTarget
, &XDNDDataObject
,
317 MK_LBUTTON
, pointl
, &effect
);
320 if (effect
!= DROPEFFECT_NONE
)
323 TRACE("the application accepted the drop\n");
326 TRACE("the application refused the drop\n");
329 WARN("IDropTarget_DragEnter failed, error 0x%08X\n", hr
);
330 IDropTarget_Release(dropTarget
);
333 if (XDNDAccepted
&& XDNDLastTargetWnd
== targetWindow
)
335 /* If drag accepted notify OLE of DragOver */
336 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
339 hr
= IDropTarget_DragOver(dropTarget
, MK_LBUTTON
, pointl
, &effect
);
341 XDNDDropEffect
= effect
;
343 WARN("IDropTarget_DragOver failed, error 0x%08X\n", hr
);
344 IDropTarget_Release(dropTarget
);
350 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)
353 TRACE("action req: %ld accept(%d) at x(%d),y(%d)\n",
354 event
->data
.l
[4], accept
, XDNDxy
.x
, XDNDxy
.y
);
357 * Let source know if we're accepting the drop by
358 * sending a status message.
360 e
.type
= ClientMessage
;
361 e
.display
= event
->display
;
362 e
.window
= event
->data
.l
[0];
363 e
.message_type
= x11drv_atom(XdndStatus
);
365 e
.data
.l
[0] = event
->window
;
366 e
.data
.l
[1] = accept
;
367 e
.data
.l
[2] = 0; /* Empty Rect */
368 e
.data
.l
[3] = 0; /* Empty Rect */
370 e
.data
.l
[4] = X11DRV_XDND_DROPEFFECTToXdndAction(effect
);
374 XSendEvent(event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
378 /**************************************************************************
379 * X11DRV_XDND_DropEvent
381 * Handle an XdndDrop event.
383 void X11DRV_XDND_DropEvent( HWND hWnd
, XClientMessageEvent
*event
)
385 XClientMessageEvent e
;
386 IDropTarget
*dropTarget
;
390 /* If we have a HDROP type we send a WM_ACCEPTFILES.*/
391 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)
392 X11DRV_XDND_SendDropFiles( hWnd
);
394 /* Notify OLE of Drop */
395 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
400 DWORD effect
= XDNDDropEffect
;
404 hr
= IDropTarget_Drop(dropTarget
, &XDNDDataObject
, MK_LBUTTON
,
408 if (effect
!= DROPEFFECT_NONE
)
409 TRACE("drop succeeded\n");
411 TRACE("the application refused the drop\n");
414 WARN("drop failed, error 0x%08X\n", hr
);
415 IDropTarget_Release(dropTarget
);
418 X11DRV_XDND_FreeDragDropOp();
420 /* Tell the target we are finished. */
421 memset(&e
, 0, sizeof(e
));
422 e
.type
= ClientMessage
;
423 e
.display
= event
->display
;
424 e
.window
= event
->data
.l
[0];
425 e
.message_type
= x11drv_atom(XdndFinished
);
427 e
.data
.l
[0] = event
->window
;
429 XSendEvent(event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
433 /**************************************************************************
434 * X11DRV_XDND_LeaveEvent
436 * Handle an XdndLeave event.
438 void X11DRV_XDND_LeaveEvent( HWND hWnd
, XClientMessageEvent
*event
)
440 IDropTarget
*dropTarget
;
442 TRACE("DND Operation canceled\n");
444 /* Notify OLE of DragLeave */
445 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
448 HRESULT hr
= IDropTarget_DragLeave(dropTarget
);
450 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr
);
451 IDropTarget_Release(dropTarget
);
454 X11DRV_XDND_FreeDragDropOp();
458 /**************************************************************************
459 * X11DRV_XDND_ResolveProperty
461 * Resolve all MIME types to windows clipboard formats. All data is cached.
463 static void X11DRV_XDND_ResolveProperty(Display
*display
, Window xwin
, Time tm
,
464 Atom
*types
, unsigned long *count
)
471 unsigned long bytesret
, icount
;
473 unsigned char* data
= NULL
;
474 XDNDDATA
*current
, *next
;
475 BOOL haveHDROP
= FALSE
;
477 TRACE("count(%ld)\n", *count
);
479 X11DRV_XDND_FreeDragDropOp(); /* Clear previously cached data */
481 for (i
= 0; i
< *count
; i
++)
483 TRACE("requesting atom %ld from xwin %ld\n", types
[i
], xwin
);
489 XConvertSelection(display
, x11drv_atom(XdndSelection
), types
[i
],
490 x11drv_atom(XdndTarget
), xwin
, /*tm*/CurrentTime
);
494 * Wait for SelectionNotify
496 for (j
= 0; j
< SELECTION_RETRIES
; j
++)
499 res
= XCheckTypedWindowEvent(display
, xwin
, SelectionNotify
, &xe
);
501 if (res
&& xe
.xselection
.selection
== x11drv_atom(XdndSelection
)) break;
503 usleep(SELECTION_WAIT
);
506 if (xe
.xselection
.property
== None
)
510 XGetWindowProperty(display
, xwin
, x11drv_atom(XdndTarget
), 0, 65535, FALSE
,
511 AnyPropertyType
, &acttype
, &actfmt
, &icount
, &bytesret
, &data
);
514 entries
+= X11DRV_XDND_MapFormat(types
[i
], data
, get_property_size( actfmt
, icount
));
520 /* On Windows when there is a CF_HDROP, there are no other CF_ formats.
521 * foobar2000 relies on this (spaces -> %20's without it).
523 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
525 if (current
->cf_win
== CF_HDROP
)
533 LIST_FOR_EACH_ENTRY_SAFE(current
, next
, &xdndData
, XDNDDATA
, entry
)
535 if (current
->cf_win
!= CF_HDROP
&& current
->cf_win
< CF_MAX
)
537 list_remove(¤t
->entry
);
538 HeapFree(GetProcessHeap(), 0, current
->data
);
539 HeapFree(GetProcessHeap(), 0, current
);
549 /**************************************************************************
550 * X11DRV_XDND_InsertXDNDData
552 * Cache available XDND property
554 static void X11DRV_XDND_InsertXDNDData(int property
, int format
, void* data
, unsigned int len
)
556 LPXDNDDATA current
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(XDNDDATA
));
560 EnterCriticalSection(&xdnd_cs
);
561 current
->cf_xdnd
= property
;
562 current
->cf_win
= format
;
563 current
->data
= data
;
565 list_add_tail(&xdndData
, ¤t
->entry
);
566 LeaveCriticalSection(&xdnd_cs
);
571 /**************************************************************************
572 * X11DRV_XDND_MapFormat
574 * Map XDND MIME format to windows clipboard format.
576 static int X11DRV_XDND_MapFormat(unsigned int property
, unsigned char *data
, int len
)
581 TRACE("%d: %s\n", property
, data
);
583 /* Always include the raw type */
584 xdata
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
585 memcpy(xdata
, data
, len
);
586 X11DRV_XDND_InsertXDNDData(property
, property
, xdata
, len
);
589 if (property
== x11drv_atom(text_uri_list
))
590 count
+= X11DRV_XDND_DeconstructTextURIList(property
, data
, len
);
591 else if (property
== x11drv_atom(text_plain
))
592 count
+= X11DRV_XDND_DeconstructTextPlain(property
, data
, len
);
593 else if (property
== x11drv_atom(text_html
))
594 count
+= X11DRV_XDND_DeconstructTextHTML(property
, data
, len
);
600 /**************************************************************************
601 * X11DRV_XDND_DeconstructTextURIList
603 * Interpret text/uri-list data and add records to <dndfmt> linked list
605 static int X11DRV_XDND_DeconstructTextURIList(int property
, void* data
, int len
)
607 char *uriList
= data
;
619 out
= HeapAlloc(GetProcessHeap(), 0, capacity
* sizeof(WCHAR
));
625 while (end
< len
&& uriList
[end
] != '\r')
627 if (end
< (len
- 1) && uriList
[end
+1] != '\n')
629 WARN("URI list line doesn't end in \\r\\n\n");
633 uri
= HeapAlloc(GetProcessHeap(), 0, end
- start
+ 1);
636 lstrcpynA(uri
, &uriList
[start
], end
- start
+ 1);
637 path
= X11DRV_XDND_URIToDOS(uri
);
638 TRACE("converted URI %s to DOS path %s\n", debugstr_a(uri
), debugstr_w(path
));
639 HeapFree(GetProcessHeap(), 0, uri
);
643 int pathSize
= strlenW(path
) + 1;
644 if (pathSize
> capacity
-size
)
646 capacity
= 2*capacity
+ pathSize
;
647 out
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, out
, (capacity
+ 1)*sizeof(WCHAR
));
651 memcpy(&out
[size
], path
, pathSize
* sizeof(WCHAR
));
654 HeapFree(GetProcessHeap(), 0, path
);
662 if (out
&& end
>= len
)
664 DROPFILES
*dropFiles
;
665 dropFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(DROPFILES
) + (size
+ 1)*sizeof(WCHAR
));
668 dropFiles
->pFiles
= sizeof(DROPFILES
);
669 dropFiles
->pt
.x
= XDNDxy
.x
;
670 dropFiles
->pt
.y
= XDNDxy
.y
;
672 dropFiles
->fWide
= TRUE
;
674 memcpy(((char*)dropFiles
) + dropFiles
->pFiles
, out
, (size
+ 1)*sizeof(WCHAR
));
675 X11DRV_XDND_InsertXDNDData(property
, CF_HDROP
, dropFiles
, sizeof(DROPFILES
) + (size
+ 1)*sizeof(WCHAR
));
679 HeapFree(GetProcessHeap(), 0, out
);
684 /**************************************************************************
685 * X11DRV_XDND_DeconstructTextPlain
687 * Interpret text/plain Data and add records to <dndfmt> linked list
689 static int X11DRV_XDND_DeconstructTextPlain(int property
, void* data
, int len
)
693 /* Always supply plain text */
694 X11DRV_XDND_UnixToDos(&dostext
, data
, len
);
695 X11DRV_XDND_InsertXDNDData(property
, CF_TEXT
, dostext
, strlen(dostext
));
697 TRACE("CF_TEXT (%d): %s\n", CF_TEXT
, dostext
);
703 /**************************************************************************
704 * X11DRV_XDND_DeconstructTextHTML
706 * Interpret text/html data and add records to <dndfmt> linked list
708 static int X11DRV_XDND_DeconstructTextHTML(int property
, void* data
, int len
)
712 X11DRV_XDND_UnixToDos(&dostext
, data
, len
);
714 X11DRV_XDND_InsertXDNDData(property
,
715 RegisterClipboardFormatA("UniformResourceLocator"), dostext
, strlen(dostext
));
717 TRACE("UniformResourceLocator: %s\n", dostext
);
723 /**************************************************************************
724 * X11DRV_XDND_SendDropFiles
726 static void X11DRV_XDND_SendDropFiles(HWND hwnd
)
728 LPXDNDDATA current
= NULL
;
731 EnterCriticalSection(&xdnd_cs
);
733 /* Find CF_HDROP type if any */
734 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
736 if (current
->cf_win
== CF_HDROP
)
745 DROPFILES
*lpDrop
= current
->data
;
749 lpDrop
->pt
.x
= XDNDxy
.x
;
750 lpDrop
->pt
.y
= XDNDxy
.y
;
752 TRACE("Sending WM_DROPFILES: hWnd(0x%p) %p(%s)\n", hwnd
,
753 ((char*)lpDrop
) + lpDrop
->pFiles
, debugstr_w((WCHAR
*)(((char*)lpDrop
) + lpDrop
->pFiles
)));
755 PostMessageW(hwnd
, WM_DROPFILES
, (WPARAM
)lpDrop
, 0L);
759 LeaveCriticalSection(&xdnd_cs
);
763 /**************************************************************************
764 * X11DRV_XDND_FreeDragDropOp
766 static void X11DRV_XDND_FreeDragDropOp(void)
773 EnterCriticalSection(&xdnd_cs
);
775 /** Free data cache */
776 LIST_FOR_EACH_ENTRY_SAFE(current
, next
, &xdndData
, XDNDDATA
, entry
)
778 list_remove(¤t
->entry
);
779 HeapFree(GetProcessHeap(), 0, current
);
782 XDNDxy
.x
= XDNDxy
.y
= 0;
783 XDNDLastTargetWnd
= NULL
;
784 XDNDLastDropTargetWnd
= NULL
;
785 XDNDAccepted
= FALSE
;
787 LeaveCriticalSection(&xdnd_cs
);
792 /**************************************************************************
793 * X11DRV_XDND_UnixToDos
795 static unsigned int X11DRV_XDND_UnixToDos(char** lpdest
, char* lpsrc
, int len
)
798 unsigned int destlen
, lines
;
800 for (i
= 0, lines
= 0; i
<= len
; i
++)
802 if (lpsrc
[i
] == '\n')
806 destlen
= len
+ lines
+ 1;
810 char* lpstr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, destlen
);
811 for (i
= 0, lines
= 0; i
<= len
; i
++)
813 if (lpsrc
[i
] == '\n')
814 lpstr
[++lines
+ i
] = '\r';
815 lpstr
[lines
+ i
] = lpsrc
[i
];
825 /**************************************************************************
826 * X11DRV_XDND_URIToDOS
828 static WCHAR
* X11DRV_XDND_URIToDOS(char *encodedURI
)
833 char *uri
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, strlen(encodedURI
) + 1);
836 for (i
= 0; encodedURI
[i
]; ++i
)
838 if (encodedURI
[i
] == '%')
840 if (encodedURI
[i
+1] && encodedURI
[i
+2])
844 buffer
[0] = encodedURI
[i
+1];
845 buffer
[1] = encodedURI
[i
+2];
847 sscanf(buffer
, "%x", &number
);
853 WARN("invalid URI encoding in %s\n", debugstr_a(encodedURI
));
854 HeapFree(GetProcessHeap(), 0, uri
);
859 uri
[j
++] = encodedURI
[i
];
862 /* Read http://www.freedesktop.org/wiki/Draganddropwarts and cry... */
863 if (strncmp(uri
, "file:/", 6) == 0)
869 /* file:///path/to/file (nautilus, thunar) */
870 ret
= wine_get_dos_file_name(&uri
[7]);
874 /* file://hostname/path/to/file (X file drag spec) */
876 char *path
= strchr(&uri
[7], '/');
880 if (strcmp(&uri
[7], "localhost") == 0)
883 ret
= wine_get_dos_file_name(path
);
885 else if (gethostname(hostname
, sizeof(hostname
)) == 0)
887 if (strcmp(hostname
, &uri
[7]) == 0)
890 ret
= wine_get_dos_file_name(path
);
898 /* file:/path/to/file (konqueror) */
899 ret
= wine_get_dos_file_name(&uri
[5]);
902 HeapFree(GetProcessHeap(), 0, uri
);
907 /**************************************************************************
908 * X11DRV_XDND_DescribeClipboardFormat
910 static void X11DRV_XDND_DescribeClipboardFormat(int cfFormat
, char *buffer
, int size
)
912 #define D(x) case x: lstrcpynA(buffer, #x, size); return;
935 if (CF_PRIVATEFIRST
<= cfFormat
&& cfFormat
<= CF_PRIVATELAST
)
937 lstrcpynA(buffer
, "some private object", size
);
940 if (CF_GDIOBJFIRST
<= cfFormat
&& cfFormat
<= CF_GDIOBJLAST
)
942 lstrcpynA(buffer
, "some GDI object", size
);
946 GetClipboardFormatNameA(cfFormat
, buffer
, size
);
950 /* The IDataObject singleton we feed to OLE follows */
952 static HRESULT WINAPI
XDNDDATAOBJECT_QueryInterface(IDataObject
*dataObject
,
953 REFIID riid
, void **ppvObject
)
955 TRACE("(%p, %s, %p)\n", dataObject
, debugstr_guid(riid
), ppvObject
);
956 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDataObject
))
958 *ppvObject
= dataObject
;
959 IDataObject_AddRef(dataObject
);
963 return E_NOINTERFACE
;
966 static ULONG WINAPI
XDNDDATAOBJECT_AddRef(IDataObject
*dataObject
)
968 TRACE("(%p)\n", dataObject
);
972 static ULONG WINAPI
XDNDDATAOBJECT_Release(IDataObject
*dataObject
)
974 TRACE("(%p)\n", dataObject
);
978 static HRESULT WINAPI
XDNDDATAOBJECT_GetData(IDataObject
*dataObject
,
979 FORMATETC
*formatEtc
,
983 char formatDesc
[1024];
985 TRACE("(%p, %p, %p)\n", dataObject
, formatEtc
, pMedium
);
986 X11DRV_XDND_DescribeClipboardFormat(formatEtc
->cfFormat
,
987 formatDesc
, sizeof(formatDesc
));
988 TRACE("application is looking for %s\n", formatDesc
);
990 hr
= IDataObject_QueryGetData(dataObject
, formatEtc
);
994 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
996 if (current
->cf_win
== formatEtc
->cfFormat
)
998 pMedium
->tymed
= TYMED_HGLOBAL
;
999 pMedium
->hGlobal
= HeapAlloc(GetProcessHeap(), 0, current
->size
);
1000 if (pMedium
->hGlobal
== NULL
)
1001 return E_OUTOFMEMORY
;
1002 memcpy(pMedium
->hGlobal
, current
->data
, current
->size
);
1003 pMedium
->pUnkForRelease
= 0;
1011 static HRESULT WINAPI
XDNDDATAOBJECT_GetDataHere(IDataObject
*dataObject
,
1012 FORMATETC
*formatEtc
,
1015 FIXME("(%p, %p, %p): stub\n", dataObject
, formatEtc
, pMedium
);
1016 return DATA_E_FORMATETC
;
1019 static HRESULT WINAPI
XDNDDATAOBJECT_QueryGetData(IDataObject
*dataObject
,
1020 FORMATETC
*formatEtc
)
1022 char formatDesc
[1024];
1025 TRACE("(%p, %p={.tymed=0x%x, .dwAspect=%d, .cfFormat=%d}\n",
1026 dataObject
, formatEtc
, formatEtc
->tymed
, formatEtc
->dwAspect
, formatEtc
->cfFormat
);
1027 X11DRV_XDND_DescribeClipboardFormat(formatEtc
->cfFormat
, formatDesc
, sizeof(formatDesc
));
1029 if (formatEtc
->tymed
&& !(formatEtc
->tymed
& TYMED_HGLOBAL
))
1031 FIXME("only HGLOBAL medium types supported right now\n");
1034 if (formatEtc
->dwAspect
!= DVASPECT_CONTENT
)
1036 FIXME("only the content aspect is supported right now\n");
1040 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
1042 if (current
->cf_win
== formatEtc
->cfFormat
)
1044 TRACE("application found %s\n", formatDesc
);
1048 TRACE("application didn't find %s\n", formatDesc
);
1049 return DV_E_FORMATETC
;
1052 static HRESULT WINAPI
XDNDDATAOBJECT_GetCanonicalFormatEtc(IDataObject
*dataObject
,
1053 FORMATETC
*formatEtc
,
1054 FORMATETC
*formatEtcOut
)
1056 FIXME("(%p, %p, %p): stub\n", dataObject
, formatEtc
, formatEtcOut
);
1057 formatEtcOut
->ptd
= NULL
;
1061 static HRESULT WINAPI
XDNDDATAOBJECT_SetData(IDataObject
*dataObject
,
1062 FORMATETC
*formatEtc
,
1063 STGMEDIUM
*pMedium
, BOOL fRelease
)
1065 FIXME("(%p, %p, %p, %s): stub\n", dataObject
, formatEtc
,
1066 pMedium
, fRelease
?"TRUE":"FALSE");
1070 static HRESULT WINAPI
XDNDDATAOBJECT_EnumFormatEtc(IDataObject
*dataObject
,
1072 IEnumFORMATETC
**ppEnumFormatEtc
)
1077 TRACE("(%p, %u, %p)\n", dataObject
, dwDirection
, ppEnumFormatEtc
);
1079 if (dwDirection
!= DATADIR_GET
)
1081 FIXME("only the get direction is implemented\n");
1085 count
= list_count(&xdndData
);
1086 formats
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(FORMATETC
));
1092 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
1094 formats
[i
].cfFormat
= current
->cf_win
;
1095 formats
[i
].ptd
= NULL
;
1096 formats
[i
].dwAspect
= DVASPECT_CONTENT
;
1097 formats
[i
].lindex
= -1;
1098 formats
[i
].tymed
= TYMED_HGLOBAL
;
1101 hr
= SHCreateStdEnumFmtEtc(count
, formats
, ppEnumFormatEtc
);
1102 HeapFree(GetProcessHeap(), 0, formats
);
1106 return E_OUTOFMEMORY
;
1109 static HRESULT WINAPI
XDNDDATAOBJECT_DAdvise(IDataObject
*dataObject
,
1110 FORMATETC
*formatEtc
, DWORD advf
,
1111 IAdviseSink
*adviseSink
,
1112 DWORD
*pdwConnection
)
1114 FIXME("(%p, %p, %u, %p, %p): stub\n", dataObject
, formatEtc
, advf
,
1115 adviseSink
, pdwConnection
);
1116 return OLE_E_ADVISENOTSUPPORTED
;
1119 static HRESULT WINAPI
XDNDDATAOBJECT_DUnadvise(IDataObject
*dataObject
,
1122 FIXME("(%p, %u): stub\n", dataObject
, dwConnection
);
1123 return OLE_E_ADVISENOTSUPPORTED
;
1126 static HRESULT WINAPI
XDNDDATAOBJECT_EnumDAdvise(IDataObject
*dataObject
,
1127 IEnumSTATDATA
**pEnumAdvise
)
1129 FIXME("(%p, %p): stub\n", dataObject
, pEnumAdvise
);
1130 return OLE_E_ADVISENOTSUPPORTED
;
1133 static IDataObjectVtbl xdndDataObjectVtbl
=
1135 XDNDDATAOBJECT_QueryInterface
,
1136 XDNDDATAOBJECT_AddRef
,
1137 XDNDDATAOBJECT_Release
,
1138 XDNDDATAOBJECT_GetData
,
1139 XDNDDATAOBJECT_GetDataHere
,
1140 XDNDDATAOBJECT_QueryGetData
,
1141 XDNDDATAOBJECT_GetCanonicalFormatEtc
,
1142 XDNDDATAOBJECT_SetData
,
1143 XDNDDATAOBJECT_EnumFormatEtc
,
1144 XDNDDATAOBJECT_DAdvise
,
1145 XDNDDATAOBJECT_DUnadvise
,
1146 XDNDDATAOBJECT_EnumDAdvise
1149 static IDataObject XDNDDataObject
= { &xdndDataObjectVtbl
};