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 */
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
.x
= event
->data
.l
[2] >> 16;
282 XDNDxy
.y
= event
->data
.l
[2] & 0xFFFF;
283 XDNDxy
.x
+= virtual_screen_rect
.left
;
284 XDNDxy
.y
+= virtual_screen_rect
.top
;
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
);
373 XSendEvent(event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
376 /**************************************************************************
377 * X11DRV_XDND_DropEvent
379 * Handle an XdndDrop event.
381 void X11DRV_XDND_DropEvent( HWND hWnd
, XClientMessageEvent
*event
)
383 XClientMessageEvent e
;
384 IDropTarget
*dropTarget
;
388 /* If we have a HDROP type we send a WM_ACCEPTFILES.*/
389 if (GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)
390 X11DRV_XDND_SendDropFiles( hWnd
);
392 /* Notify OLE of Drop */
393 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
398 DWORD effect
= XDNDDropEffect
;
402 hr
= IDropTarget_Drop(dropTarget
, &XDNDDataObject
, MK_LBUTTON
,
406 if (effect
!= DROPEFFECT_NONE
)
407 TRACE("drop succeeded\n");
409 TRACE("the application refused the drop\n");
412 WARN("drop failed, error 0x%08X\n", hr
);
413 IDropTarget_Release(dropTarget
);
416 X11DRV_XDND_FreeDragDropOp();
418 /* Tell the target we are finished. */
419 memset(&e
, 0, sizeof(e
));
420 e
.type
= ClientMessage
;
421 e
.display
= event
->display
;
422 e
.window
= event
->data
.l
[0];
423 e
.message_type
= x11drv_atom(XdndFinished
);
425 e
.data
.l
[0] = event
->window
;
426 XSendEvent(event
->display
, event
->data
.l
[0], False
, NoEventMask
, (XEvent
*)&e
);
429 /**************************************************************************
430 * X11DRV_XDND_LeaveEvent
432 * Handle an XdndLeave event.
434 void X11DRV_XDND_LeaveEvent( HWND hWnd
, XClientMessageEvent
*event
)
436 IDropTarget
*dropTarget
;
438 TRACE("DND Operation canceled\n");
440 /* Notify OLE of DragLeave */
441 dropTarget
= get_droptarget_pointer(XDNDLastDropTargetWnd
);
444 HRESULT hr
= IDropTarget_DragLeave(dropTarget
);
446 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr
);
447 IDropTarget_Release(dropTarget
);
450 X11DRV_XDND_FreeDragDropOp();
454 /**************************************************************************
455 * X11DRV_XDND_ResolveProperty
457 * Resolve all MIME types to windows clipboard formats. All data is cached.
459 static void X11DRV_XDND_ResolveProperty(Display
*display
, Window xwin
, Time tm
,
460 Atom
*types
, unsigned long *count
)
467 unsigned long bytesret
, icount
;
469 unsigned char* data
= NULL
;
470 XDNDDATA
*current
, *next
;
471 BOOL haveHDROP
= FALSE
;
473 TRACE("count(%ld)\n", *count
);
475 X11DRV_XDND_FreeDragDropOp(); /* Clear previously cached data */
477 for (i
= 0; i
< *count
; i
++)
479 TRACE("requesting atom %ld from xwin %ld\n", types
[i
], xwin
);
484 XConvertSelection(display
, x11drv_atom(XdndSelection
), types
[i
],
485 x11drv_atom(XdndTarget
), xwin
, /*tm*/CurrentTime
);
488 * Wait for SelectionNotify
490 for (j
= 0; j
< SELECTION_RETRIES
; j
++)
492 res
= XCheckTypedWindowEvent(display
, xwin
, SelectionNotify
, &xe
);
493 if (res
&& xe
.xselection
.selection
== x11drv_atom(XdndSelection
)) break;
495 usleep(SELECTION_WAIT
);
498 if (xe
.xselection
.property
== None
)
501 XGetWindowProperty(display
, xwin
, x11drv_atom(XdndTarget
), 0, 65535, FALSE
,
502 AnyPropertyType
, &acttype
, &actfmt
, &icount
, &bytesret
, &data
);
504 entries
+= X11DRV_XDND_MapFormat(types
[i
], data
, get_property_size( actfmt
, icount
));
508 /* On Windows when there is a CF_HDROP, there are no other CF_ formats.
509 * foobar2000 relies on this (spaces -> %20's without it).
511 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
513 if (current
->cf_win
== CF_HDROP
)
521 LIST_FOR_EACH_ENTRY_SAFE(current
, next
, &xdndData
, XDNDDATA
, entry
)
523 if (current
->cf_win
!= CF_HDROP
&& current
->cf_win
< CF_MAX
)
525 list_remove(¤t
->entry
);
526 HeapFree(GetProcessHeap(), 0, current
->data
);
527 HeapFree(GetProcessHeap(), 0, current
);
537 /**************************************************************************
538 * X11DRV_XDND_InsertXDNDData
540 * Cache available XDND property
542 static void X11DRV_XDND_InsertXDNDData(int property
, int format
, void* data
, unsigned int len
)
544 LPXDNDDATA current
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(XDNDDATA
));
548 EnterCriticalSection(&xdnd_cs
);
549 current
->cf_xdnd
= property
;
550 current
->cf_win
= format
;
551 current
->data
= data
;
553 list_add_tail(&xdndData
, ¤t
->entry
);
554 LeaveCriticalSection(&xdnd_cs
);
559 /**************************************************************************
560 * X11DRV_XDND_MapFormat
562 * Map XDND MIME format to windows clipboard format.
564 static int X11DRV_XDND_MapFormat(unsigned int property
, unsigned char *data
, int len
)
569 TRACE("%d: %s\n", property
, data
);
571 /* Always include the raw type */
572 xdata
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
573 memcpy(xdata
, data
, len
);
574 X11DRV_XDND_InsertXDNDData(property
, property
, xdata
, len
);
577 if (property
== x11drv_atom(text_uri_list
))
578 count
+= X11DRV_XDND_DeconstructTextURIList(property
, data
, len
);
579 else if (property
== x11drv_atom(text_plain
))
580 count
+= X11DRV_XDND_DeconstructTextPlain(property
, data
, len
);
581 else if (property
== x11drv_atom(text_html
))
582 count
+= X11DRV_XDND_DeconstructTextHTML(property
, data
, len
);
588 /**************************************************************************
589 * X11DRV_XDND_DeconstructTextURIList
591 * Interpret text/uri-list data and add records to <dndfmt> linked list
593 static int X11DRV_XDND_DeconstructTextURIList(int property
, void* data
, int len
)
595 char *uriList
= data
;
607 out
= HeapAlloc(GetProcessHeap(), 0, capacity
* sizeof(WCHAR
));
613 while (end
< len
&& uriList
[end
] != '\r')
615 if (end
< (len
- 1) && uriList
[end
+1] != '\n')
617 WARN("URI list line doesn't end in \\r\\n\n");
621 uri
= HeapAlloc(GetProcessHeap(), 0, end
- start
+ 1);
624 lstrcpynA(uri
, &uriList
[start
], end
- start
+ 1);
625 path
= X11DRV_XDND_URIToDOS(uri
);
626 TRACE("converted URI %s to DOS path %s\n", debugstr_a(uri
), debugstr_w(path
));
627 HeapFree(GetProcessHeap(), 0, uri
);
631 int pathSize
= strlenW(path
) + 1;
632 if (pathSize
> capacity
-size
)
634 capacity
= 2*capacity
+ pathSize
;
635 out
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, out
, (capacity
+ 1)*sizeof(WCHAR
));
639 memcpy(&out
[size
], path
, pathSize
* sizeof(WCHAR
));
642 HeapFree(GetProcessHeap(), 0, path
);
650 if (out
&& end
>= len
)
652 DROPFILES
*dropFiles
;
653 dropFiles
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(DROPFILES
) + (size
+ 1)*sizeof(WCHAR
));
656 dropFiles
->pFiles
= sizeof(DROPFILES
);
657 dropFiles
->pt
.x
= XDNDxy
.x
;
658 dropFiles
->pt
.y
= XDNDxy
.y
;
660 dropFiles
->fWide
= TRUE
;
662 memcpy(((char*)dropFiles
) + dropFiles
->pFiles
, out
, (size
+ 1)*sizeof(WCHAR
));
663 X11DRV_XDND_InsertXDNDData(property
, CF_HDROP
, dropFiles
, sizeof(DROPFILES
) + (size
+ 1)*sizeof(WCHAR
));
667 HeapFree(GetProcessHeap(), 0, out
);
672 /**************************************************************************
673 * X11DRV_XDND_DeconstructTextPlain
675 * Interpret text/plain Data and add records to <dndfmt> linked list
677 static int X11DRV_XDND_DeconstructTextPlain(int property
, void* data
, int len
)
681 /* Always supply plain text */
682 X11DRV_XDND_UnixToDos(&dostext
, data
, len
);
683 X11DRV_XDND_InsertXDNDData(property
, CF_TEXT
, dostext
, strlen(dostext
));
685 TRACE("CF_TEXT (%d): %s\n", CF_TEXT
, dostext
);
691 /**************************************************************************
692 * X11DRV_XDND_DeconstructTextHTML
694 * Interpret text/html data and add records to <dndfmt> linked list
696 static int X11DRV_XDND_DeconstructTextHTML(int property
, void* data
, int len
)
700 X11DRV_XDND_UnixToDos(&dostext
, data
, len
);
702 X11DRV_XDND_InsertXDNDData(property
,
703 RegisterClipboardFormatA("UniformResourceLocator"), dostext
, strlen(dostext
));
705 TRACE("UniformResourceLocator: %s\n", dostext
);
711 /**************************************************************************
712 * X11DRV_XDND_SendDropFiles
714 static void X11DRV_XDND_SendDropFiles(HWND hwnd
)
716 LPXDNDDATA current
= NULL
;
719 EnterCriticalSection(&xdnd_cs
);
721 /* Find CF_HDROP type if any */
722 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
724 if (current
->cf_win
== CF_HDROP
)
733 DROPFILES
*lpDrop
= current
->data
;
737 lpDrop
->pt
.x
= XDNDxy
.x
;
738 lpDrop
->pt
.y
= XDNDxy
.y
;
740 TRACE("Sending WM_DROPFILES: hWnd(0x%p) %p(%s)\n", hwnd
,
741 ((char*)lpDrop
) + lpDrop
->pFiles
, debugstr_w((WCHAR
*)(((char*)lpDrop
) + lpDrop
->pFiles
)));
743 PostMessageW(hwnd
, WM_DROPFILES
, (WPARAM
)lpDrop
, 0L);
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
);
770 XDNDxy
.x
= XDNDxy
.y
= 0;
771 XDNDLastTargetWnd
= NULL
;
772 XDNDLastDropTargetWnd
= NULL
;
773 XDNDAccepted
= FALSE
;
775 LeaveCriticalSection(&xdnd_cs
);
780 /**************************************************************************
781 * X11DRV_XDND_UnixToDos
783 static unsigned int X11DRV_XDND_UnixToDos(char** lpdest
, char* lpsrc
, int len
)
786 unsigned int destlen
, lines
;
788 for (i
= 0, lines
= 0; i
<= len
; i
++)
790 if (lpsrc
[i
] == '\n')
794 destlen
= len
+ lines
+ 1;
798 char* lpstr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, destlen
);
799 for (i
= 0, lines
= 0; i
<= len
; i
++)
801 if (lpsrc
[i
] == '\n')
802 lpstr
[++lines
+ i
] = '\r';
803 lpstr
[lines
+ i
] = lpsrc
[i
];
813 /**************************************************************************
814 * X11DRV_XDND_URIToDOS
816 static WCHAR
* X11DRV_XDND_URIToDOS(char *encodedURI
)
821 char *uri
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, strlen(encodedURI
) + 1);
824 for (i
= 0; encodedURI
[i
]; ++i
)
826 if (encodedURI
[i
] == '%')
828 if (encodedURI
[i
+1] && encodedURI
[i
+2])
832 buffer
[0] = encodedURI
[i
+1];
833 buffer
[1] = encodedURI
[i
+2];
835 sscanf(buffer
, "%x", &number
);
841 WARN("invalid URI encoding in %s\n", debugstr_a(encodedURI
));
842 HeapFree(GetProcessHeap(), 0, uri
);
847 uri
[j
++] = encodedURI
[i
];
850 /* Read http://www.freedesktop.org/wiki/Draganddropwarts and cry... */
851 if (strncmp(uri
, "file:/", 6) == 0)
857 /* file:///path/to/file (nautilus, thunar) */
858 ret
= wine_get_dos_file_name(&uri
[7]);
862 /* file://hostname/path/to/file (X file drag spec) */
864 char *path
= strchr(&uri
[7], '/');
868 if (strcmp(&uri
[7], "localhost") == 0)
871 ret
= wine_get_dos_file_name(path
);
873 else if (gethostname(hostname
, sizeof(hostname
)) == 0)
875 if (strcmp(hostname
, &uri
[7]) == 0)
878 ret
= wine_get_dos_file_name(path
);
886 /* file:/path/to/file (konqueror) */
887 ret
= wine_get_dos_file_name(&uri
[5]);
890 HeapFree(GetProcessHeap(), 0, uri
);
895 /**************************************************************************
896 * X11DRV_XDND_DescribeClipboardFormat
898 static void X11DRV_XDND_DescribeClipboardFormat(int cfFormat
, char *buffer
, int size
)
900 #define D(x) case x: lstrcpynA(buffer, #x, size); return;
923 if (CF_PRIVATEFIRST
<= cfFormat
&& cfFormat
<= CF_PRIVATELAST
)
925 lstrcpynA(buffer
, "some private object", size
);
928 if (CF_GDIOBJFIRST
<= cfFormat
&& cfFormat
<= CF_GDIOBJLAST
)
930 lstrcpynA(buffer
, "some GDI object", size
);
934 GetClipboardFormatNameA(cfFormat
, buffer
, size
);
938 /* The IDataObject singleton we feed to OLE follows */
940 static HRESULT WINAPI
XDNDDATAOBJECT_QueryInterface(IDataObject
*dataObject
,
941 REFIID riid
, void **ppvObject
)
943 TRACE("(%p, %s, %p)\n", dataObject
, debugstr_guid(riid
), ppvObject
);
944 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDataObject
))
946 *ppvObject
= dataObject
;
947 IDataObject_AddRef(dataObject
);
951 return E_NOINTERFACE
;
954 static ULONG WINAPI
XDNDDATAOBJECT_AddRef(IDataObject
*dataObject
)
956 TRACE("(%p)\n", dataObject
);
960 static ULONG WINAPI
XDNDDATAOBJECT_Release(IDataObject
*dataObject
)
962 TRACE("(%p)\n", dataObject
);
966 static HRESULT WINAPI
XDNDDATAOBJECT_GetData(IDataObject
*dataObject
,
967 FORMATETC
*formatEtc
,
971 char formatDesc
[1024];
973 TRACE("(%p, %p, %p)\n", dataObject
, formatEtc
, pMedium
);
974 X11DRV_XDND_DescribeClipboardFormat(formatEtc
->cfFormat
,
975 formatDesc
, sizeof(formatDesc
));
976 TRACE("application is looking for %s\n", formatDesc
);
978 hr
= IDataObject_QueryGetData(dataObject
, formatEtc
);
982 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
984 if (current
->cf_win
== formatEtc
->cfFormat
)
986 pMedium
->tymed
= TYMED_HGLOBAL
;
987 pMedium
->u
.hGlobal
= HeapAlloc(GetProcessHeap(), 0, current
->size
);
988 if (pMedium
->u
.hGlobal
== NULL
)
989 return E_OUTOFMEMORY
;
990 memcpy(pMedium
->u
.hGlobal
, current
->data
, current
->size
);
991 pMedium
->pUnkForRelease
= 0;
999 static HRESULT WINAPI
XDNDDATAOBJECT_GetDataHere(IDataObject
*dataObject
,
1000 FORMATETC
*formatEtc
,
1003 FIXME("(%p, %p, %p): stub\n", dataObject
, formatEtc
, pMedium
);
1004 return DATA_E_FORMATETC
;
1007 static HRESULT WINAPI
XDNDDATAOBJECT_QueryGetData(IDataObject
*dataObject
,
1008 FORMATETC
*formatEtc
)
1010 char formatDesc
[1024];
1013 TRACE("(%p, %p={.tymed=0x%x, .dwAspect=%d, .cfFormat=%d}\n",
1014 dataObject
, formatEtc
, formatEtc
->tymed
, formatEtc
->dwAspect
, formatEtc
->cfFormat
);
1015 X11DRV_XDND_DescribeClipboardFormat(formatEtc
->cfFormat
, formatDesc
, sizeof(formatDesc
));
1017 if (formatEtc
->tymed
&& !(formatEtc
->tymed
& TYMED_HGLOBAL
))
1019 FIXME("only HGLOBAL medium types supported right now\n");
1022 if (formatEtc
->dwAspect
!= DVASPECT_CONTENT
)
1024 FIXME("only the content aspect is supported right now\n");
1028 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
1030 if (current
->cf_win
== formatEtc
->cfFormat
)
1032 TRACE("application found %s\n", formatDesc
);
1036 TRACE("application didn't find %s\n", formatDesc
);
1037 return DV_E_FORMATETC
;
1040 static HRESULT WINAPI
XDNDDATAOBJECT_GetCanonicalFormatEtc(IDataObject
*dataObject
,
1041 FORMATETC
*formatEtc
,
1042 FORMATETC
*formatEtcOut
)
1044 FIXME("(%p, %p, %p): stub\n", dataObject
, formatEtc
, formatEtcOut
);
1045 formatEtcOut
->ptd
= NULL
;
1049 static HRESULT WINAPI
XDNDDATAOBJECT_SetData(IDataObject
*dataObject
,
1050 FORMATETC
*formatEtc
,
1051 STGMEDIUM
*pMedium
, BOOL fRelease
)
1053 FIXME("(%p, %p, %p, %s): stub\n", dataObject
, formatEtc
,
1054 pMedium
, fRelease
?"TRUE":"FALSE");
1058 static HRESULT WINAPI
XDNDDATAOBJECT_EnumFormatEtc(IDataObject
*dataObject
,
1060 IEnumFORMATETC
**ppEnumFormatEtc
)
1065 TRACE("(%p, %u, %p)\n", dataObject
, dwDirection
, ppEnumFormatEtc
);
1067 if (dwDirection
!= DATADIR_GET
)
1069 FIXME("only the get direction is implemented\n");
1073 count
= list_count(&xdndData
);
1074 formats
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(FORMATETC
));
1080 LIST_FOR_EACH_ENTRY(current
, &xdndData
, XDNDDATA
, entry
)
1082 formats
[i
].cfFormat
= current
->cf_win
;
1083 formats
[i
].ptd
= NULL
;
1084 formats
[i
].dwAspect
= DVASPECT_CONTENT
;
1085 formats
[i
].lindex
= -1;
1086 formats
[i
].tymed
= TYMED_HGLOBAL
;
1089 hr
= SHCreateStdEnumFmtEtc(count
, formats
, ppEnumFormatEtc
);
1090 HeapFree(GetProcessHeap(), 0, formats
);
1094 return E_OUTOFMEMORY
;
1097 static HRESULT WINAPI
XDNDDATAOBJECT_DAdvise(IDataObject
*dataObject
,
1098 FORMATETC
*formatEtc
, DWORD advf
,
1099 IAdviseSink
*adviseSink
,
1100 DWORD
*pdwConnection
)
1102 FIXME("(%p, %p, %u, %p, %p): stub\n", dataObject
, formatEtc
, advf
,
1103 adviseSink
, pdwConnection
);
1104 return OLE_E_ADVISENOTSUPPORTED
;
1107 static HRESULT WINAPI
XDNDDATAOBJECT_DUnadvise(IDataObject
*dataObject
,
1110 FIXME("(%p, %u): stub\n", dataObject
, dwConnection
);
1111 return OLE_E_ADVISENOTSUPPORTED
;
1114 static HRESULT WINAPI
XDNDDATAOBJECT_EnumDAdvise(IDataObject
*dataObject
,
1115 IEnumSTATDATA
**pEnumAdvise
)
1117 FIXME("(%p, %p): stub\n", dataObject
, pEnumAdvise
);
1118 return OLE_E_ADVISENOTSUPPORTED
;
1121 static IDataObjectVtbl xdndDataObjectVtbl
=
1123 XDNDDATAOBJECT_QueryInterface
,
1124 XDNDDATAOBJECT_AddRef
,
1125 XDNDDATAOBJECT_Release
,
1126 XDNDDATAOBJECT_GetData
,
1127 XDNDDATAOBJECT_GetDataHere
,
1128 XDNDDATAOBJECT_QueryGetData
,
1129 XDNDDATAOBJECT_GetCanonicalFormatEtc
,
1130 XDNDDATAOBJECT_SetData
,
1131 XDNDDATAOBJECT_EnumFormatEtc
,
1132 XDNDDATAOBJECT_DAdvise
,
1133 XDNDDATAOBJECT_DUnadvise
,
1134 XDNDDATAOBJECT_EnumDAdvise
1137 static IDataObject XDNDDataObject
= { &xdndDataObjectVtbl
};