]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdnd-win32.c
add -DG_DISABLE_DEPRECATED and -DGDK_PIXBUF_DISABLE_DEPRECATED to compile
[~andy/gtk] / gdk / win32 / gdkdnd-win32.c
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
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 /*
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/. 
26  */
27
28 #include <string.h>
29
30 /* #define OLE2_DND */
31
32 #define INITGUID
33
34 #include "gdkdnd.h"
35 #include "gdkproperty.h"
36 #include "gdkinternals.h"
37 #include "gdkprivate-win32.h"
38
39 #ifdef OLE2_DND
40 #include <ole2.h>
41 #else
42 #include <objbase.h>
43 #endif
44
45 #include <shlobj.h>
46 #include <shlguid.h>
47
48 #include <gdk/gdk.h>
49
50 typedef struct _GdkDragContextPrivateWin32 GdkDragContextPrivateWin32;
51
52 typedef enum {
53   GDK_DRAG_STATUS_DRAG,
54   GDK_DRAG_STATUS_MOTION_WAIT,
55   GDK_DRAG_STATUS_ACTION_WAIT,
56   GDK_DRAG_STATUS_DROP
57 } GtkDragStatus;
58
59 typedef enum {
60   GDK_DRAG_SOURCE,
61   GDK_DRAG_TARGET
62 } GdkDragKind;
63
64 #ifdef OLE2_DND
65
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]);
79
80
81 static FORMATETC *formats;
82 static int nformats;
83
84 #endif /* OLE2_DND */
85
86 /* Structure that holds information about a drag in progress.
87  * this is used on both source and destination sides.
88  */
89 struct _GdkDragContextPrivateWin32 {
90   gint    ref_count;
91
92   guint16 last_x;               /* Coordinates from last event */
93   guint16 last_y;
94   HWND    dest_xid;
95   guint   drag_status;          /* Current status of drag */
96 };
97
98 #define GDK_DRAG_CONTEXT_PRIVATE_DATA(context) ((GdkDragContextPrivateWin32 *) GDK_DRAG_CONTEXT (context)->windowing_data)
99
100 GdkDragContext *current_dest_drag = NULL;
101
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);
105
106 static gpointer parent_class = NULL;
107 static GList *contexts;
108
109 GType
110 gdk_drag_context_get_type (void)
111 {
112   static GType object_type = 0;
113
114   if (!object_type)
115     {
116       static const GTypeInfo object_info =
117       {
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),
125         0,              /* n_preallocs */
126         (GInstanceInitFunc) gdk_drag_context_init,
127       };
128       
129       object_type = g_type_register_static (G_TYPE_OBJECT,
130                                             "GdkDragContext",
131                                             &object_info, 0);
132     }
133   
134   return object_type;
135 }
136
137 static void
138 gdk_drag_context_init (GdkDragContext *dragcontext)
139 {
140   GdkDragContextPrivateWin32 *private = g_new0 (GdkDragContextPrivateWin32, 1);
141
142   dragcontext->windowing_data = private;
143   private->ref_count = 1;
144
145   contexts = g_list_prepend (contexts, dragcontext);
146 }
147
148 static void
149 gdk_drag_context_class_init (GdkDragContextClass *klass)
150 {
151   GObjectClass *object_class = G_OBJECT_CLASS (klass);
152
153   parent_class = g_type_class_peek_parent (klass);
154
155   object_class->finalize = gdk_drag_context_finalize;
156 }
157
158 static void
159 gdk_drag_context_finalize (GObject *object)
160 {
161   GdkDragContext *context = GDK_DRAG_CONTEXT (object);
162   GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
163   
164   g_list_free (context->targets);
165
166   if (context->source_window)
167     {
168       gdk_window_unref (context->source_window);
169     }
170   
171   if (context->dest_window)
172     gdk_window_unref (context->dest_window);
173   
174   contexts = g_list_remove (contexts, context);
175
176   g_free (private);
177   
178   G_OBJECT_CLASS (parent_class)->finalize (object);
179 }
180
181 /* Drag Contexts */
182
183 GdkDragContext *
184 gdk_drag_context_new (void)
185 {
186   return g_object_new (gdk_drag_context_get_type (), NULL);
187 }
188
189 void
190 gdk_drag_context_ref (GdkDragContext *context)
191 {
192   g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
193
194   GDK_NOTE (DND, g_print ("gdk_drag_context_ref: %p %d\n", context, G_OBJECT(context)->ref_count));
195
196   g_object_ref (context);
197 }
198
199 void
200 gdk_drag_context_unref (GdkDragContext *context)
201 {
202   g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
203
204   GDK_NOTE (DND, g_print ("gdk_drag_context_unref: %p %d\n", context, G_OBJECT(context)->ref_count));
205   g_object_unref (context);
206 }
207
208 static GdkDragContext *
209 gdk_drag_context_find (gboolean   is_source,
210                        GdkWindow *source,
211                        GdkWindow *dest)
212 {
213   GList *tmp_list = contexts;
214   GdkDragContext *context;
215   GdkDragContextPrivateWin32 *private;
216
217   while (tmp_list)
218     {
219       context = (GdkDragContext *)tmp_list->data;
220       private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
221
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))))
225         return context;
226       
227       tmp_list = tmp_list->next;
228     }
229   
230   return NULL;
231 }
232
233
234 typedef struct {
235 #ifdef OLE2_DND
236   IDropTarget idt;
237 #endif
238   GdkDragContext *context;
239 } target_drag_context;
240
241 typedef struct {
242 #ifdef OLE2_DND
243   IDropSource ids;
244 #endif
245   GdkDragContext *context;
246 } source_drag_context;
247
248 #ifdef OLE2_DND
249
250 typedef struct {
251   IDataObject ido;
252   int ref_count;
253 } data_object;
254
255 typedef struct {
256   IEnumFORMATETC ief;
257   int ref_count;
258   int ix;
259 } enum_formats;
260
261 static enum_formats *enum_formats_new (void);
262
263 static ULONG STDMETHODCALLTYPE
264 idroptarget_addref (LPDROPTARGET This)
265 {
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;
269
270   gdk_drag_context_ref (ctx->context);
271   GDK_NOTE (DND, g_print ("idroptarget_addref %#x %d\n", This, ref_count));
272   
273   return ref_count;
274 }
275
276 static HRESULT STDMETHODCALLTYPE
277 idroptarget_queryinterface (LPDROPTARGET This,
278                             REFIID       riid,
279                             LPVOID      *ppvObject)
280 {
281   GDK_NOTE (DND, g_print ("idroptarget_queryinterface %#x\n", This));
282
283   *ppvObject = NULL;
284
285   PRINT_GUID (riid);
286
287   if (IsEqualGUID (riid, &IID_IUnknown))
288     {
289       g_print ("...IUnknown\n");
290       idroptarget_addref (This);
291       *ppvObject = This;
292       return S_OK;
293     }
294   else if (IsEqualGUID (riid, &IID_IDropTarget))
295     {
296       g_print ("...IDropTarget\n");
297       idroptarget_addref (This);
298       *ppvObject = This;
299       return S_OK;
300     }
301   else
302     {
303       g_print ("...Huh?\n");
304       return E_NOINTERFACE;
305     }
306 }
307
308 static ULONG STDMETHODCALLTYPE
309 idroptarget_release (LPDROPTARGET This)
310 {
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;
314
315   gdk_drag_context_unref (ctx->context);
316   GDK_NOTE (DND, g_print ("idroptarget_release %#x %d\n", This, ref_count));
317
318   if (ref_count == 0)
319     g_free (This);
320
321   return ref_count;
322 }
323
324 static HRESULT STDMETHODCALLTYPE 
325 idroptarget_dragenter (LPDROPTARGET This,
326                        LPDATAOBJECT pDataObj,
327                        DWORD        grfKeyState,
328                        POINTL       pt,
329                        LPDWORD      pdwEffect)
330 {
331   GDK_NOTE (DND, g_print ("idroptarget_dragenter %#x\n", This));
332
333   return E_UNEXPECTED;
334 }
335
336 static HRESULT STDMETHODCALLTYPE
337 idroptarget_dragover (LPDROPTARGET This,
338                       DWORD        grfKeyState,
339                       POINTL       pt,
340                       LPDWORD      pdwEffect)
341 {
342   GDK_NOTE (DND, g_print ("idroptarget_dragover %#x\n", This));
343
344   return E_UNEXPECTED;
345 }
346
347 static HRESULT STDMETHODCALLTYPE
348 idroptarget_dragleave (LPDROPTARGET This)
349 {
350   GDK_NOTE (DND, g_print ("idroptarget_dragleave %#x\n", This));
351
352   return E_UNEXPECTED;
353 }
354
355 static HRESULT STDMETHODCALLTYPE
356 idroptarget_drop (LPDROPTARGET This,
357                   LPDATAOBJECT pDataObj,
358                   DWORD        grfKeyState,
359                   POINTL       pt,
360                   LPDWORD      pdwEffect)
361 {
362   GDK_NOTE (DND, g_print ("idroptarget_drop %#x\n", This));
363
364   return E_UNEXPECTED;
365 }
366
367 static ULONG STDMETHODCALLTYPE
368 idropsource_addref (LPDROPSOURCE This)
369 {
370   source_drag_context *ctx = (source_drag_context *) This;
371   GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
372
373   gdk_drag_context_ref (ctx->context);
374   GDK_NOTE (DND, g_print ("idropsource_addref %#x %d\n",
375                           This, private->ref_count));
376   
377   return private->ref_count;
378 }
379
380 static HRESULT STDMETHODCALLTYPE
381 idropsource_queryinterface (LPDROPSOURCE This,
382                             REFIID       riid,
383                             LPVOID      *ppvObject)
384 {
385   GDK_NOTE (DND, g_print ("idropsource_queryinterface %#x\n", This));
386
387   *ppvObject = NULL;
388
389   PRINT_GUID (riid);
390   if (IsEqualGUID (riid, &IID_IUnknown))
391     {
392       g_print ("...IUnknown\n");
393       idropsource_addref (This);
394       *ppvObject = This;
395       return S_OK;
396     }
397   else if (IsEqualGUID (riid, &IID_IDropSource))
398     {
399       g_print ("...IDropSource\n");
400       idropsource_addref (This);
401       *ppvObject = This;
402       return S_OK;
403     }
404   else
405     {
406       g_print ("...Huh?\n");
407       return E_NOINTERFACE;
408     }
409 }
410
411 static ULONG STDMETHODCALLTYPE
412 idropsource_release (LPDROPSOURCE This)
413 {
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;
417
418   gdk_drag_context_unref (ctx->context);
419   GDK_NOTE (DND, g_print ("idropsource_release %#x %d\n", This, ref_count));
420
421   if (ref_count == 0)
422     g_free (This);
423
424   return ref_count;
425 }
426
427 static HRESULT STDMETHODCALLTYPE
428 idropsource_querycontinuedrag (LPDROPSOURCE This,
429                                BOOL         fEscapePressed,
430                                DWORD        grfKeyState)
431 {
432   GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag %#x\n", This));
433
434   return E_UNEXPECTED;
435 }
436
437 static HRESULT STDMETHODCALLTYPE
438 idropsource_givefeedback (LPDROPSOURCE This,
439                           DWORD        dwEffect)
440 {
441   GDK_NOTE (DND, g_print ("idropsource_givefeedback %#x\n", This));
442
443   return E_UNEXPECTED;
444 }
445
446 static ULONG STDMETHODCALLTYPE
447 idataobject_addref (LPDATAOBJECT This)
448 {
449   data_object *dobj = (data_object *) This;
450   int ref_count = ++dobj->ref_count;
451
452   GDK_NOTE (DND, g_print ("idataobject_addref %#x %d\n", This, ref_count));
453
454   return ref_count;
455 }
456
457 static HRESULT STDMETHODCALLTYPE
458 idataobject_queryinterface (LPDATAOBJECT This,
459                             REFIID       riid,
460                             LPVOID      *ppvObject)
461 {
462   GDK_NOTE (DND, g_print ("idataobject_queryinterface %#x\n", This));
463
464   *ppvObject = NULL;
465
466   PRINT_GUID (riid);
467   if (IsEqualGUID (riid, &IID_IUnknown))
468     {
469       g_print ("...IUnknown\n");
470       idataobject_addref (This);
471       *ppvObject = This;
472       return S_OK;
473     }
474   else if (IsEqualGUID (riid, &IID_IDataObject))
475     {
476       g_print ("...IDataObject\n");
477       idataobject_addref (This);
478       *ppvObject = This;
479       return S_OK;
480     }
481   else
482     {
483       g_print ("...Huh?\n");
484       return E_NOINTERFACE;
485     }
486 }
487
488 static ULONG STDMETHODCALLTYPE
489 idataobject_release (LPDATAOBJECT This)
490 {
491   data_object *dobj = (data_object *) This;
492   int ref_count = --dobj->ref_count;
493
494   GDK_NOTE (DND, g_print ("idataobject_release %#x %d\n", This, ref_count));
495
496   if (ref_count == 0)
497     g_free (This);
498
499   return ref_count;
500 }
501
502 static HRESULT STDMETHODCALLTYPE
503 idataobject_getdata (LPDATAOBJECT This,
504                      LPFORMATETC  pFormatEtc,
505                      LPSTGMEDIUM  pMedium)
506 {
507   GDK_NOTE (DND, g_print ("idataobject_getdata %#x\n", This));
508
509   return E_UNEXPECTED;
510 }
511
512 static HRESULT STDMETHODCALLTYPE
513 idataobject_getdatahere (LPDATAOBJECT This,
514                          LPFORMATETC  pFormatEtc,
515                          LPSTGMEDIUM  pMedium)
516 {
517   GDK_NOTE (DND, g_print ("idataobject_getdatahere %#x\n", This));
518
519   return E_UNEXPECTED;
520 }
521
522 static HRESULT STDMETHODCALLTYPE
523 idataobject_querygetdata (LPDATAOBJECT This,
524                           LPFORMATETC  pFormatEtc)
525 {
526   int i;
527
528   GDK_NOTE (DND, g_print ("idataobject_querygetdata %#x %#x", This, pFormatEtc->cfFormat));
529
530   for (i = 0; i < nformats; i++)
531     if (pFormatEtc->cfFormat == formats[i].cfFormat)
532       {
533         GDK_NOTE (DND, g_print (" S_OK\n"));
534         return S_OK;
535       }
536
537   GDK_NOTE (DND, g_print (" DV_E_FORMATETC\n"));
538   return DV_E_FORMATETC;
539 }
540
541 static HRESULT STDMETHODCALLTYPE
542 idataobject_getcanonicalformatetc (LPDATAOBJECT This,
543                                    LPFORMATETC  pFormatEtcIn,
544                                    LPFORMATETC  pFormatEtcOut)
545 {
546   GDK_NOTE (DND, g_print ("idataobject_getcanonicalformatetc %#x\n", This));
547
548   return E_FAIL;
549 }
550
551 static HRESULT STDMETHODCALLTYPE
552 idataobject_setdata (LPDATAOBJECT This,
553                      LPFORMATETC  pFormatEtc,
554                      LPSTGMEDIUM  pMedium,
555                      BOOL         fRelease)
556 {
557   GDK_NOTE (DND, g_print ("idataobject_setdata %#x\n", This));
558
559   return E_UNEXPECTED;
560 }
561
562 static HRESULT STDMETHODCALLTYPE
563 idataobject_enumformatetc (LPDATAOBJECT     This,
564                            DWORD            dwDirection,
565                            LPENUMFORMATETC *ppEnumFormatEtc)
566 {
567   GDK_NOTE (DND, g_print ("idataobject_enumformatetc %#x\n", This));
568
569   if (dwDirection != DATADIR_GET)
570     return E_NOTIMPL;
571
572   *ppEnumFormatEtc = &enum_formats_new ()->ief;
573   return S_OK;
574 }
575
576 static HRESULT STDMETHODCALLTYPE
577 idataobject_dadvise (LPDATAOBJECT This,
578                      LPFORMATETC  pFormatetc,
579                      DWORD        advf,
580                      LPADVISESINK pAdvSink,
581                      DWORD       *pdwConnection)
582 {
583   GDK_NOTE (DND, g_print ("idataobject_dadvise %#x\n", This));
584
585   return E_FAIL;
586 }
587
588 static HRESULT STDMETHODCALLTYPE
589 idataobject_dunadvise (LPDATAOBJECT This,
590                        DWORD         dwConnection)
591 {
592   GDK_NOTE (DND, g_print ("idataobject_dunadvise %#x\n", This));
593
594   return E_FAIL;
595 }
596
597 static HRESULT STDMETHODCALLTYPE
598 idataobject_enumdadvise (LPDATAOBJECT    This,
599                          LPENUMSTATDATA *ppenumAdvise)
600 {
601   GDK_NOTE (DND, g_print ("idataobject_enumdadvise %#x\n", This));
602
603   return E_FAIL;
604 }
605                 
606 static ULONG STDMETHODCALLTYPE
607 ienumformatetc_addref (LPENUMFORMATETC This)
608 {
609   enum_formats *en = (enum_formats *) This;
610   int ref_count = ++en->ref_count;
611
612   GDK_NOTE (DND, g_print ("ienumformatetc_addref %#x %d\n", This, ref_count));
613
614   return ref_count;
615 }
616
617 static HRESULT STDMETHODCALLTYPE
618 ienumformatetc_queryinterface (LPENUMFORMATETC This,
619                                REFIID          riid,
620                                LPVOID         *ppvObject)
621 {
622   GDK_NOTE (DND, g_print ("ienumformatetc_queryinterface %#x\n", This));
623
624   *ppvObject = NULL;
625
626   PRINT_GUID (riid);
627   if (IsEqualGUID (riid, &IID_IUnknown))
628     {
629       g_print ("...IUnknown\n");
630       ienumformatetc_addref (This);
631       *ppvObject = This;
632       return S_OK;
633     }
634   else if (IsEqualGUID (riid, &IID_IEnumFORMATETC))
635     {
636       g_print ("...IEnumFORMATETC\n");
637       ienumformatetc_addref (This);
638       *ppvObject = This;
639       return S_OK;
640     }
641   else
642     {
643       g_print ("...Huh?\n");
644       return E_NOINTERFACE;
645     }
646 }
647
648 static ULONG STDMETHODCALLTYPE
649 ienumformatetc_release (LPENUMFORMATETC This)
650 {
651   enum_formats *en = (enum_formats *) This;
652   int ref_count = --en->ref_count;
653
654   GDK_NOTE (DND, g_print ("ienumformatetc_release %#x %d\n", This, ref_count));
655
656   if (ref_count == 0)
657     g_free (This);
658
659   return ref_count;
660 }
661
662 static HRESULT STDMETHODCALLTYPE
663 ienumformatetc_next (LPENUMFORMATETC This,
664                      ULONG           celt,
665                      LPFORMATETC     elts,
666                      ULONG          *nelt)
667 {
668   enum_formats *en = (enum_formats *) This;
669   int i, n;
670
671   GDK_NOTE (DND, g_print ("ienumformatetc_next %#x %d %d\n", This, en->ix, celt));
672
673   n = 0;
674   for (i = 0; i < celt; i++)
675     {
676       if (en->ix >= nformats)
677         break;
678       elts[i] = formats[en->ix++];
679       n++;
680     }
681
682   if (nelt != NULL)
683     *nelt = n;
684
685   if (n == celt)
686     return S_OK;
687   else
688     return S_FALSE;
689 }
690
691 static HRESULT STDMETHODCALLTYPE
692 ienumformatetc_skip (LPENUMFORMATETC This,
693                      ULONG           celt)
694 {
695   enum_formats *en = (enum_formats *) This;
696
697   GDK_NOTE (DND, g_print ("ienumformatetc_skip %#x %d %d\n", This, en->ix, celt));
698   en->ix += celt;
699
700   return S_OK;
701 }
702
703 static HRESULT STDMETHODCALLTYPE
704 ienumformatetc_reset (LPENUMFORMATETC This)
705 {
706   enum_formats *en = (enum_formats *) This;
707
708   GDK_NOTE (DND, g_print ("ienumformatetc_reset %#x\n", This));
709
710   en->ix = 0;
711
712   return S_OK;
713 }
714
715 static HRESULT STDMETHODCALLTYPE
716 ienumformatetc_clone (LPENUMFORMATETC  This,
717                       LPENUMFORMATETC *ppEnumFormatEtc)
718 {
719   enum_formats *en = (enum_formats *) This;
720   enum_formats *new;
721
722   GDK_NOTE (DND, g_print ("ienumformatetc_clone %#x\n", This));
723
724   new = enum_formats_new ();
725
726   new->ix = en->ix;
727
728   *ppEnumFormatEtc = &new->ief;
729
730   return S_OK;
731 }
732
733 static IDropTargetVtbl idt_vtbl = {
734   idroptarget_queryinterface,
735   idroptarget_addref,
736   idroptarget_release,
737   idroptarget_dragenter,
738   idroptarget_dragover,
739   idroptarget_dragleave,
740   idroptarget_drop
741 };
742
743 static IDropSourceVtbl ids_vtbl = {
744   idropsource_queryinterface,
745   idropsource_addref,
746   idropsource_release,
747   idropsource_querycontinuedrag,
748   idropsource_givefeedback
749 };
750
751 static IDataObjectVtbl ido_vtbl = {
752   idataobject_queryinterface,
753   idataobject_addref,
754   idataobject_release,
755   idataobject_getdata,
756   idataobject_getdatahere,
757   idataobject_querygetdata,
758   idataobject_getcanonicalformatetc,
759   idataobject_setdata,
760   idataobject_enumformatetc,
761   idataobject_dadvise,
762   idataobject_dunadvise,
763   idataobject_enumdadvise
764 };
765
766 static IEnumFORMATETCVtbl ief_vtbl = {
767   ienumformatetc_queryinterface,
768   ienumformatetc_addref,
769   ienumformatetc_release,
770   ienumformatetc_next,
771   ienumformatetc_skip,
772   ienumformatetc_reset,
773   ienumformatetc_clone
774 };
775
776 #endif /* OLE2_DND */
777
778 static target_drag_context *
779 target_context_new (void)
780 {
781   target_drag_context *result;
782
783   result = g_new0 (target_drag_context, 1);
784
785 #ifdef OLE2_DND
786   result->idt.lpVtbl = &idt_vtbl;
787 #endif
788
789   result->context = gdk_drag_context_new ();
790   result->context->is_source = FALSE;
791
792   GDK_NOTE (DND, g_print ("target_context_new: %p\n", result));
793
794   return result;
795 }
796
797 static source_drag_context *
798 source_context_new (void)
799 {
800   source_drag_context *result;
801
802   result = g_new0 (source_drag_context, 1);
803
804 #ifdef OLE2_DND
805   result->ids.lpVtbl = &ids_vtbl;
806 #endif
807
808   result->context = gdk_drag_context_new ();
809   result->context->is_source = TRUE;
810
811   GDK_NOTE (DND, g_print ("source_context_new: %p\n", result));
812
813   return result;
814 }
815
816 #ifdef OLE2_DND
817 static data_object *
818 data_object_new (void)
819 {
820   data_object *result;
821
822   result = g_new0 (data_object, 1);
823
824   result->ido.lpVtbl = &ido_vtbl;
825   result->ref_count = 1;
826
827   GDK_NOTE (DND, g_print ("data_object_new: %#x\n", result));
828
829   return result;
830 }
831
832
833 static enum_formats *
834 enum_formats_new (void)
835 {
836   enum_formats *result;
837
838   result = g_new0 (enum_formats, 1);
839
840   result->ief.lpVtbl = &ief_vtbl;
841   result->ref_count = 1;
842   result->ix = 0;
843
844   GDK_NOTE (DND, g_print ("enum_formats_new: %#x\n", result));
845
846   return result;
847 }
848
849 #endif
850
851 /* From MS Knowledge Base article Q130698 */
852
853 /* resolve_link() fills the filename and path buffer
854  * with relevant information
855  * hWnd         - calling app's window handle.
856  *
857  * lpszLinkName - name of the link file passed into the function.
858  *
859  * lpszPath     - the buffer that will receive the file pathname.
860  */
861
862 static HRESULT 
863 resolve_link(HWND    hWnd,
864              LPCTSTR lpszLinkName,
865              LPSTR   lpszPath,
866              LPSTR   lpszDescription)
867 {
868   HRESULT hres;
869   IShellLink *psl;
870   WIN32_FIND_DATA wfd;
871
872   /* Assume Failure to start with: */
873   *lpszPath = 0;
874   if (lpszDescription)
875     *lpszDescription = 0;
876
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.
880    */
881
882   hres = CoCreateInstance (&CLSID_ShellLink,
883                            NULL,
884                            CLSCTX_INPROC_SERVER,
885                            &IID_IShellLink,
886                            (LPVOID *)&psl);
887   if (SUCCEEDED (hres))
888    {
889      IPersistFile *ppf;
890      
891      /* The IShellLink interface supports the IPersistFile
892       * interface. Get an interface pointer to it.
893       */
894      hres = psl->lpVtbl->QueryInterface (psl,
895                                          &IID_IPersistFile,
896                                          (LPVOID *) &ppf);
897      if (SUCCEEDED (hres))
898        {
899          WORD wsz[MAX_PATH];
900
901          /* Convert the given link name string to wide character string. */
902          MultiByteToWideChar (CP_ACP, 0,
903                               lpszLinkName,
904                               -1, wsz, MAX_PATH);
905          /* Load the file. */
906          hres = ppf->lpVtbl->Load (ppf, wsz, STGM_READ);
907          if (SUCCEEDED (hres))
908            {
909              /* Resolve the link by calling the Resolve()
910               * interface function.
911               */
912              hres = psl->lpVtbl->Resolve(psl,  hWnd,
913                                          SLR_ANY_MATCH |
914                                          SLR_NO_UI);
915              if (SUCCEEDED (hres))
916                {
917                  hres = psl->lpVtbl->GetPath (psl, lpszPath,
918                                               MAX_PATH,
919                                               (WIN32_FIND_DATA*)&wfd,
920                                               0);
921
922                  if (SUCCEEDED (hres) && lpszDescription != NULL)
923                    {
924                      hres = psl->lpVtbl->GetDescription (psl,
925                                                          lpszDescription,
926                                                          MAX_PATH );
927
928                      if (!SUCCEEDED (hres))
929                        return FALSE;
930                    }
931                }
932            }
933          ppf->lpVtbl->Release (ppf);
934        }
935      psl->lpVtbl->Release (psl);
936    }
937   return SUCCEEDED (hres);
938 }
939
940 static GdkFilterReturn
941 gdk_dropfiles_filter (GdkXEvent *xev,
942                       GdkEvent  *event,
943                       gpointer   data)
944 {
945   GdkDragContext *context;
946   GdkDragContextPrivateWin32 *private;
947   GString *result;
948   MSG *msg = (MSG *) xev;
949   HANDLE hdrop;
950   POINT pt;
951   gint nfiles, i;
952   guchar fileName[MAX_PATH], linkedFile[MAX_PATH];
953   
954   if (msg->message == WM_DROPFILES)
955     {
956       GDK_NOTE (DND, g_print ("WM_DROPFILES: %#x\n", (guint) msg->hwnd));
957
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 */
967       context->targets =
968         g_list_append (NULL, GUINT_TO_POINTER (text_uri_list));
969       current_dest_drag = context;
970
971       event->dnd.type = GDK_DROP_START;
972       event->dnd.context = current_dest_drag;
973       
974       hdrop = (HANDLE) msg->wParam;
975       DragQueryPoint (hdrop, &pt);
976       ClientToScreen (msg->hwnd, &pt);
977
978       event->dnd.x_root = pt.x;
979       event->dnd.y_root = pt.y;
980       event->dnd.time = msg->time;
981
982       nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
983
984       result = g_string_new (NULL);
985       for (i = 0; i < nfiles; i++)
986         {
987           gchar *uri;
988
989           DragQueryFile (hdrop, i, fileName, MAX_PATH);
990
991           /* Resolve shortcuts */
992           if (resolve_link (msg->hwnd, fileName, linkedFile, NULL))
993             {
994               uri = g_filename_to_uri (linkedFile, NULL, NULL);
995               if (uri != NULL)
996                 {
997                   g_string_append (result, uri);
998                   GDK_NOTE (DND, g_print ("...%s link to %s: %s\n",
999                                           fileName, linkedFile, uri));
1000                   g_free (uri);
1001                 }
1002             }
1003           else
1004             {
1005               uri = g_filename_to_uri (fileName, NULL, NULL);
1006               if (uri != NULL)
1007                 {
1008                   g_string_append (result, uri);
1009                   GDK_NOTE (DND, g_print ("...%s: %s\n", fileName, uri));
1010                   g_free (uri);
1011                 }
1012             }
1013           g_string_append (result, "\015\012");
1014         }
1015       _gdk_dropfiles_store (result->str);
1016       g_string_free (result, FALSE);
1017
1018       DragFinish (hdrop);
1019       
1020       return GDK_FILTER_TRANSLATE;
1021     }
1022   else
1023     return GDK_FILTER_CONTINUE;
1024 }
1025
1026 /*************************************************************
1027  ************************** Public API ***********************
1028  *************************************************************/
1029
1030 void
1031 _gdk_dnd_init (void)
1032 {
1033 #ifdef OLE2_DND
1034   HRESULT hres;
1035   hres = OleInitialize (NULL);
1036
1037   if (! SUCCEEDED (hres))
1038     g_error ("OleInitialize failed");
1039
1040   nformats = 2;
1041   formats = g_new (FORMATETC, nformats);
1042
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;
1048   
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;
1054 #endif
1055 }      
1056
1057 void
1058 _gdk_win32_dnd_exit (void)
1059 {
1060 #ifdef OLE2_DND
1061   OleUninitialize ();
1062 #endif
1063 }
1064
1065 /* Source side */
1066
1067 static void
1068 local_send_leave (GdkDragContext *context,
1069                   guint32         time)
1070 {
1071   GdkEvent tmp_event;
1072   
1073   if ((current_dest_drag != NULL) &&
1074       (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
1075       (current_dest_drag->source_window == context->source_window))
1076     {
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? */
1083
1084       current_dest_drag = NULL;
1085       
1086       gdk_event_put (&tmp_event);
1087     }
1088 }
1089
1090 static void
1091 local_send_enter (GdkDragContext *context,
1092                   guint32         time)
1093 {
1094   GdkEvent tmp_event;
1095   GdkDragContextPrivateWin32 *private;
1096   GdkDragContext *new_context;
1097
1098   private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
1099   
1100   if (current_dest_drag != NULL)
1101     {
1102       gdk_drag_context_unref (current_dest_drag);
1103       current_dest_drag = NULL;
1104     }
1105
1106   new_context = gdk_drag_context_new ();
1107   new_context->protocol = GDK_DRAG_PROTO_LOCAL;
1108   new_context->is_source = FALSE;
1109
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);
1114
1115   new_context->targets = g_list_copy (context->targets);
1116
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;
1121
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? */
1127   
1128   current_dest_drag = new_context;
1129   
1130   gdk_event_put (&tmp_event);
1131 }
1132
1133 static void
1134 local_send_motion (GdkDragContext *context,
1135                    gint            x_root, 
1136                    gint            y_root,
1137                    GdkDragAction   action,
1138                    guint32         time)
1139 {
1140   GdkEvent tmp_event;
1141   
1142   if ((current_dest_drag != NULL) &&
1143       (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
1144       (current_dest_drag->source_window == context->source_window))
1145     {
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;
1151
1152       current_dest_drag->suggested_action = action;
1153       current_dest_drag->actions = current_dest_drag->suggested_action;
1154
1155       tmp_event.dnd.x_root = x_root;
1156       tmp_event.dnd.y_root = y_root;
1157
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;
1160
1161       GDK_DRAG_CONTEXT_PRIVATE_DATA (context)->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
1162       
1163       gdk_event_put (&tmp_event);
1164     }
1165 }
1166
1167 static void
1168 local_send_drop (GdkDragContext *context,
1169                  guint32         time)
1170 {
1171   GdkEvent tmp_event;
1172   
1173   if ((current_dest_drag != NULL) &&
1174       (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
1175       (current_dest_drag->source_window == context->source_window))
1176     {
1177       GdkDragContextPrivateWin32 *private;
1178       private = GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag);
1179
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;
1185       
1186       tmp_event.dnd.x_root = private->last_x;
1187       tmp_event.dnd.y_root = private->last_y;
1188       
1189       gdk_event_put (&tmp_event);
1190     }
1191
1192 }
1193
1194 static void
1195 gdk_drag_do_leave (GdkDragContext *context,
1196                    guint32         time)
1197 {
1198   if (context->dest_window)
1199     {
1200       GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n"));
1201
1202       switch (context->protocol)
1203         {
1204         case GDK_DRAG_PROTO_LOCAL:
1205           local_send_leave (context, time);
1206           break;
1207         default:
1208           break;
1209         }
1210
1211       gdk_drawable_unref (context->dest_window);
1212       context->dest_window = NULL;
1213     }
1214 }
1215
1216 GdkDragContext * 
1217 gdk_drag_begin (GdkWindow *window,
1218                 GList     *targets)
1219 {
1220 #ifndef OLE2_DND
1221   GList *tmp_list;
1222   GdkDragContext *new_context;
1223
1224   g_return_val_if_fail (window != NULL, NULL);
1225
1226   new_context = gdk_drag_context_new ();
1227   new_context->is_source = TRUE;
1228   new_context->source_window = window;
1229   gdk_window_ref (window);
1230
1231   tmp_list = g_list_last (targets);
1232   new_context->targets = NULL;
1233   while (tmp_list)
1234     {
1235       new_context->targets = g_list_prepend (new_context->targets,
1236                                              tmp_list->data);
1237       tmp_list = tmp_list->prev;
1238     }
1239
1240   new_context->actions = 0;
1241
1242   return new_context;
1243 #else
1244   source_drag_context *ctx;
1245   GList *tmp_list;
1246   data_object *dobj;
1247   HRESULT hResult;
1248   DWORD dwEffect;
1249   HGLOBAL global;
1250   FORMATETC format;
1251   STGMEDIUM medium;
1252
1253   g_return_val_if_fail (window != NULL, NULL);
1254
1255   GDK_NOTE (DND, g_print ("gdk_drag_begin\n"));
1256
1257   ctx = source_context_new ();
1258   ctx->context->protocol = GDK_DRAG_PROTO_OLE2;
1259   ctx->context->source_window = window;
1260   gdk_drawable_ref (window);
1261
1262   tmp_list = g_list_last (targets);
1263   ctx->context->targets = NULL;
1264   while (tmp_list)
1265     {
1266       ctx->context->targets = g_list_prepend (ctx->context->targets,
1267                                               tmp_list->data);
1268       tmp_list = tmp_list->prev;
1269     }
1270
1271   ctx->context->actions = 0;
1272
1273   dobj = data_object_new ();
1274
1275   global = GlobalAlloc (GMEM_FIXED, sizeof (ctx));
1276
1277   memcpy (&global, ctx, sizeof (ctx));
1278
1279   medium.tymed = TYMED_HGLOBAL;
1280   medium.hGlobal = global;
1281   medium.pUnkForRelease = NULL;
1282
1283   dobj->ido.lpVtbl->SetData (&dobj->ido, &formats[1], &medium, TRUE);
1284
1285   hResult = DoDragDrop (&dobj->ido, &ctx->ids, DROPEFFECT_MOVE|DROPEFFECT_COPY, &dwEffect);
1286
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))))));
1292
1293   dobj->ido.lpVtbl->Release (&dobj->ido);
1294   ctx->ids.lpVtbl->Release (&ctx->ids);
1295
1296   return ctx->context;
1297 #endif
1298 }
1299
1300 guint32
1301 gdk_drag_get_protocol (guint32          xid,
1302                        GdkDragProtocol *protocol)
1303 {
1304   GdkWindow *window;
1305
1306   GDK_NOTE (DND, g_print ("gdk_drag_get_protocol\n"));
1307
1308   window = gdk_window_lookup (xid);
1309
1310   if (GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
1311     {
1312       *protocol = GDK_DRAG_PROTO_LOCAL;
1313       return xid;
1314     }
1315
1316   return 0;
1317 }
1318
1319 void
1320 gdk_drag_find_window (GdkDragContext  *context,
1321                       GdkWindow       *drag_window,
1322                       gint             x_root,
1323                       gint             y_root,
1324                       GdkWindow      **dest_window,
1325                       GdkDragProtocol *protocol)
1326 {
1327   HWND recipient;
1328   POINT pt;
1329
1330   pt.x = x_root;
1331   pt.y = y_root;
1332   recipient = WindowFromPoint (pt);
1333   if (recipient == NULL)
1334     *dest_window = NULL;
1335   else
1336     {
1337       *dest_window = gdk_win32_handle_table_lookup (GPOINTER_TO_UINT(recipient));
1338       if (*dest_window)
1339         {
1340           *dest_window = gdk_window_get_toplevel (*dest_window);
1341           gdk_drawable_ref (*dest_window);
1342         }
1343
1344       if (context->source_window)
1345         *protocol = GDK_DRAG_PROTO_LOCAL;
1346       else
1347         *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
1348     }
1349
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));
1353 }
1354
1355 gboolean
1356 gdk_drag_motion (GdkDragContext *context,
1357                  GdkWindow      *dest_window,
1358                  GdkDragProtocol protocol,
1359                  gint            x_root, 
1360                  gint            y_root,
1361                  GdkDragAction   suggested_action,
1362                  GdkDragAction   possible_actions,
1363                  guint32         time)
1364 {
1365   GdkDragContextPrivateWin32 *private;
1366
1367   g_return_val_if_fail (context != NULL, FALSE);
1368
1369   GDK_NOTE (DND, g_print ("gdk_drag_motion\n"));
1370
1371   private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
1372   
1373   if (context->dest_window != dest_window)
1374     {
1375       GdkEvent temp_event;
1376
1377       /* Send a leave to the last destination */
1378       gdk_drag_do_leave (context, time);
1379       private->drag_status = GDK_DRAG_STATUS_DRAG;
1380
1381       /* Check if new destination accepts drags, and which protocol */
1382       if (dest_window)
1383         {
1384           context->dest_window = dest_window;
1385           gdk_window_ref (context->dest_window);
1386           context->protocol = protocol;
1387
1388           switch (protocol)
1389             {
1390             case GDK_DRAG_PROTO_LOCAL:
1391               local_send_enter (context, time);
1392               break;
1393
1394             default:
1395               break;
1396             }
1397           context->suggested_action = suggested_action;
1398         }
1399       else
1400         {
1401           context->dest_window = NULL;
1402           context->action = 0;
1403         }
1404
1405       /* Push a status event, to let the client know that
1406        * the drag changed 
1407        */
1408
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...
1413        */
1414       temp_event.dnd.send_event = TRUE;
1415
1416       temp_event.dnd.context = context;
1417       temp_event.dnd.time = time;
1418
1419       gdk_event_put (&temp_event);
1420     }
1421   else
1422     {
1423       context->suggested_action = suggested_action;
1424     }
1425
1426   /* Send a drag-motion event */
1427
1428   private->last_x = x_root;
1429   private->last_y = y_root;
1430       
1431   if (context->dest_window)
1432     {
1433       if (private->drag_status == GDK_DRAG_STATUS_DRAG)
1434         {
1435           switch (context->protocol)
1436             {
1437             case GDK_DRAG_PROTO_LOCAL:
1438               local_send_motion (context, x_root, y_root, suggested_action, time);
1439               break;
1440               
1441             case GDK_DRAG_PROTO_NONE:
1442               g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
1443               break;
1444
1445             default:
1446               break;
1447             }
1448         }
1449       else
1450         return TRUE;
1451     }
1452
1453   return FALSE;
1454 }
1455
1456 void
1457 gdk_drag_drop (GdkDragContext *context,
1458                guint32         time)
1459 {
1460   g_return_if_fail (context != NULL);
1461
1462   GDK_NOTE (DND, g_print ("gdk_drag_drop\n"));
1463
1464   if (context->dest_window)
1465     {
1466       switch (context->protocol)
1467         {
1468         case GDK_DRAG_PROTO_LOCAL:
1469           local_send_drop (context, time);
1470           break;
1471
1472         case GDK_DRAG_PROTO_NONE:
1473           g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
1474           break;
1475
1476         default:
1477           break;
1478         }
1479     }
1480 }
1481
1482 void
1483 gdk_drag_abort (GdkDragContext *context,
1484                 guint32         time)
1485 {
1486   g_return_if_fail (context != NULL);
1487
1488   GDK_NOTE (DND, g_print ("gdk_drag_abort\n"));
1489
1490   gdk_drag_do_leave (context, time);
1491 }
1492
1493 /* Destination side */
1494
1495 void
1496 gdk_drag_status (GdkDragContext *context,
1497                  GdkDragAction   action,
1498                  guint32         time)
1499 {
1500   GdkDragContextPrivateWin32 *private;
1501   GdkDragContext *src_context;
1502   GdkEvent tmp_event;
1503
1504   g_return_if_fail (context != NULL);
1505
1506   private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
1507
1508   src_context = gdk_drag_context_find (TRUE,
1509                                        context->source_window,
1510                                        context->dest_window);
1511
1512   if (src_context)
1513     {
1514       GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (src_context);
1515       
1516       if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
1517         private->drag_status = GDK_DRAG_STATUS_DRAG;
1518
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? */
1524
1525       if (action == GDK_ACTION_DEFAULT)
1526         action = 0;
1527       
1528       src_context->action = action;
1529       
1530       gdk_event_put (&tmp_event);
1531     }
1532 }
1533
1534 void 
1535 gdk_drop_reply (GdkDragContext *context,
1536                 gboolean        ok,
1537                 guint32         time)
1538 {
1539   g_return_if_fail (context != NULL);
1540
1541   GDK_NOTE (DND, g_print ("gdk_drop_reply\n"));
1542
1543   if (context->dest_window)
1544     {
1545       switch (context->protocol)
1546         {
1547         case GDK_DRAG_PROTO_WIN32_DROPFILES:
1548           _gdk_dropfiles_store (NULL);
1549           break;
1550
1551         default:
1552           break;
1553         }
1554     }
1555 }
1556
1557 void
1558 gdk_drop_finish (GdkDragContext *context,
1559                  gboolean        success,
1560                  guint32         time)
1561 {
1562   GdkDragContextPrivateWin32 *private;
1563   GdkDragContext *src_context;
1564   GdkEvent tmp_event;
1565         
1566   g_return_if_fail (context != NULL);
1567
1568   GDK_NOTE (DND, g_print ("gdk_drop_finish\n"));
1569
1570   private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
1571
1572   src_context = gdk_drag_context_find (TRUE,
1573                                        context->source_window,
1574                                        context->dest_window);
1575   if (src_context)
1576     {
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;
1581
1582       gdk_event_put (&tmp_event);
1583     }
1584 }
1585
1586 #ifdef OLE2_DND
1587
1588 static GdkFilterReturn
1589 gdk_destroy_filter (GdkXEvent *xev,
1590                     GdkEvent  *event,
1591                     gpointer   data)
1592 {
1593   MSG *msg = (MSG *) xev;
1594
1595   if (msg->message == WM_DESTROY)
1596     {
1597       IDropTarget *idtp = (IDropTarget *) data;
1598
1599       GDK_NOTE (DND, g_print ("gdk_destroy_filter: WM_DESTROY: %#x\n", msg->hwnd));
1600 #if 0
1601       idtp->lpVtbl->Release (idtp);
1602 #endif
1603       RevokeDragDrop (msg->hwnd);
1604       CoLockObjectExternal (idtp, FALSE, TRUE);
1605     }
1606   return GDK_FILTER_CONTINUE;
1607 }
1608 #endif
1609
1610 void
1611 gdk_window_register_dnd (GdkWindow *window)
1612 {
1613 #ifdef OLE2_DND
1614   target_drag_context *ctx;
1615   HRESULT hres;
1616 #endif
1617
1618   g_return_if_fail (window != NULL);
1619
1620   if (GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
1621     return;
1622
1623   gdk_drawable_set_data (window, "gdk-dnd-registered", GINT_TO_POINTER(TRUE), NULL);
1624
1625   GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %#x\n",
1626                           (guint) GDK_WINDOW_HWND (window)));
1627
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.
1632    */
1633   gdk_window_add_filter (window, gdk_dropfiles_filter, NULL);
1634   DragAcceptFiles (GDK_WINDOW_HWND (window), TRUE);
1635
1636 #ifdef OLE2_DND
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");
1643   else
1644     {
1645       hres = RegisterDragDrop (GDK_WINDOW_HWND (window), &ctx->idt);
1646       if (hres == DRAGDROP_E_ALREADYREGISTERED)
1647         {
1648           g_print ("DRAGDROP_E_ALREADYREGISTERED\n");
1649 #if 0
1650           ctx->idt.lpVtbl->Release (&ctx->idt);
1651 #endif
1652           CoLockObjectExternal ((IUnknown *) &ctx->idt, FALSE, FALSE);
1653         }
1654       else if (!SUCCEEDED (hres))
1655         OTHER_API_FAILED ("RegisterDragDrop");
1656       else
1657         {
1658           gdk_window_add_filter (window, gdk_destroy_filter, &ctx->idt);
1659         }
1660     }
1661 #endif
1662 }
1663
1664 /*************************************************************
1665  * gdk_drag_get_selection:
1666  *     Returns the selection atom for the current source window
1667  *   arguments:
1668  *
1669  *   results:
1670  *************************************************************/
1671
1672 GdkAtom
1673 gdk_drag_get_selection (GdkDragContext *context)
1674 {
1675   if (context->protocol == GDK_DRAG_PROTO_LOCAL)
1676     return local_dnd;
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;
1681   else
1682     return GDK_NONE;
1683 }