1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1998-2002 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/.
30 /* #define OLE2_DND */
35 #include "gdkproperty.h"
36 #include "gdkinternals.h"
37 #include "gdkprivate-win32.h"
50 typedef struct _GdkDragContextPrivateWin32 GdkDragContextPrivateWin32;
54 GDK_DRAG_STATUS_MOTION_WAIT,
55 GDK_DRAG_STATUS_ACTION_WAIT,
66 #define PRINT_GUID(guid) \
67 g_print ("guid = %.08x-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", \
68 ((gulong *) guid)[0], \
69 ((gushort *) guid)[2], \
70 ((gushort *) guid)[3], \
71 ((guchar *) guid)[8], \
72 ((guchar *) guid)[9], \
73 ((guchar *) guid)[10], \
74 ((guchar *) guid)[11], \
75 ((guchar *) guid)[12], \
76 ((guchar *) guid)[13], \
77 ((guchar *) guid)[14], \
78 ((guchar *) guid)[15]);
81 static FORMATETC *formats;
86 /* Structure that holds information about a drag in progress.
87 * this is used on both source and destination sides.
89 struct _GdkDragContextPrivateWin32 {
92 guint16 last_x; /* Coordinates from last event */
95 guint drag_status; /* Current status of drag */
98 #define GDK_DRAG_CONTEXT_PRIVATE_DATA(context) ((GdkDragContextPrivateWin32 *) GDK_DRAG_CONTEXT (context)->windowing_data)
100 GdkDragContext *current_dest_drag = NULL;
102 static void gdk_drag_context_init (GdkDragContext *dragcontext);
103 static void gdk_drag_context_class_init (GdkDragContextClass *klass);
104 static void gdk_drag_context_finalize (GObject *object);
106 static gpointer parent_class = NULL;
107 static GList *contexts;
110 gdk_drag_context_get_type (void)
112 static GType object_type = 0;
116 static const GTypeInfo object_info =
118 sizeof (GdkDragContextClass),
119 (GBaseInitFunc) NULL,
120 (GBaseFinalizeFunc) NULL,
121 (GClassInitFunc) gdk_drag_context_class_init,
122 NULL, /* class_finalize */
123 NULL, /* class_data */
124 sizeof (GdkDragContext),
126 (GInstanceInitFunc) gdk_drag_context_init,
129 object_type = g_type_register_static (G_TYPE_OBJECT,
138 gdk_drag_context_init (GdkDragContext *dragcontext)
140 GdkDragContextPrivateWin32 *private = g_new0 (GdkDragContextPrivateWin32, 1);
142 dragcontext->windowing_data = private;
143 private->ref_count = 1;
145 contexts = g_list_prepend (contexts, dragcontext);
149 gdk_drag_context_class_init (GdkDragContextClass *klass)
151 GObjectClass *object_class = G_OBJECT_CLASS (klass);
153 parent_class = g_type_class_peek_parent (klass);
155 object_class->finalize = gdk_drag_context_finalize;
159 gdk_drag_context_finalize (GObject *object)
161 GdkDragContext *context = GDK_DRAG_CONTEXT (object);
162 GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
164 g_list_free (context->targets);
166 if (context->source_window)
168 gdk_window_unref (context->source_window);
171 if (context->dest_window)
172 gdk_window_unref (context->dest_window);
174 contexts = g_list_remove (contexts, context);
178 G_OBJECT_CLASS (parent_class)->finalize (object);
184 gdk_drag_context_new (void)
186 return g_object_new (gdk_drag_context_get_type (), NULL);
190 gdk_drag_context_ref (GdkDragContext *context)
192 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
194 GDK_NOTE (DND, g_print ("gdk_drag_context_ref: %p %d\n", context, G_OBJECT(context)->ref_count));
196 g_object_ref (context);
200 gdk_drag_context_unref (GdkDragContext *context)
202 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
204 GDK_NOTE (DND, g_print ("gdk_drag_context_unref: %p %d\n", context, G_OBJECT(context)->ref_count));
205 g_object_unref (context);
208 static GdkDragContext *
209 gdk_drag_context_find (gboolean is_source,
213 GList *tmp_list = contexts;
214 GdkDragContext *context;
215 GdkDragContextPrivateWin32 *private;
219 context = (GdkDragContext *)tmp_list->data;
220 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
222 if ((!context->is_source == !is_source) &&
223 ((source == NULL) || (context->source_window && (context->source_window == source))) &&
224 ((dest == NULL) || (context->dest_window && (context->dest_window == dest))))
227 tmp_list = tmp_list->next;
238 GdkDragContext *context;
239 } target_drag_context;
245 GdkDragContext *context;
246 } source_drag_context;
261 static enum_formats *enum_formats_new (void);
263 static ULONG STDMETHODCALLTYPE
264 idroptarget_addref (LPDROPTARGET This)
266 target_drag_context *ctx = (target_drag_context *) This;
267 GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
268 int ref_count = ++private->ref_count;
270 gdk_drag_context_ref (ctx->context);
271 GDK_NOTE (DND, g_print ("idroptarget_addref %#x %d\n", This, ref_count));
276 static HRESULT STDMETHODCALLTYPE
277 idroptarget_queryinterface (LPDROPTARGET This,
281 GDK_NOTE (DND, g_print ("idroptarget_queryinterface %#x\n", This));
287 if (IsEqualGUID (riid, &IID_IUnknown))
289 g_print ("...IUnknown\n");
290 idroptarget_addref (This);
294 else if (IsEqualGUID (riid, &IID_IDropTarget))
296 g_print ("...IDropTarget\n");
297 idroptarget_addref (This);
303 g_print ("...Huh?\n");
304 return E_NOINTERFACE;
308 static ULONG STDMETHODCALLTYPE
309 idroptarget_release (LPDROPTARGET This)
311 target_drag_context *ctx = (target_drag_context *) This;
312 GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
313 int ref_count = --private->ref_count;
315 gdk_drag_context_unref (ctx->context);
316 GDK_NOTE (DND, g_print ("idroptarget_release %#x %d\n", This, ref_count));
324 static HRESULT STDMETHODCALLTYPE
325 idroptarget_dragenter (LPDROPTARGET This,
326 LPDATAOBJECT pDataObj,
331 GDK_NOTE (DND, g_print ("idroptarget_dragenter %#x\n", This));
336 static HRESULT STDMETHODCALLTYPE
337 idroptarget_dragover (LPDROPTARGET This,
342 GDK_NOTE (DND, g_print ("idroptarget_dragover %#x\n", This));
347 static HRESULT STDMETHODCALLTYPE
348 idroptarget_dragleave (LPDROPTARGET This)
350 GDK_NOTE (DND, g_print ("idroptarget_dragleave %#x\n", This));
355 static HRESULT STDMETHODCALLTYPE
356 idroptarget_drop (LPDROPTARGET This,
357 LPDATAOBJECT pDataObj,
362 GDK_NOTE (DND, g_print ("idroptarget_drop %#x\n", This));
367 static ULONG STDMETHODCALLTYPE
368 idropsource_addref (LPDROPSOURCE This)
370 source_drag_context *ctx = (source_drag_context *) This;
371 GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
373 gdk_drag_context_ref (ctx->context);
374 GDK_NOTE (DND, g_print ("idropsource_addref %#x %d\n",
375 This, private->ref_count));
377 return private->ref_count;
380 static HRESULT STDMETHODCALLTYPE
381 idropsource_queryinterface (LPDROPSOURCE This,
385 GDK_NOTE (DND, g_print ("idropsource_queryinterface %#x\n", This));
390 if (IsEqualGUID (riid, &IID_IUnknown))
392 g_print ("...IUnknown\n");
393 idropsource_addref (This);
397 else if (IsEqualGUID (riid, &IID_IDropSource))
399 g_print ("...IDropSource\n");
400 idropsource_addref (This);
406 g_print ("...Huh?\n");
407 return E_NOINTERFACE;
411 static ULONG STDMETHODCALLTYPE
412 idropsource_release (LPDROPSOURCE This)
414 source_drag_context *ctx = (source_drag_context *) This;
415 GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
416 int ref_count = --private->ref_count;
418 gdk_drag_context_unref (ctx->context);
419 GDK_NOTE (DND, g_print ("idropsource_release %#x %d\n", This, ref_count));
427 static HRESULT STDMETHODCALLTYPE
428 idropsource_querycontinuedrag (LPDROPSOURCE This,
432 GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag %#x\n", This));
437 static HRESULT STDMETHODCALLTYPE
438 idropsource_givefeedback (LPDROPSOURCE This,
441 GDK_NOTE (DND, g_print ("idropsource_givefeedback %#x\n", This));
446 static ULONG STDMETHODCALLTYPE
447 idataobject_addref (LPDATAOBJECT This)
449 data_object *dobj = (data_object *) This;
450 int ref_count = ++dobj->ref_count;
452 GDK_NOTE (DND, g_print ("idataobject_addref %#x %d\n", This, ref_count));
457 static HRESULT STDMETHODCALLTYPE
458 idataobject_queryinterface (LPDATAOBJECT This,
462 GDK_NOTE (DND, g_print ("idataobject_queryinterface %#x\n", This));
467 if (IsEqualGUID (riid, &IID_IUnknown))
469 g_print ("...IUnknown\n");
470 idataobject_addref (This);
474 else if (IsEqualGUID (riid, &IID_IDataObject))
476 g_print ("...IDataObject\n");
477 idataobject_addref (This);
483 g_print ("...Huh?\n");
484 return E_NOINTERFACE;
488 static ULONG STDMETHODCALLTYPE
489 idataobject_release (LPDATAOBJECT This)
491 data_object *dobj = (data_object *) This;
492 int ref_count = --dobj->ref_count;
494 GDK_NOTE (DND, g_print ("idataobject_release %#x %d\n", This, ref_count));
502 static HRESULT STDMETHODCALLTYPE
503 idataobject_getdata (LPDATAOBJECT This,
504 LPFORMATETC pFormatEtc,
507 GDK_NOTE (DND, g_print ("idataobject_getdata %#x\n", This));
512 static HRESULT STDMETHODCALLTYPE
513 idataobject_getdatahere (LPDATAOBJECT This,
514 LPFORMATETC pFormatEtc,
517 GDK_NOTE (DND, g_print ("idataobject_getdatahere %#x\n", This));
522 static HRESULT STDMETHODCALLTYPE
523 idataobject_querygetdata (LPDATAOBJECT This,
524 LPFORMATETC pFormatEtc)
528 GDK_NOTE (DND, g_print ("idataobject_querygetdata %#x %#x", This, pFormatEtc->cfFormat));
530 for (i = 0; i < nformats; i++)
531 if (pFormatEtc->cfFormat == formats[i].cfFormat)
533 GDK_NOTE (DND, g_print (" S_OK\n"));
537 GDK_NOTE (DND, g_print (" DV_E_FORMATETC\n"));
538 return DV_E_FORMATETC;
541 static HRESULT STDMETHODCALLTYPE
542 idataobject_getcanonicalformatetc (LPDATAOBJECT This,
543 LPFORMATETC pFormatEtcIn,
544 LPFORMATETC pFormatEtcOut)
546 GDK_NOTE (DND, g_print ("idataobject_getcanonicalformatetc %#x\n", This));
551 static HRESULT STDMETHODCALLTYPE
552 idataobject_setdata (LPDATAOBJECT This,
553 LPFORMATETC pFormatEtc,
557 GDK_NOTE (DND, g_print ("idataobject_setdata %#x\n", This));
562 static HRESULT STDMETHODCALLTYPE
563 idataobject_enumformatetc (LPDATAOBJECT This,
565 LPENUMFORMATETC *ppEnumFormatEtc)
567 GDK_NOTE (DND, g_print ("idataobject_enumformatetc %#x\n", This));
569 if (dwDirection != DATADIR_GET)
572 *ppEnumFormatEtc = &enum_formats_new ()->ief;
576 static HRESULT STDMETHODCALLTYPE
577 idataobject_dadvise (LPDATAOBJECT This,
578 LPFORMATETC pFormatetc,
580 LPADVISESINK pAdvSink,
581 DWORD *pdwConnection)
583 GDK_NOTE (DND, g_print ("idataobject_dadvise %#x\n", This));
588 static HRESULT STDMETHODCALLTYPE
589 idataobject_dunadvise (LPDATAOBJECT This,
592 GDK_NOTE (DND, g_print ("idataobject_dunadvise %#x\n", This));
597 static HRESULT STDMETHODCALLTYPE
598 idataobject_enumdadvise (LPDATAOBJECT This,
599 LPENUMSTATDATA *ppenumAdvise)
601 GDK_NOTE (DND, g_print ("idataobject_enumdadvise %#x\n", This));
606 static ULONG STDMETHODCALLTYPE
607 ienumformatetc_addref (LPENUMFORMATETC This)
609 enum_formats *en = (enum_formats *) This;
610 int ref_count = ++en->ref_count;
612 GDK_NOTE (DND, g_print ("ienumformatetc_addref %#x %d\n", This, ref_count));
617 static HRESULT STDMETHODCALLTYPE
618 ienumformatetc_queryinterface (LPENUMFORMATETC This,
622 GDK_NOTE (DND, g_print ("ienumformatetc_queryinterface %#x\n", This));
627 if (IsEqualGUID (riid, &IID_IUnknown))
629 g_print ("...IUnknown\n");
630 ienumformatetc_addref (This);
634 else if (IsEqualGUID (riid, &IID_IEnumFORMATETC))
636 g_print ("...IEnumFORMATETC\n");
637 ienumformatetc_addref (This);
643 g_print ("...Huh?\n");
644 return E_NOINTERFACE;
648 static ULONG STDMETHODCALLTYPE
649 ienumformatetc_release (LPENUMFORMATETC This)
651 enum_formats *en = (enum_formats *) This;
652 int ref_count = --en->ref_count;
654 GDK_NOTE (DND, g_print ("ienumformatetc_release %#x %d\n", This, ref_count));
662 static HRESULT STDMETHODCALLTYPE
663 ienumformatetc_next (LPENUMFORMATETC This,
668 enum_formats *en = (enum_formats *) This;
671 GDK_NOTE (DND, g_print ("ienumformatetc_next %#x %d %d\n", This, en->ix, celt));
674 for (i = 0; i < celt; i++)
676 if (en->ix >= nformats)
678 elts[i] = formats[en->ix++];
691 static HRESULT STDMETHODCALLTYPE
692 ienumformatetc_skip (LPENUMFORMATETC This,
695 enum_formats *en = (enum_formats *) This;
697 GDK_NOTE (DND, g_print ("ienumformatetc_skip %#x %d %d\n", This, en->ix, celt));
703 static HRESULT STDMETHODCALLTYPE
704 ienumformatetc_reset (LPENUMFORMATETC This)
706 enum_formats *en = (enum_formats *) This;
708 GDK_NOTE (DND, g_print ("ienumformatetc_reset %#x\n", This));
715 static HRESULT STDMETHODCALLTYPE
716 ienumformatetc_clone (LPENUMFORMATETC This,
717 LPENUMFORMATETC *ppEnumFormatEtc)
719 enum_formats *en = (enum_formats *) This;
722 GDK_NOTE (DND, g_print ("ienumformatetc_clone %#x\n", This));
724 new = enum_formats_new ();
728 *ppEnumFormatEtc = &new->ief;
733 static IDropTargetVtbl idt_vtbl = {
734 idroptarget_queryinterface,
737 idroptarget_dragenter,
738 idroptarget_dragover,
739 idroptarget_dragleave,
743 static IDropSourceVtbl ids_vtbl = {
744 idropsource_queryinterface,
747 idropsource_querycontinuedrag,
748 idropsource_givefeedback
751 static IDataObjectVtbl ido_vtbl = {
752 idataobject_queryinterface,
756 idataobject_getdatahere,
757 idataobject_querygetdata,
758 idataobject_getcanonicalformatetc,
760 idataobject_enumformatetc,
762 idataobject_dunadvise,
763 idataobject_enumdadvise
766 static IEnumFORMATETCVtbl ief_vtbl = {
767 ienumformatetc_queryinterface,
768 ienumformatetc_addref,
769 ienumformatetc_release,
772 ienumformatetc_reset,
776 #endif /* OLE2_DND */
778 static target_drag_context *
779 target_context_new (void)
781 target_drag_context *result;
783 result = g_new0 (target_drag_context, 1);
786 result->idt.lpVtbl = &idt_vtbl;
789 result->context = gdk_drag_context_new ();
790 result->context->is_source = FALSE;
792 GDK_NOTE (DND, g_print ("target_context_new: %p\n", result));
797 static source_drag_context *
798 source_context_new (void)
800 source_drag_context *result;
802 result = g_new0 (source_drag_context, 1);
805 result->ids.lpVtbl = &ids_vtbl;
808 result->context = gdk_drag_context_new ();
809 result->context->is_source = TRUE;
811 GDK_NOTE (DND, g_print ("source_context_new: %p\n", result));
818 data_object_new (void)
822 result = g_new0 (data_object, 1);
824 result->ido.lpVtbl = &ido_vtbl;
825 result->ref_count = 1;
827 GDK_NOTE (DND, g_print ("data_object_new: %#x\n", result));
833 static enum_formats *
834 enum_formats_new (void)
836 enum_formats *result;
838 result = g_new0 (enum_formats, 1);
840 result->ief.lpVtbl = &ief_vtbl;
841 result->ref_count = 1;
844 GDK_NOTE (DND, g_print ("enum_formats_new: %#x\n", result));
851 /* From MS Knowledge Base article Q130698 */
853 /* resolve_link() fills the filename and path buffer
854 * with relevant information
855 * hWnd - calling app's window handle.
857 * lpszLinkName - name of the link file passed into the function.
859 * lpszPath - the buffer that will receive the file pathname.
863 resolve_link(HWND hWnd,
864 LPCTSTR lpszLinkName,
866 LPSTR lpszDescription)
872 /* Assume Failure to start with: */
875 *lpszDescription = 0;
877 /* Call CoCreateInstance to obtain the IShellLink interface
878 * pointer. This call fails if CoInitialize is not called, so it is
879 * assumed that CoInitialize has been called.
882 hres = CoCreateInstance (&CLSID_ShellLink,
884 CLSCTX_INPROC_SERVER,
887 if (SUCCEEDED (hres))
891 /* The IShellLink interface supports the IPersistFile
892 * interface. Get an interface pointer to it.
894 hres = psl->lpVtbl->QueryInterface (psl,
897 if (SUCCEEDED (hres))
901 /* Convert the given link name string to wide character string. */
902 MultiByteToWideChar (CP_ACP, 0,
906 hres = ppf->lpVtbl->Load (ppf, wsz, STGM_READ);
907 if (SUCCEEDED (hres))
909 /* Resolve the link by calling the Resolve()
910 * interface function.
912 hres = psl->lpVtbl->Resolve(psl, hWnd,
915 if (SUCCEEDED (hres))
917 hres = psl->lpVtbl->GetPath (psl, lpszPath,
919 (WIN32_FIND_DATA*)&wfd,
922 if (SUCCEEDED (hres) && lpszDescription != NULL)
924 hres = psl->lpVtbl->GetDescription (psl,
928 if (!SUCCEEDED (hres))
933 ppf->lpVtbl->Release (ppf);
935 psl->lpVtbl->Release (psl);
937 return SUCCEEDED (hres);
940 static GdkFilterReturn
941 gdk_dropfiles_filter (GdkXEvent *xev,
945 GdkDragContext *context;
946 GdkDragContextPrivateWin32 *private;
948 MSG *msg = (MSG *) xev;
952 guchar fileName[MAX_PATH], linkedFile[MAX_PATH];
954 if (msg->message == WM_DROPFILES)
956 GDK_NOTE (DND, g_print ("WM_DROPFILES: %#x\n", (guint) msg->hwnd));
958 context = gdk_drag_context_new ();
959 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
960 context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
961 context->is_source = FALSE;
962 context->source_window = _gdk_parent_root;
963 gdk_drawable_ref (context->source_window);
964 context->dest_window = event->any.window;
965 gdk_drawable_ref (context->dest_window);
966 /* WM_DROPFILES drops are always file names */
968 g_list_append (NULL, GUINT_TO_POINTER (text_uri_list));
969 current_dest_drag = context;
971 event->dnd.type = GDK_DROP_START;
972 event->dnd.context = current_dest_drag;
974 hdrop = (HANDLE) msg->wParam;
975 DragQueryPoint (hdrop, &pt);
976 ClientToScreen (msg->hwnd, &pt);
978 event->dnd.x_root = pt.x;
979 event->dnd.y_root = pt.y;
980 event->dnd.time = msg->time;
982 nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
984 result = g_string_new (NULL);
985 for (i = 0; i < nfiles; i++)
989 DragQueryFile (hdrop, i, fileName, MAX_PATH);
991 /* Resolve shortcuts */
992 if (resolve_link (msg->hwnd, fileName, linkedFile, NULL))
994 uri = g_filename_to_uri (linkedFile, NULL, NULL);
997 g_string_append (result, uri);
998 GDK_NOTE (DND, g_print ("...%s link to %s: %s\n",
999 fileName, linkedFile, uri));
1005 uri = g_filename_to_uri (fileName, NULL, NULL);
1008 g_string_append (result, uri);
1009 GDK_NOTE (DND, g_print ("...%s: %s\n", fileName, uri));
1013 g_string_append (result, "\015\012");
1015 _gdk_dropfiles_store (result->str);
1016 g_string_free (result, FALSE);
1020 return GDK_FILTER_TRANSLATE;
1023 return GDK_FILTER_CONTINUE;
1026 /*************************************************************
1027 ************************** Public API ***********************
1028 *************************************************************/
1031 _gdk_dnd_init (void)
1035 hres = OleInitialize (NULL);
1037 if (! SUCCEEDED (hres))
1038 g_error ("OleInitialize failed");
1041 formats = g_new (FORMATETC, nformats);
1043 formats[0].cfFormat = CF_TEXT;
1044 formats[0].ptd = NULL;
1045 formats[0].dwAspect = DVASPECT_CONTENT;
1046 formats[0].lindex = -1;
1047 formats[0].tymed = TYMED_HGLOBAL;
1049 formats[1].cfFormat = CF_GDIOBJFIRST;
1050 formats[1].ptd = NULL;
1051 formats[1].dwAspect = DVASPECT_CONTENT;
1052 formats[1].lindex = -1;
1053 formats[1].tymed = TYMED_HGLOBAL;
1058 _gdk_win32_dnd_exit (void)
1068 local_send_leave (GdkDragContext *context,
1073 if ((current_dest_drag != NULL) &&
1074 (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
1075 (current_dest_drag->source_window == context->source_window))
1077 tmp_event.dnd.type = GDK_DRAG_LEAVE;
1078 tmp_event.dnd.window = context->dest_window;
1079 /* Pass ownership of context to the event */
1080 tmp_event.dnd.send_event = FALSE;
1081 tmp_event.dnd.context = current_dest_drag;
1082 tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
1084 current_dest_drag = NULL;
1086 gdk_event_put (&tmp_event);
1091 local_send_enter (GdkDragContext *context,
1095 GdkDragContextPrivateWin32 *private;
1096 GdkDragContext *new_context;
1098 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
1100 if (current_dest_drag != NULL)
1102 gdk_drag_context_unref (current_dest_drag);
1103 current_dest_drag = NULL;
1106 new_context = gdk_drag_context_new ();
1107 new_context->protocol = GDK_DRAG_PROTO_LOCAL;
1108 new_context->is_source = FALSE;
1110 new_context->source_window = context->source_window;
1111 gdk_window_ref (new_context->source_window);
1112 new_context->dest_window = context->dest_window;
1113 gdk_window_ref (new_context->dest_window);
1115 new_context->targets = g_list_copy (context->targets);
1117 gdk_window_set_events (new_context->source_window,
1118 gdk_window_get_events (new_context->source_window) |
1119 GDK_PROPERTY_CHANGE_MASK);
1120 new_context->actions = context->actions;
1122 tmp_event.dnd.type = GDK_DRAG_ENTER;
1123 tmp_event.dnd.window = context->dest_window;
1124 tmp_event.dnd.send_event = FALSE;
1125 tmp_event.dnd.context = new_context;
1126 tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
1128 current_dest_drag = new_context;
1130 gdk_event_put (&tmp_event);
1134 local_send_motion (GdkDragContext *context,
1137 GdkDragAction action,
1142 if ((current_dest_drag != NULL) &&
1143 (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
1144 (current_dest_drag->source_window == context->source_window))
1146 tmp_event.dnd.type = GDK_DRAG_MOTION;
1147 tmp_event.dnd.window = current_dest_drag->dest_window;
1148 tmp_event.dnd.send_event = FALSE;
1149 tmp_event.dnd.context = current_dest_drag;
1150 tmp_event.dnd.time = time;
1152 current_dest_drag->suggested_action = action;
1153 current_dest_drag->actions = current_dest_drag->suggested_action;
1155 tmp_event.dnd.x_root = x_root;
1156 tmp_event.dnd.y_root = y_root;
1158 (GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag))->last_x = x_root;
1159 (GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag))->last_y = y_root;
1161 GDK_DRAG_CONTEXT_PRIVATE_DATA (context)->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
1163 gdk_event_put (&tmp_event);
1168 local_send_drop (GdkDragContext *context,
1173 if ((current_dest_drag != NULL) &&
1174 (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
1175 (current_dest_drag->source_window == context->source_window))
1177 GdkDragContextPrivateWin32 *private;
1178 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag);
1180 tmp_event.dnd.type = GDK_DROP_START;
1181 tmp_event.dnd.window = current_dest_drag->dest_window;
1182 tmp_event.dnd.send_event = FALSE;
1183 tmp_event.dnd.context = current_dest_drag;
1184 tmp_event.dnd.time = GDK_CURRENT_TIME;
1186 tmp_event.dnd.x_root = private->last_x;
1187 tmp_event.dnd.y_root = private->last_y;
1189 gdk_event_put (&tmp_event);
1195 gdk_drag_do_leave (GdkDragContext *context,
1198 if (context->dest_window)
1200 GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n"));
1202 switch (context->protocol)
1204 case GDK_DRAG_PROTO_LOCAL:
1205 local_send_leave (context, time);
1211 gdk_drawable_unref (context->dest_window);
1212 context->dest_window = NULL;
1217 gdk_drag_begin (GdkWindow *window,
1222 GdkDragContext *new_context;
1224 g_return_val_if_fail (window != NULL, NULL);
1226 new_context = gdk_drag_context_new ();
1227 new_context->is_source = TRUE;
1228 new_context->source_window = window;
1229 gdk_window_ref (window);
1231 tmp_list = g_list_last (targets);
1232 new_context->targets = NULL;
1235 new_context->targets = g_list_prepend (new_context->targets,
1237 tmp_list = tmp_list->prev;
1240 new_context->actions = 0;
1244 source_drag_context *ctx;
1253 g_return_val_if_fail (window != NULL, NULL);
1255 GDK_NOTE (DND, g_print ("gdk_drag_begin\n"));
1257 ctx = source_context_new ();
1258 ctx->context->protocol = GDK_DRAG_PROTO_OLE2;
1259 ctx->context->source_window = window;
1260 gdk_drawable_ref (window);
1262 tmp_list = g_list_last (targets);
1263 ctx->context->targets = NULL;
1266 ctx->context->targets = g_list_prepend (ctx->context->targets,
1268 tmp_list = tmp_list->prev;
1271 ctx->context->actions = 0;
1273 dobj = data_object_new ();
1275 global = GlobalAlloc (GMEM_FIXED, sizeof (ctx));
1277 memcpy (&global, ctx, sizeof (ctx));
1279 medium.tymed = TYMED_HGLOBAL;
1280 medium.hGlobal = global;
1281 medium.pUnkForRelease = NULL;
1283 dobj->ido.lpVtbl->SetData (&dobj->ido, &formats[1], &medium, TRUE);
1285 hResult = DoDragDrop (&dobj->ido, &ctx->ids, DROPEFFECT_MOVE|DROPEFFECT_COPY, &dwEffect);
1287 GDK_NOTE (DND, g_print ("DoDragDrop returned %s\n",
1288 (hResult == DRAGDROP_S_DROP ? "DRAGDROP_S_DROP" :
1289 (hResult == DRAGDROP_S_CANCEL ? "DRAGDROP_S_CANCEL" :
1290 (hResult == E_UNEXPECTED ? "E_UNEXPECTED" :
1291 g_strdup_printf ("%#.8x", hResult))))));
1293 dobj->ido.lpVtbl->Release (&dobj->ido);
1294 ctx->ids.lpVtbl->Release (&ctx->ids);
1296 return ctx->context;
1301 gdk_drag_get_protocol (guint32 xid,
1302 GdkDragProtocol *protocol)
1306 GDK_NOTE (DND, g_print ("gdk_drag_get_protocol\n"));
1308 window = gdk_window_lookup (xid);
1310 if (GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
1312 *protocol = GDK_DRAG_PROTO_LOCAL;
1320 gdk_drag_find_window (GdkDragContext *context,
1321 GdkWindow *drag_window,
1324 GdkWindow **dest_window,
1325 GdkDragProtocol *protocol)
1332 recipient = WindowFromPoint (pt);
1333 if (recipient == NULL)
1334 *dest_window = NULL;
1337 *dest_window = gdk_win32_handle_table_lookup (GPOINTER_TO_UINT(recipient));
1340 *dest_window = gdk_window_get_toplevel (*dest_window);
1341 gdk_drawable_ref (*dest_window);
1344 if (context->source_window)
1345 *protocol = GDK_DRAG_PROTO_LOCAL;
1347 *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
1350 GDK_NOTE (DND, g_print ("gdk_drag_find_window: %#x +%d+%d Protocol: %d\n",
1351 (drag_window ? (guint) GDK_WINDOW_HWND (drag_window) : 0),
1352 x_root, y_root, *protocol));
1356 gdk_drag_motion (GdkDragContext *context,
1357 GdkWindow *dest_window,
1358 GdkDragProtocol protocol,
1361 GdkDragAction suggested_action,
1362 GdkDragAction possible_actions,
1365 GdkDragContextPrivateWin32 *private;
1367 g_return_val_if_fail (context != NULL, FALSE);
1369 GDK_NOTE (DND, g_print ("gdk_drag_motion\n"));
1371 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
1373 if (context->dest_window != dest_window)
1375 GdkEvent temp_event;
1377 /* Send a leave to the last destination */
1378 gdk_drag_do_leave (context, time);
1379 private->drag_status = GDK_DRAG_STATUS_DRAG;
1381 /* Check if new destination accepts drags, and which protocol */
1384 context->dest_window = dest_window;
1385 gdk_window_ref (context->dest_window);
1386 context->protocol = protocol;
1390 case GDK_DRAG_PROTO_LOCAL:
1391 local_send_enter (context, time);
1397 context->suggested_action = suggested_action;
1401 context->dest_window = NULL;
1402 context->action = 0;
1405 /* Push a status event, to let the client know that
1409 temp_event.dnd.type = GDK_DRAG_STATUS;
1410 temp_event.dnd.window = context->source_window;
1411 /* We use this to signal a synthetic status. Perhaps
1412 * we should use an extra field...
1414 temp_event.dnd.send_event = TRUE;
1416 temp_event.dnd.context = context;
1417 temp_event.dnd.time = time;
1419 gdk_event_put (&temp_event);
1423 context->suggested_action = suggested_action;
1426 /* Send a drag-motion event */
1428 private->last_x = x_root;
1429 private->last_y = y_root;
1431 if (context->dest_window)
1433 if (private->drag_status == GDK_DRAG_STATUS_DRAG)
1435 switch (context->protocol)
1437 case GDK_DRAG_PROTO_LOCAL:
1438 local_send_motion (context, x_root, y_root, suggested_action, time);
1441 case GDK_DRAG_PROTO_NONE:
1442 g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
1457 gdk_drag_drop (GdkDragContext *context,
1460 g_return_if_fail (context != NULL);
1462 GDK_NOTE (DND, g_print ("gdk_drag_drop\n"));
1464 if (context->dest_window)
1466 switch (context->protocol)
1468 case GDK_DRAG_PROTO_LOCAL:
1469 local_send_drop (context, time);
1472 case GDK_DRAG_PROTO_NONE:
1473 g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
1483 gdk_drag_abort (GdkDragContext *context,
1486 g_return_if_fail (context != NULL);
1488 GDK_NOTE (DND, g_print ("gdk_drag_abort\n"));
1490 gdk_drag_do_leave (context, time);
1493 /* Destination side */
1496 gdk_drag_status (GdkDragContext *context,
1497 GdkDragAction action,
1500 GdkDragContextPrivateWin32 *private;
1501 GdkDragContext *src_context;
1504 g_return_if_fail (context != NULL);
1506 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
1508 src_context = gdk_drag_context_find (TRUE,
1509 context->source_window,
1510 context->dest_window);
1514 GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (src_context);
1516 if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
1517 private->drag_status = GDK_DRAG_STATUS_DRAG;
1519 tmp_event.dnd.type = GDK_DRAG_STATUS;
1520 tmp_event.dnd.window = context->source_window;
1521 tmp_event.dnd.send_event = FALSE;
1522 tmp_event.dnd.context = src_context;
1523 tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
1525 if (action == GDK_ACTION_DEFAULT)
1528 src_context->action = action;
1530 gdk_event_put (&tmp_event);
1535 gdk_drop_reply (GdkDragContext *context,
1539 g_return_if_fail (context != NULL);
1541 GDK_NOTE (DND, g_print ("gdk_drop_reply\n"));
1543 if (context->dest_window)
1545 switch (context->protocol)
1547 case GDK_DRAG_PROTO_WIN32_DROPFILES:
1548 _gdk_dropfiles_store (NULL);
1558 gdk_drop_finish (GdkDragContext *context,
1562 GdkDragContextPrivateWin32 *private;
1563 GdkDragContext *src_context;
1566 g_return_if_fail (context != NULL);
1568 GDK_NOTE (DND, g_print ("gdk_drop_finish\n"));
1570 private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
1572 src_context = gdk_drag_context_find (TRUE,
1573 context->source_window,
1574 context->dest_window);
1577 tmp_event.dnd.type = GDK_DROP_FINISHED;
1578 tmp_event.dnd.window = src_context->source_window;
1579 tmp_event.dnd.send_event = FALSE;
1580 tmp_event.dnd.context = src_context;
1582 gdk_event_put (&tmp_event);
1588 static GdkFilterReturn
1589 gdk_destroy_filter (GdkXEvent *xev,
1593 MSG *msg = (MSG *) xev;
1595 if (msg->message == WM_DESTROY)
1597 IDropTarget *idtp = (IDropTarget *) data;
1599 GDK_NOTE (DND, g_print ("gdk_destroy_filter: WM_DESTROY: %#x\n", msg->hwnd));
1601 idtp->lpVtbl->Release (idtp);
1603 RevokeDragDrop (msg->hwnd);
1604 CoLockObjectExternal (idtp, FALSE, TRUE);
1606 return GDK_FILTER_CONTINUE;
1611 gdk_window_register_dnd (GdkWindow *window)
1614 target_drag_context *ctx;
1618 g_return_if_fail (window != NULL);
1620 if (GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
1623 gdk_drawable_set_data (window, "gdk-dnd-registered", GINT_TO_POINTER(TRUE), NULL);
1625 GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %#x\n",
1626 (guint) GDK_WINDOW_HWND (window)));
1628 /* We always claim to accept dropped files, but in fact we might not,
1629 * of course. This function is called in such a way that it cannot know
1630 * whether the window (widget) in question actually accepts files
1631 * (in gtk, data of type text/uri-list) or not.
1633 gdk_window_add_filter (window, gdk_dropfiles_filter, NULL);
1634 DragAcceptFiles (GDK_WINDOW_HWND (window), TRUE);
1637 /* Register for OLE2 d&d */
1638 ctx = target_context_new ();
1639 ctx->context->protocol = GDK_DRAG_PROTO_OLE2;
1640 hres = CoLockObjectExternal ((IUnknown *) &ctx->idt, TRUE, FALSE);
1641 if (!SUCCEEDED (hres))
1642 OTHER_API_FAILED ("CoLockObjectExternal");
1645 hres = RegisterDragDrop (GDK_WINDOW_HWND (window), &ctx->idt);
1646 if (hres == DRAGDROP_E_ALREADYREGISTERED)
1648 g_print ("DRAGDROP_E_ALREADYREGISTERED\n");
1650 ctx->idt.lpVtbl->Release (&ctx->idt);
1652 CoLockObjectExternal ((IUnknown *) &ctx->idt, FALSE, FALSE);
1654 else if (!SUCCEEDED (hres))
1655 OTHER_API_FAILED ("RegisterDragDrop");
1658 gdk_window_add_filter (window, gdk_destroy_filter, &ctx->idt);
1664 /*************************************************************
1665 * gdk_drag_get_selection:
1666 * Returns the selection atom for the current source window
1670 *************************************************************/
1673 gdk_drag_get_selection (GdkDragContext *context)
1675 if (context->protocol == GDK_DRAG_PROTO_LOCAL)
1677 else if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES)
1678 return gdk_win32_dropfiles;
1679 else if (context->protocol == GDK_DRAG_PROTO_OLE2)
1680 return gdk_ole2_dnd;