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