1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1998-1999 Tor Lillqvist
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
32 /* #define OLE2_DND */
37 #include "gdkproperty.h"
38 #include "gdkinternals.h"
39 #include "gdkprivate-win32.h"
52 typedef struct _GdkDragContextPrivateWin32 GdkDragContextPrivateWin32;
56 GDK_DRAG_STATUS_MOTION_WAIT,
57 GDK_DRAG_STATUS_ACTION_WAIT,
68 #define PRINT_GUID(guid) \
69 g_print ("guid = %.08x-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", \
70 ((gulong *) guid)[0], \
71 ((gushort *) guid)[2], \
72 ((gushort *) guid)[3], \
73 ((guchar *) guid)[8], \
74 ((guchar *) guid)[9], \
75 ((guchar *) guid)[10], \
76 ((guchar *) guid)[11], \
77 ((guchar *) guid)[12], \
78 ((guchar *) guid)[13], \
79 ((guchar *) guid)[14], \
80 ((guchar *) guid)[15]);
83 static FORMATETC *formats;
88 /* Structure that holds information about a drag in progress.
89 * this is used on both source and destination sides.
91 struct _GdkDragContextPrivateWin32 {
94 guint16 last_x; /* Coordinates from last event */
97 guint drag_status; /* Current status of drag */
100 #define PRIVATE_DATA(context) ((GdkDragContextPrivateWin32 *) GDK_DRAG_CONTEXT (context)->windowing_data)
102 GdkDragContext *current_dest_drag = NULL;
104 static void gdk_drag_context_init (GdkDragContext *dragcontext);
105 static void gdk_drag_context_class_init (GdkDragContextClass *klass);
106 static void gdk_drag_context_finalize (GObject *object);
108 static gpointer parent_class = NULL;
109 static GList *contexts;
112 gdk_drag_context_get_type (void)
114 static GType object_type = 0;
118 static const GTypeInfo object_info =
120 sizeof (GdkDragContextClass),
121 (GBaseInitFunc) NULL,
122 (GBaseFinalizeFunc) NULL,
123 (GClassInitFunc) gdk_drag_context_class_init,
124 NULL, /* class_finalize */
125 NULL, /* class_data */
126 sizeof (GdkDragContext),
128 (GInstanceInitFunc) gdk_drag_context_init,
131 object_type = g_type_register_static (G_TYPE_OBJECT,
140 gdk_drag_context_init (GdkDragContext *dragcontext)
142 GdkDragContextPrivateWin32 *private = g_new0 (GdkDragContextPrivateWin32, 1);
144 dragcontext->windowing_data = private;
145 private->ref_count = 1;
147 contexts = g_list_prepend (contexts, dragcontext);
151 gdk_drag_context_class_init (GdkDragContextClass *klass)
153 GObjectClass *object_class = G_OBJECT_CLASS (klass);
155 parent_class = g_type_class_peek_parent (klass);
157 object_class->finalize = gdk_drag_context_finalize;
161 gdk_drag_context_finalize (GObject *object)
163 GdkDragContext *context = GDK_DRAG_CONTEXT (object);
164 GdkDragContextPrivateWin32 *private = PRIVATE_DATA (context);
166 g_list_free (context->targets);
168 if (context->source_window)
170 gdk_window_unref (context->source_window);
173 if (context->dest_window)
174 gdk_window_unref (context->dest_window);
176 contexts = g_list_remove (contexts, context);
180 G_OBJECT_CLASS (parent_class)->finalize (object);
186 gdk_drag_context_new (void)
188 return g_object_new (gdk_drag_context_get_type (), NULL);
192 gdk_drag_context_ref (GdkDragContext *context)
194 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
196 g_object_ref (G_OBJECT (context));
200 gdk_drag_context_unref (GdkDragContext *context)
202 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
204 g_object_unref (G_OBJECT (context));
209 static GdkDragContext *
210 gdk_drag_context_find (gboolean is_source,
214 GList *tmp_list = contexts;
215 GdkDragContext *context;
219 context = (GdkDragContext *)tmp_list->data;
221 if ((!context->is_source == !is_source) &&
222 ((source_xid == None) || (context->source_window &&
223 (GDK_WINDOW_XWINDOW (context->source_window) == source_xid))) &&
224 ((dest_xid == None) || (context->dest_window &&
225 (GDK_WINDOW_XWINDOW (context->dest_window) == dest_xid))))
228 tmp_list = tmp_list->next;
240 GdkDragContext *context;
241 } target_drag_context;
247 GdkDragContext *context;
248 } source_drag_context;
263 static enum_formats *enum_formats_new (void);
265 static ULONG STDMETHODCALLTYPE
266 idroptarget_addref (LPDROPTARGET This)
268 target_drag_context *ctx = (target_drag_context *) This;
269 GdkDragContextPrivateWin32 *private = PRIVATE_DATA (ctx->context);
270 int ref_count = ++private->ref_count;
272 gdk_drag_context_ref (ctx->context);
273 GDK_NOTE (DND, g_print ("idroptarget_addref %#x %d\n", This, ref_count));
278 static HRESULT STDMETHODCALLTYPE
279 idroptarget_queryinterface (LPDROPTARGET This,
283 GDK_NOTE (DND, g_print ("idroptarget_queryinterface %#x\n", This));
289 if (IsEqualGUID (riid, &IID_IUnknown))
291 g_print ("...IUnknown\n");
292 idroptarget_addref (This);
296 else if (IsEqualGUID (riid, &IID_IDropTarget))
298 g_print ("...IDropTarget\n");
299 idroptarget_addref (This);
305 g_print ("...Huh?\n");
306 return E_NOINTERFACE;
310 static ULONG STDMETHODCALLTYPE
311 idroptarget_release (LPDROPTARGET This)
313 target_drag_context *ctx = (target_drag_context *) This;
314 GdkDragContextPrivateWin32 *private = PRIVATE_DATA (ctx->context);
315 int ref_count = --private->ref_count;
317 gdk_drag_context_unref (ctx->context);
318 GDK_NOTE (DND, g_print ("idroptarget_release %#x %d\n", This, ref_count));
326 static HRESULT STDMETHODCALLTYPE
327 idroptarget_dragenter (LPDROPTARGET This,
328 LPDATAOBJECT pDataObj,
333 GDK_NOTE (DND, g_print ("idroptarget_dragenter %#x\n", This));
338 static HRESULT STDMETHODCALLTYPE
339 idroptarget_dragover (LPDROPTARGET This,
344 GDK_NOTE (DND, g_print ("idroptarget_dragover %#x\n", This));
349 static HRESULT STDMETHODCALLTYPE
350 idroptarget_dragleave (LPDROPTARGET This)
352 GDK_NOTE (DND, g_print ("idroptarget_dragleave %#x\n", This));
357 static HRESULT STDMETHODCALLTYPE
358 idroptarget_drop (LPDROPTARGET This,
359 LPDATAOBJECT pDataObj,
364 GDK_NOTE (DND, g_print ("idroptarget_drop %#x\n", This));
369 static ULONG STDMETHODCALLTYPE
370 idropsource_addref (LPDROPSOURCE This)
372 source_drag_context *ctx = (source_drag_context *) This;
373 GdkDragContextPrivateWin32 *private = PRIVATE_DATA (ctx->context);
375 gdk_drag_context_ref (ctx->context);
376 GDK_NOTE (DND, g_print ("idropsource_addref %#x %d\n",
377 This, private->ref_count));
379 return private->ref_count;
382 static HRESULT STDMETHODCALLTYPE
383 idropsource_queryinterface (LPDROPSOURCE This,
387 GDK_NOTE (DND, g_print ("idropsource_queryinterface %#x\n", This));
392 if (IsEqualGUID (riid, &IID_IUnknown))
394 g_print ("...IUnknown\n");
395 idropsource_addref (This);
399 else if (IsEqualGUID (riid, &IID_IDropSource))
401 g_print ("...IDropSource\n");
402 idropsource_addref (This);
408 g_print ("...Huh?\n");
409 return E_NOINTERFACE;
413 static ULONG STDMETHODCALLTYPE
414 idropsource_release (LPDROPSOURCE This)
416 source_drag_context *ctx = (source_drag_context *) This;
417 GdkDragContextPrivateWin32 *private = PRIVATE_DATA (ctx->context);
418 int ref_count = --private->ref_count;
420 gdk_drag_context_unref (ctx->context);
421 GDK_NOTE (DND, g_print ("idropsource_release %#x %d\n", This, ref_count));
429 static HRESULT STDMETHODCALLTYPE
430 idropsource_querycontinuedrag (LPDROPSOURCE This,
434 GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag %#x\n", This));
439 static HRESULT STDMETHODCALLTYPE
440 idropsource_givefeedback (LPDROPSOURCE This,
443 GDK_NOTE (DND, g_print ("idropsource_givefeedback %#x\n", This));
448 static ULONG STDMETHODCALLTYPE
449 idataobject_addref (LPDATAOBJECT This)
451 data_object *dobj = (data_object *) This;
452 int ref_count = ++dobj->ref_count;
454 GDK_NOTE (DND, g_print ("idataobject_addref %#x %d\n", This, ref_count));
459 static HRESULT STDMETHODCALLTYPE
460 idataobject_queryinterface (LPDATAOBJECT This,
464 GDK_NOTE (DND, g_print ("idataobject_queryinterface %#x\n", This));
469 if (IsEqualGUID (riid, &IID_IUnknown))
471 g_print ("...IUnknown\n");
472 idataobject_addref (This);
476 else if (IsEqualGUID (riid, &IID_IDataObject))
478 g_print ("...IDataObject\n");
479 idataobject_addref (This);
485 g_print ("...Huh?\n");
486 return E_NOINTERFACE;
490 static ULONG STDMETHODCALLTYPE
491 idataobject_release (LPDATAOBJECT This)
493 data_object *dobj = (data_object *) This;
494 int ref_count = --dobj->ref_count;
496 GDK_NOTE (DND, g_print ("idataobject_release %#x %d\n", This, ref_count));
504 static HRESULT STDMETHODCALLTYPE
505 idataobject_getdata (LPDATAOBJECT This,
506 LPFORMATETC pFormatEtc,
509 GDK_NOTE (DND, g_print ("idataobject_getdata %#x\n", This));
514 static HRESULT STDMETHODCALLTYPE
515 idataobject_getdatahere (LPDATAOBJECT This,
516 LPFORMATETC pFormatEtc,
519 GDK_NOTE (DND, g_print ("idataobject_getdatahere %#x\n", This));
524 static HRESULT STDMETHODCALLTYPE
525 idataobject_querygetdata (LPDATAOBJECT This,
526 LPFORMATETC pFormatEtc)
530 GDK_NOTE (DND, g_print ("idataobject_querygetdata %#x %#x", This, pFormatEtc->cfFormat));
532 for (i = 0; i < nformats; i++)
533 if (pFormatEtc->cfFormat == formats[i].cfFormat)
535 GDK_NOTE (DND, g_print (" S_OK\n"));
539 GDK_NOTE (DND, g_print (" DV_E_FORMATETC\n"));
540 return DV_E_FORMATETC;
543 static HRESULT STDMETHODCALLTYPE
544 idataobject_getcanonicalformatetc (LPDATAOBJECT This,
545 LPFORMATETC pFormatEtcIn,
546 LPFORMATETC pFormatEtcOut)
548 GDK_NOTE (DND, g_print ("idataobject_getcanonicalformatetc %#x\n", This));
553 static HRESULT STDMETHODCALLTYPE
554 idataobject_setdata (LPDATAOBJECT This,
555 LPFORMATETC pFormatEtc,
559 GDK_NOTE (DND, g_print ("idataobject_setdata %#x\n", This));
564 static HRESULT STDMETHODCALLTYPE
565 idataobject_enumformatetc (LPDATAOBJECT This,
567 LPENUMFORMATETC *ppEnumFormatEtc)
569 GDK_NOTE (DND, g_print ("idataobject_enumformatetc %#x\n", This));
571 if (dwDirection != DATADIR_GET)
574 *ppEnumFormatEtc = &enum_formats_new ()->ief;
578 static HRESULT STDMETHODCALLTYPE
579 idataobject_dadvise (LPDATAOBJECT This,
580 LPFORMATETC pFormatetc,
582 LPADVISESINK pAdvSink,
583 DWORD *pdwConnection)
585 GDK_NOTE (DND, g_print ("idataobject_dadvise %#x\n", This));
590 static HRESULT STDMETHODCALLTYPE
591 idataobject_dunadvise (LPDATAOBJECT This,
594 GDK_NOTE (DND, g_print ("idataobject_dunadvise %#x\n", This));
599 static HRESULT STDMETHODCALLTYPE
600 idataobject_enumdadvise (LPDATAOBJECT This,
601 LPENUMSTATDATA *ppenumAdvise)
603 GDK_NOTE (DND, g_print ("idataobject_enumdadvise %#x\n", This));
608 static ULONG STDMETHODCALLTYPE
609 ienumformatetc_addref (LPENUMFORMATETC This)
611 enum_formats *en = (enum_formats *) This;
612 int ref_count = ++en->ref_count;
614 GDK_NOTE (DND, g_print ("ienumformatetc_addref %#x %d\n", This, ref_count));
619 static HRESULT STDMETHODCALLTYPE
620 ienumformatetc_queryinterface (LPENUMFORMATETC This,
624 GDK_NOTE (DND, g_print ("ienumformatetc_queryinterface %#x\n", This));
629 if (IsEqualGUID (riid, &IID_IUnknown))
631 g_print ("...IUnknown\n");
632 ienumformatetc_addref (This);
636 else if (IsEqualGUID (riid, &IID_IEnumFORMATETC))
638 g_print ("...IEnumFORMATETC\n");
639 ienumformatetc_addref (This);
645 g_print ("...Huh?\n");
646 return E_NOINTERFACE;
650 static ULONG STDMETHODCALLTYPE
651 ienumformatetc_release (LPENUMFORMATETC This)
653 enum_formats *en = (enum_formats *) This;
654 int ref_count = --en->ref_count;
656 GDK_NOTE (DND, g_print ("ienumformatetc_release %#x %d\n", This, ref_count));
664 static HRESULT STDMETHODCALLTYPE
665 ienumformatetc_next (LPENUMFORMATETC This,
670 enum_formats *en = (enum_formats *) This;
673 GDK_NOTE (DND, g_print ("ienumformatetc_next %#x %d %d\n", This, en->ix, celt));
676 for (i = 0; i < celt; i++)
678 if (en->ix >= nformats)
680 elts[i] = formats[en->ix++];
693 static HRESULT STDMETHODCALLTYPE
694 ienumformatetc_skip (LPENUMFORMATETC This,
697 enum_formats *en = (enum_formats *) This;
699 GDK_NOTE (DND, g_print ("ienumformatetc_skip %#x %d %d\n", This, en->ix, celt));
705 static HRESULT STDMETHODCALLTYPE
706 ienumformatetc_reset (LPENUMFORMATETC This)
708 enum_formats *en = (enum_formats *) This;
710 GDK_NOTE (DND, g_print ("ienumformatetc_reset %#x\n", This));
717 static HRESULT STDMETHODCALLTYPE
718 ienumformatetc_clone (LPENUMFORMATETC This,
719 LPENUMFORMATETC *ppEnumFormatEtc)
721 enum_formats *en = (enum_formats *) This;
724 GDK_NOTE (DND, g_print ("ienumformatetc_clone %#x\n", This));
726 new = enum_formats_new ();
730 *ppEnumFormatEtc = &new->ief;
735 static IDropTargetVtbl idt_vtbl = {
736 idroptarget_queryinterface,
739 idroptarget_dragenter,
740 idroptarget_dragover,
741 idroptarget_dragleave,
745 static IDropSourceVtbl ids_vtbl = {
746 idropsource_queryinterface,
749 idropsource_querycontinuedrag,
750 idropsource_givefeedback
753 static IDataObjectVtbl ido_vtbl = {
754 idataobject_queryinterface,
758 idataobject_getdatahere,
759 idataobject_querygetdata,
760 idataobject_getcanonicalformatetc,
762 idataobject_enumformatetc,
764 idataobject_dunadvise,
765 idataobject_enumdadvise
768 static IEnumFORMATETCVtbl ief_vtbl = {
769 ienumformatetc_queryinterface,
770 ienumformatetc_addref,
771 ienumformatetc_release,
774 ienumformatetc_reset,
778 #endif /* OLE2_DND */
780 static target_drag_context *
781 target_context_new (void)
783 target_drag_context *result;
785 result = g_new0 (target_drag_context, 1);
788 result->idt.lpVtbl = &idt_vtbl;
791 result->context = gdk_drag_context_new ();
792 result->context->is_source = FALSE;
794 GDK_NOTE (DND, g_print ("target_context_new: %p\n", result));
799 static source_drag_context *
800 source_context_new (void)
802 source_drag_context *result;
804 result = g_new0 (source_drag_context, 1);
807 result->ids.lpVtbl = &ids_vtbl;
810 result->context = gdk_drag_context_new ();
811 result->context->is_source = TRUE;
813 GDK_NOTE (DND, g_print ("source_context_new: %p\n", result));
820 data_object_new (void)
824 result = g_new0 (data_object, 1);
826 result->ido.lpVtbl = &ido_vtbl;
827 result->ref_count = 1;
829 GDK_NOTE (DND, g_print ("data_object_new: %#x\n", result));
835 static enum_formats *
836 enum_formats_new (void)
838 enum_formats *result;
840 result = g_new0 (enum_formats, 1);
842 result->ief.lpVtbl = &ief_vtbl;
843 result->ref_count = 1;
846 GDK_NOTE (DND, g_print ("enum_formats_new: %#x\n", result));
853 /* From MS Knowledge Base article Q130698 */
855 /* resolve_link() fills the filename and path buffer
856 * with relevant information
857 * hWnd - calling app's window handle.
859 * lpszLinkName - name of the link file passed into the function.
861 * lpszPath - the buffer that will receive the file pathname.
865 resolve_link(HWND hWnd,
866 LPCTSTR lpszLinkName,
868 LPSTR lpszDescription)
874 /* Assume Failure to start with: */
877 *lpszDescription = 0;
879 /* Call CoCreateInstance to obtain the IShellLink interface
880 * pointer. This call fails if CoInitialize is not called, so it is
881 * assumed that CoInitialize has been called.
884 hres = CoCreateInstance (&CLSID_ShellLink,
886 CLSCTX_INPROC_SERVER,
889 if (SUCCEEDED (hres))
893 /* The IShellLink interface supports the IPersistFile
894 * interface. Get an interface pointer to it.
896 hres = psl->lpVtbl->QueryInterface (psl,
899 if (SUCCEEDED (hres))
903 /* Convert the given link name string to wide character string. */
904 MultiByteToWideChar (CP_ACP, 0,
908 hres = ppf->lpVtbl->Load (ppf, wsz, STGM_READ);
909 if (SUCCEEDED (hres))
911 /* Resolve the link by calling the Resolve()
912 * interface function.
914 hres = psl->lpVtbl->Resolve(psl, hWnd,
917 if (SUCCEEDED (hres))
919 hres = psl->lpVtbl->GetPath (psl, lpszPath,
921 (WIN32_FIND_DATA*)&wfd,
924 if (SUCCEEDED (hres) && lpszDescription != NULL)
926 hres = psl->lpVtbl->GetDescription (psl,
930 if (!SUCCEEDED (hres))
935 ppf->lpVtbl->Release (ppf);
937 psl->lpVtbl->Release (psl);
939 return SUCCEEDED (hres);
942 static GdkFilterReturn
943 gdk_dropfiles_filter (GdkXEvent *xev,
947 GdkDragContext *context;
948 GdkDragContextPrivateWin32 *private;
949 static GdkAtom text_uri_list_atom = GDK_NONE;
951 MSG *msg = (MSG *) xev;
955 guchar fileName[MAX_PATH], linkedFile[MAX_PATH];
957 if (text_uri_list_atom == GDK_NONE)
958 text_uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE);
960 if (msg->message == WM_DROPFILES)
962 GDK_NOTE (DND, g_print ("WM_DROPFILES: %#x\n", (guint) msg->hwnd));
964 context = gdk_drag_context_new ();
965 private = PRIVATE_DATA (context);
966 context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
967 context->is_source = FALSE;
968 context->source_window = gdk_parent_root;
969 context->dest_window = event->any.window;
970 gdk_drawable_ref (context->dest_window);
971 /* WM_DROPFILES drops are always file names */
973 g_list_append (NULL, GUINT_TO_POINTER (text_uri_list_atom));
974 current_dest_drag = context;
976 event->dnd.type = GDK_DROP_START;
977 event->dnd.context = current_dest_drag;
978 gdk_drag_context_ref (current_dest_drag);
980 hdrop = (HANDLE) msg->wParam;
981 DragQueryPoint (hdrop, &pt);
982 ClientToScreen (msg->hwnd, &pt);
984 event->dnd.x_root = pt.x;
985 event->dnd.y_root = pt.y;
986 event->dnd.time = msg->time;
988 nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
990 result = g_string_new (NULL);
991 for (i = 0; i < nfiles; i++)
993 g_string_append (result, "file:");
994 DragQueryFile (hdrop, i, fileName, MAX_PATH);
996 /* Resolve shortcuts */
997 if (resolve_link (msg->hwnd, fileName, linkedFile, NULL))
999 g_string_append (result, linkedFile);
1000 GDK_NOTE (DND, g_print ("...%s link to %s\n",
1001 fileName, linkedFile));
1005 g_string_append (result, fileName);
1006 GDK_NOTE (DND, g_print ("...%s\n", fileName));
1008 g_string_append (result, "\015\012");
1010 gdk_sel_prop_store (gdk_parent_root, text_uri_list_atom, 8,
1011 result->str, result->len + 1);
1015 return GDK_FILTER_TRANSLATE;
1018 return GDK_FILTER_CONTINUE;
1021 /*************************************************************
1022 ************************** Public API ***********************
1023 *************************************************************/
1030 hres = OleInitialize (NULL);
1032 if (! SUCCEEDED (hres))
1033 g_error ("OleInitialize failed");
1036 formats = g_new (FORMATETC, nformats);
1038 formats[0].cfFormat = CF_TEXT;
1039 formats[0].ptd = NULL;
1040 formats[0].dwAspect = DVASPECT_CONTENT;
1041 formats[0].lindex = -1;
1042 formats[0].tymed = TYMED_HGLOBAL;
1044 formats[1].cfFormat = CF_GDIOBJFIRST;
1045 formats[1].ptd = NULL;
1046 formats[1].dwAspect = DVASPECT_CONTENT;
1047 formats[1].lindex = -1;
1048 formats[1].tymed = TYMED_HGLOBAL;
1053 gdk_win32_dnd_exit (void)
1063 gdk_drag_do_leave (GdkDragContext *context,
1066 if (context->dest_window)
1068 GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n"));
1069 gdk_drawable_unref (context->dest_window);
1070 context->dest_window = NULL;
1075 gdk_drag_begin (GdkWindow *window,
1078 source_drag_context *ctx;
1089 g_return_val_if_fail (window != NULL, NULL);
1091 GDK_NOTE (DND, g_print ("gdk_drag_begin\n"));
1093 ctx = source_context_new ();
1094 ctx->context->protocol = GDK_DRAG_PROTO_OLE2;
1095 ctx->context->source_window = window;
1096 gdk_drawable_ref (window);
1099 tmp_list = g_list_last (targets);
1100 ctx->context->targets = NULL;
1103 ctx->context->targets = g_list_prepend (ctx->context->targets,
1105 tmp_list = tmp_list->prev;
1108 ctx->context->actions = 0;
1110 dobj = data_object_new ();
1112 global = GlobalAlloc (GMEM_FIXED, sizeof (ctx));
1114 memcpy (&global, ctx, sizeof (ctx));
1116 medium.tymed = TYMED_HGLOBAL;
1117 medium.hGlobal = global;
1118 medium.pUnkForRelease = NULL;
1120 dobj->ido.lpVtbl->SetData (&dobj->ido, &formats[1], &medium, TRUE);
1122 hResult = DoDragDrop (&dobj->ido, &ctx->ids, DROPEFFECT_MOVE|DROPEFFECT_COPY, &dwEffect);
1124 GDK_NOTE (DND, g_print ("DoDragDrop returned %s\n",
1125 (hResult == DRAGDROP_S_DROP ? "DRAGDROP_S_DROP" :
1126 (hResult == DRAGDROP_S_CANCEL ? "DRAGDROP_S_CANCEL" :
1127 (hResult == E_UNEXPECTED ? "E_UNEXPECTED" :
1128 g_strdup_printf ("%#.8x", hResult))))));
1130 dobj->ido.lpVtbl->Release (&dobj->ido);
1131 ctx->ids.lpVtbl->Release (&ctx->ids);
1133 return ctx->context;
1137 gdk_drag_get_protocol (guint32 xid,
1138 GdkDragProtocol *protocol)
1140 /* This isn't used */
1145 gdk_drag_find_window (GdkDragContext *context,
1146 GdkWindow *drag_window,
1149 GdkWindow **dest_window,
1150 GdkDragProtocol *protocol)
1155 GDK_NOTE (DND, g_print ("gdk_drag_find_window: %#x +%d+%d\n",
1156 (drag_window ? (guint) GDK_WINDOW_HWND (drag_window) : 0),
1161 recipient = WindowFromPoint (pt);
1162 if (recipient == NULL)
1163 *dest_window = NULL;
1166 *dest_window = gdk_win32_handle_table_lookup (GPOINTER_TO_UINT(recipient));
1168 gdk_drawable_ref (*dest_window);
1169 *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
1174 gdk_drag_motion (GdkDragContext *context,
1175 GdkWindow *dest_window,
1176 GdkDragProtocol protocol,
1179 GdkDragAction suggested_action,
1180 GdkDragAction possible_actions,
1183 GDK_NOTE (DND, g_print ("gdk_drag_motion\n"));
1189 gdk_drag_drop (GdkDragContext *context,
1192 g_return_if_fail (context != NULL);
1194 GDK_NOTE (DND, g_print ("gdk_drag_drop\n"));
1198 gdk_drag_abort (GdkDragContext *context,
1201 g_return_if_fail (context != NULL);
1203 GDK_NOTE (DND, g_print ("gdk_drag_abort\n"));
1205 gdk_drag_do_leave (context, time);
1208 /* Destination side */
1211 gdk_drag_status (GdkDragContext *context,
1212 GdkDragAction action,
1215 GDK_NOTE (DND, g_print ("gdk_drag_status\n"));
1219 gdk_drop_reply (GdkDragContext *context,
1223 GDK_NOTE (DND, g_print ("gdk_drop_reply\n"));
1227 gdk_drop_finish (GdkDragContext *context,
1231 GDK_NOTE (DND, g_print ("gdk_drop_finish\n"));
1234 static GdkFilterReturn
1235 gdk_destroy_filter (GdkXEvent *xev,
1240 MSG *msg = (MSG *) xev;
1242 if (msg->message == WM_DESTROY)
1244 IDropTarget *idtp = (IDropTarget *) data;
1246 GDK_NOTE (DND, g_print ("gdk_destroy_filter: WM_DESTROY: %#x\n", msg->hwnd));
1248 idtp->lpVtbl->Release (idtp);
1250 RevokeDragDrop (msg->hwnd);
1251 CoLockObjectExternal (idtp, FALSE, TRUE);
1254 return GDK_FILTER_CONTINUE;
1258 gdk_window_register_dnd (GdkWindow *window)
1261 target_drag_context *ctx;
1265 g_return_if_fail (window != NULL);
1267 GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %#x\n",
1268 (guint) GDK_WINDOW_HWND (window)));
1270 /* We always claim to accept dropped files, but in fact we might not,
1271 * of course. This function is called in such a way that it cannot know
1272 * whether the window (widget) in question actually accepts files
1273 * (in gtk, data of type text/uri-list) or not.
1275 gdk_window_add_filter (window, gdk_dropfiles_filter, NULL);
1276 DragAcceptFiles (GDK_WINDOW_HWND (window), TRUE);
1279 /* Register for OLE2 d&d */
1280 ctx = target_context_new ();
1281 ctx->context->protocol = GDK_DRAG_PROTO_OLE2;
1282 hres = CoLockObjectExternal ((IUnknown *) &ctx->idt, TRUE, FALSE);
1283 if (!SUCCEEDED (hres))
1284 OTHER_API_FAILED ("CoLockObjectExternal");
1287 hres = RegisterDragDrop (GDK_WINDOW_HWND (window), &ctx->idt);
1288 if (hres == DRAGDROP_E_ALREADYREGISTERED)
1290 g_print ("DRAGDROP_E_ALREADYREGISTERED\n");
1292 ctx->idt.lpVtbl->Release (&ctx->idt);
1294 CoLockObjectExternal ((IUnknown *) &ctx->idt, FALSE, FALSE);
1296 else if (!SUCCEEDED (hres))
1297 OTHER_API_FAILED ("RegisterDragDrop");
1300 gdk_window_add_filter (window, gdk_destroy_filter, &ctx->idt);
1306 /*************************************************************
1307 * gdk_drag_get_selection:
1308 * Returns the selection atom for the current source window
1312 *************************************************************/
1315 gdk_drag_get_selection (GdkDragContext *context)
1317 if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES)
1318 return gdk_win32_dropfiles_atom;
1319 else if (context->protocol == GDK_DRAG_PROTO_OLE2)
1320 return gdk_ole2_dnd_atom;