wininet: Use isspaceW() instead of isspace() for WCHARs.
[wine.git] / dlls / winex11.drv / xdnd.c
blob2ab28e43bfe0d8761ba70d977e874df1aa3173ce
1 /*
2 * XDND handler code
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
22 #include "config.h"
23 #include "wine/port.h"
25 #include <string.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <stdarg.h>
30 #include <stdio.h>
32 #define NONAMELESSUNION
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wingdi.h"
37 #include "winuser.h"
39 #define COBJMACROS
40 #include "x11drv.h"
41 #include "shellapi.h"
42 #include "shlobj.h" /* DROPFILES */
43 #include "oleidl.h"
44 #include "objidl.h"
46 #include "wine/unicode.h"
47 #include "wine/debug.h"
48 #include "wine/list.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(xdnd);
52 typedef struct tagXDNDDATA
54 int cf_win;
55 Atom cf_xdnd;
56 HANDLE contents;
57 struct list entry;
58 } XDNDDATA, *LPXDNDDATA;
60 static struct list xdndData = LIST_INIT(xdndData);
61 static POINT XDNDxy = { 0, 0 };
62 static IDataObject XDNDDataObject;
63 static BOOL XDNDAccepted = FALSE;
64 static DWORD XDNDDropEffect = DROPEFFECT_NONE;
65 /* the last window the mouse was over */
66 static HWND XDNDLastTargetWnd;
67 /* might be an ancestor of XDNDLastTargetWnd */
68 static HWND XDNDLastDropTargetWnd;
70 static void X11DRV_XDND_InsertXDNDData( Atom property, UINT format, HANDLE contents );
71 static void X11DRV_XDND_ResolveProperty(Display *display, Window xwin, Time tm,
72 Atom *types, unsigned long count);
73 static BOOL X11DRV_XDND_HasHDROP(void);
74 static HRESULT X11DRV_XDND_SendDropFiles(HWND hwnd);
75 static void X11DRV_XDND_FreeDragDropOp(void);
77 static CRITICAL_SECTION xdnd_cs;
78 static CRITICAL_SECTION_DEBUG critsect_debug =
80 0, 0, &xdnd_cs,
81 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": xdnd_cs") }
84 static CRITICAL_SECTION xdnd_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
87 /* Based on functions in dlls/ole32/ole2.c */
88 static HANDLE get_droptarget_local_handle(HWND hwnd)
90 static const WCHAR prop_marshalleddroptarget[] =
91 {'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};
92 HANDLE handle;
93 HANDLE local_handle = 0;
95 handle = GetPropW(hwnd, prop_marshalleddroptarget);
96 if (handle)
98 DWORD pid;
99 HANDLE process;
101 GetWindowThreadProcessId(hwnd, &pid);
102 process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
103 if (process)
105 DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
106 CloseHandle(process);
109 return local_handle;
112 static HRESULT create_stream_from_map(HANDLE map, IStream **stream)
114 HRESULT hr = E_OUTOFMEMORY;
115 HGLOBAL hmem;
116 void *data;
117 MEMORY_BASIC_INFORMATION info;
119 data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
120 if(!data) return hr;
122 VirtualQuery(data, &info, sizeof(info));
123 TRACE("size %d\n", (int)info.RegionSize);
125 hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize);
126 if(hmem)
128 memcpy(GlobalLock(hmem), data, info.RegionSize);
129 GlobalUnlock(hmem);
130 hr = CreateStreamOnHGlobal(hmem, TRUE, stream);
132 UnmapViewOfFile(data);
133 return hr;
136 static IDropTarget* get_droptarget_pointer(HWND hwnd)
138 IDropTarget *droptarget = NULL;
139 HANDLE map;
140 IStream *stream;
142 map = get_droptarget_local_handle(hwnd);
143 if(!map) return NULL;
145 if(SUCCEEDED(create_stream_from_map(map, &stream)))
147 CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget);
148 IStream_Release(stream);
150 CloseHandle(map);
151 return droptarget;
154 /**************************************************************************
155 * X11DRV_XDND_XdndActionToDROPEFFECT
157 static DWORD X11DRV_XDND_XdndActionToDROPEFFECT(long action)
159 /* In Windows, nothing but the given effects is allowed.
160 * In X the given action is just a hint, and you can always
161 * XdndActionCopy and XdndActionPrivate, so be more permissive. */
162 if (action == x11drv_atom(XdndActionCopy))
163 return DROPEFFECT_COPY;
164 else if (action == x11drv_atom(XdndActionMove))
165 return DROPEFFECT_MOVE | DROPEFFECT_COPY;
166 else if (action == x11drv_atom(XdndActionLink))
167 return DROPEFFECT_LINK | DROPEFFECT_COPY;
168 else if (action == x11drv_atom(XdndActionAsk))
169 /* FIXME: should we somehow ask the user what to do here? */
170 return DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
171 FIXME("unknown action %ld, assuming DROPEFFECT_COPY\n", action);
172 return DROPEFFECT_COPY;
175 /**************************************************************************
176 * X11DRV_XDND_DROPEFFECTToXdndAction
178 static long X11DRV_XDND_DROPEFFECTToXdndAction(DWORD effect)
180 if (effect == DROPEFFECT_COPY)
181 return x11drv_atom(XdndActionCopy);
182 else if (effect == DROPEFFECT_MOVE)
183 return x11drv_atom(XdndActionMove);
184 else if (effect == DROPEFFECT_LINK)
185 return x11drv_atom(XdndActionLink);
186 FIXME("unknown drop effect %u, assuming XdndActionCopy\n", effect);
187 return x11drv_atom(XdndActionCopy);
190 /**************************************************************************
191 * X11DRV_XDND_EnterEvent
193 * Handle an XdndEnter event.
195 void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event )
197 int version;
198 Atom *xdndtypes;
199 unsigned long count = 0;
201 version = (event->data.l[1] & 0xFF000000) >> 24;
202 TRACE("ver(%d) check-XdndTypeList(%ld) data=%ld,%ld,%ld,%ld,%ld\n",
203 version, (event->data.l[1] & 1),
204 event->data.l[0], event->data.l[1], event->data.l[2],
205 event->data.l[3], event->data.l[4]);
207 if (version > WINE_XDND_VERSION)
209 ERR("ignoring unsupported XDND version %d\n", version);
210 return;
213 XDNDAccepted = FALSE;
215 /* If the source supports more than 3 data types we retrieve
216 * the entire list. */
217 if (event->data.l[1] & 1)
219 Atom acttype;
220 int actfmt;
221 unsigned long bytesret;
223 /* Request supported formats from source window */
224 XGetWindowProperty(event->display, event->data.l[0], x11drv_atom(XdndTypeList),
225 0, 65535, FALSE, AnyPropertyType, &acttype, &actfmt, &count,
226 &bytesret, (unsigned char**)&xdndtypes);
228 else
230 count = 3;
231 xdndtypes = (Atom*) &event->data.l[2];
234 if (TRACE_ON(xdnd))
236 unsigned int i;
238 for (i = 0; i < count; i++)
240 if (xdndtypes[i] != 0)
242 char * pn = XGetAtomName(event->display, xdndtypes[i]);
243 TRACE("XDNDEnterAtom %ld: %s\n", xdndtypes[i], pn);
244 XFree(pn);
249 /* Do a one-time data read and cache results */
250 X11DRV_XDND_ResolveProperty(event->display, event->window,
251 event->data.l[1], xdndtypes, count);
253 if (event->data.l[1] & 1)
254 XFree(xdndtypes);
257 /**************************************************************************
258 * X11DRV_XDND_PositionEvent
260 * Handle an XdndPosition event.
262 void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event )
264 XClientMessageEvent e;
265 int accept = 0; /* Assume we're not accepting */
266 IDropTarget *dropTarget = NULL;
267 DWORD effect;
268 POINTL pointl;
269 HWND targetWindow;
270 HRESULT hr;
272 XDNDxy = root_to_virtual_screen( event->data.l[2] >> 16, event->data.l[2] & 0xFFFF );
273 targetWindow = WindowFromPoint(XDNDxy);
275 pointl.x = XDNDxy.x;
276 pointl.y = XDNDxy.y;
277 effect = X11DRV_XDND_XdndActionToDROPEFFECT(event->data.l[4]);
279 if (!XDNDAccepted || XDNDLastTargetWnd != targetWindow)
281 /* Notify OLE of DragEnter. Result determines if we accept */
282 HWND dropTargetWindow;
284 if (XDNDAccepted && XDNDLastDropTargetWnd)
286 dropTarget = get_droptarget_pointer(XDNDLastDropTargetWnd);
287 if (dropTarget)
289 hr = IDropTarget_DragLeave(dropTarget);
290 if (FAILED(hr))
291 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr);
292 IDropTarget_Release(dropTarget);
295 dropTargetWindow = targetWindow;
298 dropTarget = get_droptarget_pointer(dropTargetWindow);
299 } while (dropTarget == NULL && (dropTargetWindow = GetParent(dropTargetWindow)) != NULL);
300 XDNDLastTargetWnd = targetWindow;
301 XDNDLastDropTargetWnd = dropTargetWindow;
302 if (dropTarget)
304 DWORD effect_ignore = effect;
305 hr = IDropTarget_DragEnter(dropTarget, &XDNDDataObject,
306 MK_LBUTTON, pointl, &effect_ignore);
307 if (hr == S_OK)
309 XDNDAccepted = TRUE;
310 TRACE("the application accepted the drop (effect = %d)\n", effect_ignore);
312 else
314 XDNDAccepted = FALSE;
315 WARN("IDropTarget_DragEnter failed, error 0x%08X\n", hr);
317 IDropTarget_Release(dropTarget);
320 if (XDNDAccepted && XDNDLastTargetWnd == targetWindow)
322 /* If drag accepted notify OLE of DragOver */
323 dropTarget = get_droptarget_pointer(XDNDLastDropTargetWnd);
324 if (dropTarget)
326 hr = IDropTarget_DragOver(dropTarget, MK_LBUTTON, pointl, &effect);
327 if (hr == S_OK)
328 XDNDDropEffect = effect;
329 else
330 WARN("IDropTarget_DragOver failed, error 0x%08X\n", hr);
331 IDropTarget_Release(dropTarget);
335 if (XDNDAccepted)
336 accept = 1;
337 else if ((GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) &&
338 X11DRV_XDND_HasHDROP())
340 accept = 1;
341 effect = DROPEFFECT_COPY;
344 TRACE("actionRequested(%ld) accept(%d) chosen(0x%x) at x(%d),y(%d)\n",
345 event->data.l[4], accept, effect, XDNDxy.x, XDNDxy.y);
348 * Let source know if we're accepting the drop by
349 * sending a status message.
351 e.type = ClientMessage;
352 e.display = event->display;
353 e.window = event->data.l[0];
354 e.message_type = x11drv_atom(XdndStatus);
355 e.format = 32;
356 e.data.l[0] = event->window;
357 e.data.l[1] = accept;
358 e.data.l[2] = 0; /* Empty Rect */
359 e.data.l[3] = 0; /* Empty Rect */
360 if (accept)
361 e.data.l[4] = X11DRV_XDND_DROPEFFECTToXdndAction(effect);
362 else
363 e.data.l[4] = None;
364 XSendEvent(event->display, event->data.l[0], False, NoEventMask, (XEvent*)&e);
367 /**************************************************************************
368 * X11DRV_XDND_DropEvent
370 * Handle an XdndDrop event.
372 void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event )
374 XClientMessageEvent e;
375 IDropTarget *dropTarget;
376 DWORD effect = XDNDDropEffect;
377 int accept = 0; /* Assume we're not accepting */
378 BOOL drop_file = TRUE;
380 /* Notify OLE of Drop */
381 if (XDNDAccepted)
383 dropTarget = get_droptarget_pointer(XDNDLastDropTargetWnd);
384 if (dropTarget && effect!=DROPEFFECT_NONE)
386 HRESULT hr;
387 POINTL pointl;
389 pointl.x = XDNDxy.x;
390 pointl.y = XDNDxy.y;
391 hr = IDropTarget_Drop(dropTarget, &XDNDDataObject, MK_LBUTTON,
392 pointl, &effect);
393 if (hr == S_OK)
395 if (effect != DROPEFFECT_NONE)
397 TRACE("drop succeeded\n");
398 accept = 1;
399 drop_file = FALSE;
401 else
402 TRACE("the application refused the drop\n");
404 else if (FAILED(hr))
405 WARN("drop failed, error 0x%08X\n", hr);
406 else
408 WARN("drop returned 0x%08X\n", hr);
409 drop_file = FALSE;
411 IDropTarget_Release(dropTarget);
413 else if (dropTarget)
415 HRESULT hr = IDropTarget_DragLeave(dropTarget);
416 if (FAILED(hr))
417 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr);
418 IDropTarget_Release(dropTarget);
422 if (drop_file)
424 /* Only send WM_DROPFILES if Drop didn't succeed or DROPEFFECT_NONE was set.
425 * Doing both causes winamp to duplicate the dropped files (#29081) */
426 if ((GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) &&
427 X11DRV_XDND_HasHDROP())
429 HRESULT hr = X11DRV_XDND_SendDropFiles( hWnd );
430 if (SUCCEEDED(hr))
432 accept = 1;
433 effect = DROPEFFECT_COPY;
438 TRACE("effectRequested(0x%x) accept(%d) performed(0x%x) at x(%d),y(%d)\n",
439 XDNDDropEffect, accept, effect, XDNDxy.x, XDNDxy.y);
441 X11DRV_XDND_FreeDragDropOp();
443 /* Tell the target we are finished. */
444 memset(&e, 0, sizeof(e));
445 e.type = ClientMessage;
446 e.display = event->display;
447 e.window = event->data.l[0];
448 e.message_type = x11drv_atom(XdndFinished);
449 e.format = 32;
450 e.data.l[0] = event->window;
451 e.data.l[1] = accept;
452 if (accept)
453 e.data.l[2] = X11DRV_XDND_DROPEFFECTToXdndAction(effect);
454 else
455 e.data.l[2] = None;
456 XSendEvent(event->display, event->data.l[0], False, NoEventMask, (XEvent*)&e);
459 /**************************************************************************
460 * X11DRV_XDND_LeaveEvent
462 * Handle an XdndLeave event.
464 void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event )
466 IDropTarget *dropTarget;
468 TRACE("DND Operation canceled\n");
470 /* Notify OLE of DragLeave */
471 if (XDNDAccepted)
473 dropTarget = get_droptarget_pointer(XDNDLastDropTargetWnd);
474 if (dropTarget)
476 HRESULT hr = IDropTarget_DragLeave(dropTarget);
477 if (FAILED(hr))
478 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr);
479 IDropTarget_Release(dropTarget);
483 X11DRV_XDND_FreeDragDropOp();
487 /**************************************************************************
488 * X11DRV_XDND_ResolveProperty
490 * Resolve all MIME types to windows clipboard formats. All data is cached.
492 static void X11DRV_XDND_ResolveProperty(Display *display, Window xwin, Time tm,
493 Atom *types, unsigned long count)
495 XDNDDATA *current, *next;
496 BOOL haveHDROP = FALSE;
498 TRACE("count(%ld)\n", count);
500 X11DRV_XDND_FreeDragDropOp(); /* Clear previously cached data */
502 X11DRV_CLIPBOARD_ImportSelection( display, xwin, x11drv_atom(XdndSelection),
503 types, count, X11DRV_XDND_InsertXDNDData );
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)
512 haveHDROP = TRUE;
513 break;
516 if (haveHDROP)
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(&current->entry);
523 GlobalFree(current->contents);
524 HeapFree(GetProcessHeap(), 0, current);
531 /**************************************************************************
532 * X11DRV_XDND_InsertXDNDData
534 * Cache available XDND property
536 static void X11DRV_XDND_InsertXDNDData( Atom property, UINT format, HANDLE contents )
538 LPXDNDDATA current = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(XDNDDATA));
540 if (current)
542 EnterCriticalSection(&xdnd_cs);
543 current->cf_xdnd = property;
544 current->cf_win = format;
545 current->contents = contents;
546 list_add_tail(&xdndData, &current->entry);
547 LeaveCriticalSection(&xdnd_cs);
552 /**************************************************************************
553 * X11DRV_XDND_HasHDROP
555 static BOOL X11DRV_XDND_HasHDROP(void)
557 LPXDNDDATA current = NULL;
558 BOOL found = FALSE;
560 EnterCriticalSection(&xdnd_cs);
562 /* Find CF_HDROP type if any */
563 LIST_FOR_EACH_ENTRY(current, &xdndData, XDNDDATA, entry)
565 if (current->cf_win == CF_HDROP)
567 found = TRUE;
568 break;
572 LeaveCriticalSection(&xdnd_cs);
574 return found;
577 /**************************************************************************
578 * X11DRV_XDND_SendDropFiles
580 static HRESULT X11DRV_XDND_SendDropFiles(HWND hwnd)
582 HRESULT hr;
583 LPXDNDDATA current = NULL;
584 BOOL found = FALSE;
586 EnterCriticalSection(&xdnd_cs);
588 LIST_FOR_EACH_ENTRY(current, &xdndData, XDNDDATA, entry)
590 if (current->cf_win == CF_HDROP)
592 found = TRUE;
593 break;
596 if (found)
598 HGLOBAL dropHandle = GlobalAlloc(GMEM_FIXED, GlobalSize(current->contents));
599 if (dropHandle)
601 DROPFILES *lpDrop = GlobalLock(dropHandle);
602 memcpy(lpDrop, GlobalLock(current->contents), GlobalSize(current->contents));
603 GlobalUnlock(current->contents);
604 lpDrop->pt.x = XDNDxy.x;
605 lpDrop->pt.y = XDNDxy.y;
606 lpDrop->fNC = !ScreenToClient(hwnd, &lpDrop->pt);
607 TRACE("Sending WM_DROPFILES: hWnd=0x%p, fNC=%d, x=%d, y=%d, files=%p(%s)\n", hwnd,
608 lpDrop->fNC, lpDrop->pt.x, lpDrop->pt.y, ((char*)lpDrop) + lpDrop->pFiles,
609 debugstr_w((WCHAR*)(((char*)lpDrop) + lpDrop->pFiles)));
610 GlobalUnlock(dropHandle);
611 if (PostMessageW(hwnd, WM_DROPFILES, (WPARAM)dropHandle, 0))
612 hr = S_OK;
613 else
615 hr = HRESULT_FROM_WIN32(GetLastError());
616 GlobalFree(dropHandle);
619 else
620 hr = HRESULT_FROM_WIN32(GetLastError());
622 else
623 hr = E_FAIL;
625 LeaveCriticalSection(&xdnd_cs);
627 return hr;
631 /**************************************************************************
632 * X11DRV_XDND_FreeDragDropOp
634 static void X11DRV_XDND_FreeDragDropOp(void)
636 LPXDNDDATA next;
637 LPXDNDDATA current;
639 TRACE("\n");
641 EnterCriticalSection(&xdnd_cs);
643 /** Free data cache */
644 LIST_FOR_EACH_ENTRY_SAFE(current, next, &xdndData, XDNDDATA, entry)
646 list_remove(&current->entry);
647 GlobalFree(current->contents);
648 HeapFree(GetProcessHeap(), 0, current);
651 XDNDxy.x = XDNDxy.y = 0;
652 XDNDLastTargetWnd = NULL;
653 XDNDLastDropTargetWnd = NULL;
654 XDNDAccepted = FALSE;
656 LeaveCriticalSection(&xdnd_cs);
660 /**************************************************************************
661 * X11DRV_XDND_DescribeClipboardFormat
663 static void X11DRV_XDND_DescribeClipboardFormat(int cfFormat, char *buffer, int size)
665 #define D(x) case x: lstrcpynA(buffer, #x, size); return;
666 switch (cfFormat)
668 D(CF_TEXT)
669 D(CF_BITMAP)
670 D(CF_METAFILEPICT)
671 D(CF_SYLK)
672 D(CF_DIF)
673 D(CF_TIFF)
674 D(CF_OEMTEXT)
675 D(CF_DIB)
676 D(CF_PALETTE)
677 D(CF_PENDATA)
678 D(CF_RIFF)
679 D(CF_WAVE)
680 D(CF_UNICODETEXT)
681 D(CF_ENHMETAFILE)
682 D(CF_HDROP)
683 D(CF_LOCALE)
684 D(CF_DIBV5)
686 #undef D
688 if (CF_PRIVATEFIRST <= cfFormat && cfFormat <= CF_PRIVATELAST)
690 lstrcpynA(buffer, "some private object", size);
691 return;
693 if (CF_GDIOBJFIRST <= cfFormat && cfFormat <= CF_GDIOBJLAST)
695 lstrcpynA(buffer, "some GDI object", size);
696 return;
699 GetClipboardFormatNameA(cfFormat, buffer, size);
703 /* The IDataObject singleton we feed to OLE follows */
705 static HRESULT WINAPI XDNDDATAOBJECT_QueryInterface(IDataObject *dataObject,
706 REFIID riid, void **ppvObject)
708 TRACE("(%p, %s, %p)\n", dataObject, debugstr_guid(riid), ppvObject);
709 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDataObject))
711 *ppvObject = dataObject;
712 IDataObject_AddRef(dataObject);
713 return S_OK;
715 *ppvObject = NULL;
716 return E_NOINTERFACE;
719 static ULONG WINAPI XDNDDATAOBJECT_AddRef(IDataObject *dataObject)
721 TRACE("(%p)\n", dataObject);
722 return 2;
725 static ULONG WINAPI XDNDDATAOBJECT_Release(IDataObject *dataObject)
727 TRACE("(%p)\n", dataObject);
728 return 1;
731 static HRESULT WINAPI XDNDDATAOBJECT_GetData(IDataObject *dataObject,
732 FORMATETC *formatEtc,
733 STGMEDIUM *pMedium)
735 HRESULT hr;
736 char formatDesc[1024];
738 TRACE("(%p, %p, %p)\n", dataObject, formatEtc, pMedium);
739 X11DRV_XDND_DescribeClipboardFormat(formatEtc->cfFormat,
740 formatDesc, sizeof(formatDesc));
741 TRACE("application is looking for %s\n", formatDesc);
743 hr = IDataObject_QueryGetData(dataObject, formatEtc);
744 if (SUCCEEDED(hr))
746 XDNDDATA *current;
747 LIST_FOR_EACH_ENTRY(current, &xdndData, XDNDDATA, entry)
749 if (current->cf_win == formatEtc->cfFormat)
751 pMedium->tymed = TYMED_HGLOBAL;
752 pMedium->u.hGlobal = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, GlobalSize(current->contents));
753 if (pMedium->u.hGlobal == NULL)
754 return E_OUTOFMEMORY;
755 memcpy(GlobalLock(pMedium->u.hGlobal), GlobalLock(current->contents), GlobalSize(current->contents));
756 GlobalUnlock(pMedium->u.hGlobal);
757 GlobalUnlock(current->contents);
758 pMedium->pUnkForRelease = 0;
759 return S_OK;
763 return hr;
766 static HRESULT WINAPI XDNDDATAOBJECT_GetDataHere(IDataObject *dataObject,
767 FORMATETC *formatEtc,
768 STGMEDIUM *pMedium)
770 FIXME("(%p, %p, %p): stub\n", dataObject, formatEtc, pMedium);
771 return DATA_E_FORMATETC;
774 static HRESULT WINAPI XDNDDATAOBJECT_QueryGetData(IDataObject *dataObject,
775 FORMATETC *formatEtc)
777 char formatDesc[1024];
778 XDNDDATA *current;
780 TRACE("(%p, %p={.tymed=0x%x, .dwAspect=%d, .cfFormat=%d}\n",
781 dataObject, formatEtc, formatEtc->tymed, formatEtc->dwAspect, formatEtc->cfFormat);
782 X11DRV_XDND_DescribeClipboardFormat(formatEtc->cfFormat, formatDesc, sizeof(formatDesc));
784 if (formatEtc->tymed && !(formatEtc->tymed & TYMED_HGLOBAL))
786 FIXME("only HGLOBAL medium types supported right now\n");
787 return DV_E_TYMED;
789 if (formatEtc->dwAspect != DVASPECT_CONTENT)
791 FIXME("only the content aspect is supported right now\n");
792 return E_NOTIMPL;
795 LIST_FOR_EACH_ENTRY(current, &xdndData, XDNDDATA, entry)
797 if (current->cf_win == formatEtc->cfFormat)
799 TRACE("application found %s\n", formatDesc);
800 return S_OK;
803 TRACE("application didn't find %s\n", formatDesc);
804 return DV_E_FORMATETC;
807 static HRESULT WINAPI XDNDDATAOBJECT_GetCanonicalFormatEtc(IDataObject *dataObject,
808 FORMATETC *formatEtc,
809 FORMATETC *formatEtcOut)
811 FIXME("(%p, %p, %p): stub\n", dataObject, formatEtc, formatEtcOut);
812 formatEtcOut->ptd = NULL;
813 return E_NOTIMPL;
816 static HRESULT WINAPI XDNDDATAOBJECT_SetData(IDataObject *dataObject,
817 FORMATETC *formatEtc,
818 STGMEDIUM *pMedium, BOOL fRelease)
820 FIXME("(%p, %p, %p, %s): stub\n", dataObject, formatEtc,
821 pMedium, fRelease?"TRUE":"FALSE");
822 return E_NOTIMPL;
825 static HRESULT WINAPI XDNDDATAOBJECT_EnumFormatEtc(IDataObject *dataObject,
826 DWORD dwDirection,
827 IEnumFORMATETC **ppEnumFormatEtc)
829 DWORD count;
830 FORMATETC *formats;
832 TRACE("(%p, %u, %p)\n", dataObject, dwDirection, ppEnumFormatEtc);
834 if (dwDirection != DATADIR_GET)
836 FIXME("only the get direction is implemented\n");
837 return E_NOTIMPL;
840 count = list_count(&xdndData);
841 formats = HeapAlloc(GetProcessHeap(), 0, count * sizeof(FORMATETC));
842 if (formats)
844 XDNDDATA *current;
845 DWORD i = 0;
846 HRESULT hr;
847 LIST_FOR_EACH_ENTRY(current, &xdndData, XDNDDATA, entry)
849 formats[i].cfFormat = current->cf_win;
850 formats[i].ptd = NULL;
851 formats[i].dwAspect = DVASPECT_CONTENT;
852 formats[i].lindex = -1;
853 formats[i].tymed = TYMED_HGLOBAL;
854 i++;
856 hr = SHCreateStdEnumFmtEtc(count, formats, ppEnumFormatEtc);
857 HeapFree(GetProcessHeap(), 0, formats);
858 return hr;
860 else
861 return E_OUTOFMEMORY;
864 static HRESULT WINAPI XDNDDATAOBJECT_DAdvise(IDataObject *dataObject,
865 FORMATETC *formatEtc, DWORD advf,
866 IAdviseSink *adviseSink,
867 DWORD *pdwConnection)
869 FIXME("(%p, %p, %u, %p, %p): stub\n", dataObject, formatEtc, advf,
870 adviseSink, pdwConnection);
871 return OLE_E_ADVISENOTSUPPORTED;
874 static HRESULT WINAPI XDNDDATAOBJECT_DUnadvise(IDataObject *dataObject,
875 DWORD dwConnection)
877 FIXME("(%p, %u): stub\n", dataObject, dwConnection);
878 return OLE_E_ADVISENOTSUPPORTED;
881 static HRESULT WINAPI XDNDDATAOBJECT_EnumDAdvise(IDataObject *dataObject,
882 IEnumSTATDATA **pEnumAdvise)
884 FIXME("(%p, %p): stub\n", dataObject, pEnumAdvise);
885 return OLE_E_ADVISENOTSUPPORTED;
888 static IDataObjectVtbl xdndDataObjectVtbl =
890 XDNDDATAOBJECT_QueryInterface,
891 XDNDDATAOBJECT_AddRef,
892 XDNDDATAOBJECT_Release,
893 XDNDDATAOBJECT_GetData,
894 XDNDDATAOBJECT_GetDataHere,
895 XDNDDATAOBJECT_QueryGetData,
896 XDNDDATAOBJECT_GetCanonicalFormatEtc,
897 XDNDDATAOBJECT_SetData,
898 XDNDDATAOBJECT_EnumFormatEtc,
899 XDNDDATAOBJECT_DAdvise,
900 XDNDDATAOBJECT_DUnadvise,
901 XDNDDATAOBJECT_EnumDAdvise
904 static IDataObject XDNDDataObject = { &xdndDataObjectVtbl };