windowscodecs: Correctly set pixel format of uncompressed DDS images.
[wine.git] / dlls / winex11.drv / xdnd.c
blob0cd2ad889244c01747844f5859dd37f37f22bef2
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 /* Recursively searches for a window on given coordinates in a drag&drop specific manner.
259 * Don't use WindowFromPoint instead, because it omits the STATIC and transparent
260 * windows, but they can be a valid drop targets if have WS_EX_ACCEPTFILES set.
262 static HWND window_from_point_dnd(HWND hwnd, POINT point)
264 HWND child;
265 ScreenToClient(hwnd, &point);
266 while ((child = ChildWindowFromPointEx(hwnd, point, CWP_SKIPDISABLED | CWP_SKIPINVISIBLE)) && child != hwnd)
268 MapWindowPoints(hwnd, child, &point, 1);
269 hwnd = child;
272 return hwnd;
275 /* Returns the first window down the hierarchy that has WS_EX_ACCEPTFILES set or
276 * returns NULL, if such window does not exists.
278 static HWND window_accepting_files(HWND hwnd)
280 while (hwnd && !(GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_ACCEPTFILES))
281 /* MUST to be GetParent, not GetAncestor, because the owner window
282 * (with WS_EX_ACCEPTFILES) of a window with WS_POPUP is a valid
283 * drop target. GetParent works exactly this way!
285 hwnd = GetParent(hwnd);
286 return hwnd;
289 /**************************************************************************
290 * X11DRV_XDND_PositionEvent
292 * Handle an XdndPosition event.
294 void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event )
296 XClientMessageEvent e;
297 int accept = 0; /* Assume we're not accepting */
298 IDropTarget *dropTarget = NULL;
299 DWORD effect;
300 POINTL pointl;
301 HWND targetWindow;
302 HRESULT hr;
304 XDNDxy = root_to_virtual_screen( event->data.l[2] >> 16, event->data.l[2] & 0xFFFF );
305 targetWindow = window_from_point_dnd(hWnd, XDNDxy);
307 pointl.x = XDNDxy.x;
308 pointl.y = XDNDxy.y;
309 effect = X11DRV_XDND_XdndActionToDROPEFFECT(event->data.l[4]);
311 if (!XDNDAccepted || XDNDLastTargetWnd != targetWindow)
313 /* Notify OLE of DragEnter. Result determines if we accept */
314 HWND dropTargetWindow;
316 if (XDNDAccepted && XDNDLastDropTargetWnd)
318 dropTarget = get_droptarget_pointer(XDNDLastDropTargetWnd);
319 if (dropTarget)
321 hr = IDropTarget_DragLeave(dropTarget);
322 if (FAILED(hr))
323 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr);
324 IDropTarget_Release(dropTarget);
327 dropTargetWindow = targetWindow;
330 dropTarget = get_droptarget_pointer(dropTargetWindow);
331 } while (dropTarget == NULL && (dropTargetWindow = GetParent(dropTargetWindow)) != NULL);
332 XDNDLastTargetWnd = targetWindow;
333 XDNDLastDropTargetWnd = dropTargetWindow;
334 if (dropTarget)
336 DWORD effect_ignore = effect;
337 hr = IDropTarget_DragEnter(dropTarget, &XDNDDataObject,
338 MK_LBUTTON, pointl, &effect_ignore);
339 if (hr == S_OK)
341 XDNDAccepted = TRUE;
342 TRACE("the application accepted the drop (effect = %d)\n", effect_ignore);
344 else
346 XDNDAccepted = FALSE;
347 WARN("IDropTarget_DragEnter failed, error 0x%08X\n", hr);
349 IDropTarget_Release(dropTarget);
352 if (XDNDAccepted && XDNDLastTargetWnd == targetWindow)
354 /* If drag accepted notify OLE of DragOver */
355 dropTarget = get_droptarget_pointer(XDNDLastDropTargetWnd);
356 if (dropTarget)
358 hr = IDropTarget_DragOver(dropTarget, MK_LBUTTON, pointl, &effect);
359 if (hr == S_OK)
360 XDNDDropEffect = effect;
361 else
362 WARN("IDropTarget_DragOver failed, error 0x%08X\n", hr);
363 IDropTarget_Release(dropTarget);
367 if (XDNDAccepted)
368 accept = 1;
369 else
371 /* fallback search for window able to accept these files. */
373 if (window_accepting_files(targetWindow) && X11DRV_XDND_HasHDROP())
375 accept = 1;
376 effect = DROPEFFECT_COPY;
380 TRACE("actionRequested(%ld) accept(%d) chosen(0x%x) at x(%d),y(%d)\n",
381 event->data.l[4], accept, effect, XDNDxy.x, XDNDxy.y);
384 * Let source know if we're accepting the drop by
385 * sending a status message.
387 e.type = ClientMessage;
388 e.display = event->display;
389 e.window = event->data.l[0];
390 e.message_type = x11drv_atom(XdndStatus);
391 e.format = 32;
392 e.data.l[0] = event->window;
393 e.data.l[1] = accept;
394 e.data.l[2] = 0; /* Empty Rect */
395 e.data.l[3] = 0; /* Empty Rect */
396 if (accept)
397 e.data.l[4] = X11DRV_XDND_DROPEFFECTToXdndAction(effect);
398 else
399 e.data.l[4] = None;
400 XSendEvent(event->display, event->data.l[0], False, NoEventMask, (XEvent*)&e);
403 /**************************************************************************
404 * X11DRV_XDND_DropEvent
406 * Handle an XdndDrop event.
408 void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event )
410 XClientMessageEvent e;
411 IDropTarget *dropTarget;
412 DWORD effect = XDNDDropEffect;
413 int accept = 0; /* Assume we're not accepting */
414 BOOL drop_file = TRUE;
416 /* Notify OLE of Drop */
417 if (XDNDAccepted)
419 dropTarget = get_droptarget_pointer(XDNDLastDropTargetWnd);
420 if (dropTarget && effect!=DROPEFFECT_NONE)
422 HRESULT hr;
423 POINTL pointl;
425 pointl.x = XDNDxy.x;
426 pointl.y = XDNDxy.y;
427 hr = IDropTarget_Drop(dropTarget, &XDNDDataObject, MK_LBUTTON,
428 pointl, &effect);
429 if (hr == S_OK)
431 if (effect != DROPEFFECT_NONE)
433 TRACE("drop succeeded\n");
434 accept = 1;
435 drop_file = FALSE;
437 else
438 TRACE("the application refused the drop\n");
440 else if (FAILED(hr))
441 WARN("drop failed, error 0x%08X\n", hr);
442 else
444 WARN("drop returned 0x%08X\n", hr);
445 drop_file = FALSE;
447 IDropTarget_Release(dropTarget);
449 else if (dropTarget)
451 HRESULT hr = IDropTarget_DragLeave(dropTarget);
452 if (FAILED(hr))
453 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr);
454 IDropTarget_Release(dropTarget);
458 if (drop_file)
460 /* Only send WM_DROPFILES if Drop didn't succeed or DROPEFFECT_NONE was set.
461 * Doing both causes winamp to duplicate the dropped files (#29081) */
463 HWND hwnd_drop = window_accepting_files(window_from_point_dnd(hWnd, XDNDxy));
465 if (hwnd_drop && X11DRV_XDND_HasHDROP())
467 HRESULT hr = X11DRV_XDND_SendDropFiles(hwnd_drop);
468 if (SUCCEEDED(hr))
470 accept = 1;
471 effect = DROPEFFECT_COPY;
476 TRACE("effectRequested(0x%x) accept(%d) performed(0x%x) at x(%d),y(%d)\n",
477 XDNDDropEffect, accept, effect, XDNDxy.x, XDNDxy.y);
479 X11DRV_XDND_FreeDragDropOp();
481 /* Tell the target we are finished. */
482 memset(&e, 0, sizeof(e));
483 e.type = ClientMessage;
484 e.display = event->display;
485 e.window = event->data.l[0];
486 e.message_type = x11drv_atom(XdndFinished);
487 e.format = 32;
488 e.data.l[0] = event->window;
489 e.data.l[1] = accept;
490 if (accept)
491 e.data.l[2] = X11DRV_XDND_DROPEFFECTToXdndAction(effect);
492 else
493 e.data.l[2] = None;
494 XSendEvent(event->display, event->data.l[0], False, NoEventMask, (XEvent*)&e);
497 /**************************************************************************
498 * X11DRV_XDND_LeaveEvent
500 * Handle an XdndLeave event.
502 void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event )
504 IDropTarget *dropTarget;
506 TRACE("DND Operation canceled\n");
508 /* Notify OLE of DragLeave */
509 if (XDNDAccepted)
511 dropTarget = get_droptarget_pointer(XDNDLastDropTargetWnd);
512 if (dropTarget)
514 HRESULT hr = IDropTarget_DragLeave(dropTarget);
515 if (FAILED(hr))
516 WARN("IDropTarget_DragLeave failed, error 0x%08X\n", hr);
517 IDropTarget_Release(dropTarget);
521 X11DRV_XDND_FreeDragDropOp();
525 /**************************************************************************
526 * X11DRV_XDND_ResolveProperty
528 * Resolve all MIME types to windows clipboard formats. All data is cached.
530 static void X11DRV_XDND_ResolveProperty(Display *display, Window xwin, Time tm,
531 Atom *types, unsigned long count)
533 XDNDDATA *current, *next;
534 BOOL haveHDROP = FALSE;
536 TRACE("count(%ld)\n", count);
538 X11DRV_XDND_FreeDragDropOp(); /* Clear previously cached data */
540 X11DRV_CLIPBOARD_ImportSelection( display, xwin, x11drv_atom(XdndSelection),
541 types, count, X11DRV_XDND_InsertXDNDData );
543 /* On Windows when there is a CF_HDROP, there are no other CF_ formats.
544 * foobar2000 relies on this (spaces -> %20's without it).
546 LIST_FOR_EACH_ENTRY(current, &xdndData, XDNDDATA, entry)
548 if (current->cf_win == CF_HDROP)
550 haveHDROP = TRUE;
551 break;
554 if (haveHDROP)
556 LIST_FOR_EACH_ENTRY_SAFE(current, next, &xdndData, XDNDDATA, entry)
558 if (current->cf_win != CF_HDROP && current->cf_win < CF_MAX)
560 list_remove(&current->entry);
561 GlobalFree(current->contents);
562 HeapFree(GetProcessHeap(), 0, current);
569 /**************************************************************************
570 * X11DRV_XDND_InsertXDNDData
572 * Cache available XDND property
574 static void X11DRV_XDND_InsertXDNDData( Atom property, UINT format, HANDLE contents )
576 LPXDNDDATA current = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(XDNDDATA));
578 if (current)
580 EnterCriticalSection(&xdnd_cs);
581 current->cf_xdnd = property;
582 current->cf_win = format;
583 current->contents = contents;
584 list_add_tail(&xdndData, &current->entry);
585 LeaveCriticalSection(&xdnd_cs);
590 /**************************************************************************
591 * X11DRV_XDND_HasHDROP
593 static BOOL X11DRV_XDND_HasHDROP(void)
595 LPXDNDDATA current = NULL;
596 BOOL found = FALSE;
598 EnterCriticalSection(&xdnd_cs);
600 /* Find CF_HDROP type if any */
601 LIST_FOR_EACH_ENTRY(current, &xdndData, XDNDDATA, entry)
603 if (current->cf_win == CF_HDROP)
605 found = TRUE;
606 break;
610 LeaveCriticalSection(&xdnd_cs);
612 return found;
615 /**************************************************************************
616 * X11DRV_XDND_SendDropFiles
618 static HRESULT X11DRV_XDND_SendDropFiles(HWND hwnd)
620 HRESULT hr;
621 LPXDNDDATA current = NULL;
622 BOOL found = FALSE;
624 EnterCriticalSection(&xdnd_cs);
626 LIST_FOR_EACH_ENTRY(current, &xdndData, XDNDDATA, entry)
628 if (current->cf_win == CF_HDROP)
630 found = TRUE;
631 break;
634 if (found)
636 HGLOBAL dropHandle = GlobalAlloc(GMEM_FIXED, GlobalSize(current->contents));
637 if (dropHandle)
639 RECT rect;
640 DROPFILES *lpDrop = GlobalLock(dropHandle);
641 memcpy(lpDrop, GlobalLock(current->contents), GlobalSize(current->contents));
642 GlobalUnlock(current->contents);
643 lpDrop->pt.x = XDNDxy.x;
644 lpDrop->pt.y = XDNDxy.y;
645 lpDrop->fNC = !(ScreenToClient(hwnd, &lpDrop->pt) &&
646 GetClientRect(hwnd, &rect) &&
647 PtInRect(&rect, lpDrop->pt));
648 TRACE("Sending WM_DROPFILES: hWnd=0x%p, fNC=%d, x=%d, y=%d, files=%p(%s)\n", hwnd,
649 lpDrop->fNC, lpDrop->pt.x, lpDrop->pt.y, ((char*)lpDrop) + lpDrop->pFiles,
650 debugstr_w((WCHAR*)(((char*)lpDrop) + lpDrop->pFiles)));
651 GlobalUnlock(dropHandle);
652 if (PostMessageW(hwnd, WM_DROPFILES, (WPARAM)dropHandle, 0))
653 hr = S_OK;
654 else
656 hr = HRESULT_FROM_WIN32(GetLastError());
657 GlobalFree(dropHandle);
660 else
661 hr = HRESULT_FROM_WIN32(GetLastError());
663 else
664 hr = E_FAIL;
666 LeaveCriticalSection(&xdnd_cs);
668 return hr;
672 /**************************************************************************
673 * X11DRV_XDND_FreeDragDropOp
675 static void X11DRV_XDND_FreeDragDropOp(void)
677 LPXDNDDATA next;
678 LPXDNDDATA current;
680 TRACE("\n");
682 EnterCriticalSection(&xdnd_cs);
684 /** Free data cache */
685 LIST_FOR_EACH_ENTRY_SAFE(current, next, &xdndData, XDNDDATA, entry)
687 list_remove(&current->entry);
688 GlobalFree(current->contents);
689 HeapFree(GetProcessHeap(), 0, current);
692 XDNDxy.x = XDNDxy.y = 0;
693 XDNDLastTargetWnd = NULL;
694 XDNDLastDropTargetWnd = NULL;
695 XDNDAccepted = FALSE;
697 LeaveCriticalSection(&xdnd_cs);
701 /**************************************************************************
702 * X11DRV_XDND_DescribeClipboardFormat
704 static void X11DRV_XDND_DescribeClipboardFormat(int cfFormat, char *buffer, int size)
706 #define D(x) case x: lstrcpynA(buffer, #x, size); return;
707 switch (cfFormat)
709 D(CF_TEXT)
710 D(CF_BITMAP)
711 D(CF_METAFILEPICT)
712 D(CF_SYLK)
713 D(CF_DIF)
714 D(CF_TIFF)
715 D(CF_OEMTEXT)
716 D(CF_DIB)
717 D(CF_PALETTE)
718 D(CF_PENDATA)
719 D(CF_RIFF)
720 D(CF_WAVE)
721 D(CF_UNICODETEXT)
722 D(CF_ENHMETAFILE)
723 D(CF_HDROP)
724 D(CF_LOCALE)
725 D(CF_DIBV5)
727 #undef D
729 if (CF_PRIVATEFIRST <= cfFormat && cfFormat <= CF_PRIVATELAST)
731 lstrcpynA(buffer, "some private object", size);
732 return;
734 if (CF_GDIOBJFIRST <= cfFormat && cfFormat <= CF_GDIOBJLAST)
736 lstrcpynA(buffer, "some GDI object", size);
737 return;
740 GetClipboardFormatNameA(cfFormat, buffer, size);
744 /* The IDataObject singleton we feed to OLE follows */
746 static HRESULT WINAPI XDNDDATAOBJECT_QueryInterface(IDataObject *dataObject,
747 REFIID riid, void **ppvObject)
749 TRACE("(%p, %s, %p)\n", dataObject, debugstr_guid(riid), ppvObject);
750 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDataObject))
752 *ppvObject = dataObject;
753 IDataObject_AddRef(dataObject);
754 return S_OK;
756 *ppvObject = NULL;
757 return E_NOINTERFACE;
760 static ULONG WINAPI XDNDDATAOBJECT_AddRef(IDataObject *dataObject)
762 TRACE("(%p)\n", dataObject);
763 return 2;
766 static ULONG WINAPI XDNDDATAOBJECT_Release(IDataObject *dataObject)
768 TRACE("(%p)\n", dataObject);
769 return 1;
772 static HRESULT WINAPI XDNDDATAOBJECT_GetData(IDataObject *dataObject,
773 FORMATETC *formatEtc,
774 STGMEDIUM *pMedium)
776 HRESULT hr;
777 char formatDesc[1024];
779 TRACE("(%p, %p, %p)\n", dataObject, formatEtc, pMedium);
780 X11DRV_XDND_DescribeClipboardFormat(formatEtc->cfFormat,
781 formatDesc, sizeof(formatDesc));
782 TRACE("application is looking for %s\n", formatDesc);
784 hr = IDataObject_QueryGetData(dataObject, formatEtc);
785 if (SUCCEEDED(hr))
787 XDNDDATA *current;
788 LIST_FOR_EACH_ENTRY(current, &xdndData, XDNDDATA, entry)
790 if (current->cf_win == formatEtc->cfFormat)
792 pMedium->tymed = TYMED_HGLOBAL;
793 pMedium->u.hGlobal = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, GlobalSize(current->contents));
794 if (pMedium->u.hGlobal == NULL)
795 return E_OUTOFMEMORY;
796 memcpy(GlobalLock(pMedium->u.hGlobal), GlobalLock(current->contents), GlobalSize(current->contents));
797 GlobalUnlock(pMedium->u.hGlobal);
798 GlobalUnlock(current->contents);
799 pMedium->pUnkForRelease = 0;
800 return S_OK;
804 return hr;
807 static HRESULT WINAPI XDNDDATAOBJECT_GetDataHere(IDataObject *dataObject,
808 FORMATETC *formatEtc,
809 STGMEDIUM *pMedium)
811 FIXME("(%p, %p, %p): stub\n", dataObject, formatEtc, pMedium);
812 return DATA_E_FORMATETC;
815 static HRESULT WINAPI XDNDDATAOBJECT_QueryGetData(IDataObject *dataObject,
816 FORMATETC *formatEtc)
818 char formatDesc[1024];
819 XDNDDATA *current;
821 TRACE("(%p, %p={.tymed=0x%x, .dwAspect=%d, .cfFormat=%d}\n",
822 dataObject, formatEtc, formatEtc->tymed, formatEtc->dwAspect, formatEtc->cfFormat);
823 X11DRV_XDND_DescribeClipboardFormat(formatEtc->cfFormat, formatDesc, sizeof(formatDesc));
825 if (formatEtc->tymed && !(formatEtc->tymed & TYMED_HGLOBAL))
827 FIXME("only HGLOBAL medium types supported right now\n");
828 return DV_E_TYMED;
830 /* Windows Explorer ignores .dwAspect and .lindex for CF_HDROP,
831 * and we have no way to implement them on XDnD anyway, so ignore them too.
834 LIST_FOR_EACH_ENTRY(current, &xdndData, XDNDDATA, entry)
836 if (current->cf_win == formatEtc->cfFormat)
838 TRACE("application found %s\n", formatDesc);
839 return S_OK;
842 TRACE("application didn't find %s\n", formatDesc);
843 return DV_E_FORMATETC;
846 static HRESULT WINAPI XDNDDATAOBJECT_GetCanonicalFormatEtc(IDataObject *dataObject,
847 FORMATETC *formatEtc,
848 FORMATETC *formatEtcOut)
850 FIXME("(%p, %p, %p): stub\n", dataObject, formatEtc, formatEtcOut);
851 formatEtcOut->ptd = NULL;
852 return E_NOTIMPL;
855 static HRESULT WINAPI XDNDDATAOBJECT_SetData(IDataObject *dataObject,
856 FORMATETC *formatEtc,
857 STGMEDIUM *pMedium, BOOL fRelease)
859 FIXME("(%p, %p, %p, %s): stub\n", dataObject, formatEtc,
860 pMedium, fRelease?"TRUE":"FALSE");
861 return E_NOTIMPL;
864 static HRESULT WINAPI XDNDDATAOBJECT_EnumFormatEtc(IDataObject *dataObject,
865 DWORD dwDirection,
866 IEnumFORMATETC **ppEnumFormatEtc)
868 DWORD count;
869 FORMATETC *formats;
871 TRACE("(%p, %u, %p)\n", dataObject, dwDirection, ppEnumFormatEtc);
873 if (dwDirection != DATADIR_GET)
875 FIXME("only the get direction is implemented\n");
876 return E_NOTIMPL;
879 count = list_count(&xdndData);
880 formats = HeapAlloc(GetProcessHeap(), 0, count * sizeof(FORMATETC));
881 if (formats)
883 XDNDDATA *current;
884 DWORD i = 0;
885 HRESULT hr;
886 LIST_FOR_EACH_ENTRY(current, &xdndData, XDNDDATA, entry)
888 formats[i].cfFormat = current->cf_win;
889 formats[i].ptd = NULL;
890 formats[i].dwAspect = DVASPECT_CONTENT;
891 formats[i].lindex = -1;
892 formats[i].tymed = TYMED_HGLOBAL;
893 i++;
895 hr = SHCreateStdEnumFmtEtc(count, formats, ppEnumFormatEtc);
896 HeapFree(GetProcessHeap(), 0, formats);
897 return hr;
899 else
900 return E_OUTOFMEMORY;
903 static HRESULT WINAPI XDNDDATAOBJECT_DAdvise(IDataObject *dataObject,
904 FORMATETC *formatEtc, DWORD advf,
905 IAdviseSink *adviseSink,
906 DWORD *pdwConnection)
908 FIXME("(%p, %p, %u, %p, %p): stub\n", dataObject, formatEtc, advf,
909 adviseSink, pdwConnection);
910 return OLE_E_ADVISENOTSUPPORTED;
913 static HRESULT WINAPI XDNDDATAOBJECT_DUnadvise(IDataObject *dataObject,
914 DWORD dwConnection)
916 FIXME("(%p, %u): stub\n", dataObject, dwConnection);
917 return OLE_E_ADVISENOTSUPPORTED;
920 static HRESULT WINAPI XDNDDATAOBJECT_EnumDAdvise(IDataObject *dataObject,
921 IEnumSTATDATA **pEnumAdvise)
923 FIXME("(%p, %p): stub\n", dataObject, pEnumAdvise);
924 return OLE_E_ADVISENOTSUPPORTED;
927 static IDataObjectVtbl xdndDataObjectVtbl =
929 XDNDDATAOBJECT_QueryInterface,
930 XDNDDATAOBJECT_AddRef,
931 XDNDDATAOBJECT_Release,
932 XDNDDATAOBJECT_GetData,
933 XDNDDATAOBJECT_GetDataHere,
934 XDNDDATAOBJECT_QueryGetData,
935 XDNDDATAOBJECT_GetCanonicalFormatEtc,
936 XDNDDATAOBJECT_SetData,
937 XDNDDATAOBJECT_EnumFormatEtc,
938 XDNDDATAOBJECT_DAdvise,
939 XDNDDATAOBJECT_DUnadvise,
940 XDNDDATAOBJECT_EnumDAdvise
943 static IDataObject XDNDDataObject = { &xdndDataObjectVtbl };