]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkdnd-win32.c
Win32 version of GDK source files and resource files (cursors and icons).
[~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 Library 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  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library 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-1999.  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 #define INITGUID
31
32 #include <string.h>
33 #include "gdk.h"
34 #include "gdkx.h"
35 #include "gdk/gdkprivate.h"
36 #include <ole2.h>
37 #include <shlobj.h>
38 #include <shlguid.h>
39
40 typedef struct _GdkDragContextPrivate GdkDragContextPrivate;
41
42 typedef enum {
43   GDK_DRAG_STATUS_DRAG,
44   GDK_DRAG_STATUS_MOTION_WAIT,
45   GDK_DRAG_STATUS_ACTION_WAIT,
46   GDK_DRAG_STATUS_DROP
47 } GtkDragStatus;
48
49 typedef enum {
50   GDK_DRAG_SOURCE,
51   GDK_DRAG_TARGET
52 } GdkDragKind;
53
54 #ifdef OLE2_DND
55
56 HRESULT STDMETHODCALLTYPE
57   m_query_interface_target (IDropTarget __RPC_FAR *This,
58                             /* [in] */ REFIID riid,
59                             /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
60
61 ULONG STDMETHODCALLTYPE
62   m_add_ref_target (IDropTarget __RPC_FAR *This);
63
64 ULONG STDMETHODCALLTYPE
65   m_release_target (IDropTarget __RPC_FAR *This);
66
67 HRESULT STDMETHODCALLTYPE 
68   m_drag_enter (IDropTarget __RPC_FAR *This,
69                 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
70                 /* [in] */ DWORD grfKeyState,
71                 /* [in] */ POINTL pt,
72                 /* [out][in] */ DWORD __RPC_FAR *pdwEffect);
73
74 HRESULT STDMETHODCALLTYPE
75   m_drag_over (IDropTarget __RPC_FAR *This,
76                /* [in] */ DWORD grfKeyState,
77                /* [in] */ POINTL pt,
78                /* [out][in] */ DWORD __RPC_FAR *pdwEffect);
79
80 HRESULT STDMETHODCALLTYPE
81   m_drag_leave (IDropTarget __RPC_FAR *This);
82
83 HRESULT STDMETHODCALLTYPE
84   m_drop (IDropTarget __RPC_FAR *This,
85           /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
86           /* [in] */ DWORD grfKeyState,
87           /* [in] */ POINTL pt,
88           /* [out][in] */ DWORD __RPC_FAR *pdwEffect);
89
90 HRESULT STDMETHODCALLTYPE
91   m_query_interface_source (IDropSource __RPC_FAR *This,
92                             /* [in] */ REFIID riid,
93                             /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
94
95 ULONG STDMETHODCALLTYPE
96   m_add_ref_source (IDropSource __RPC_FAR *This);
97
98 ULONG STDMETHODCALLTYPE
99   m_release_source (IDropSource __RPC_FAR *This);
100
101 HRESULT STDMETHODCALLTYPE
102   m_query_continue_drag (IDropSource __RPC_FAR *This,
103                          /* [in] */ BOOL fEscapePressed,
104                          /* [in] */ DWORD grfKeyState);
105 HRESULT STDMETHODCALLTYPE
106   m_give_feedback (IDropSource __RPC_FAR *This,
107                    /* [in] */ DWORD dwEffect);
108
109 #endif /* OLE2_DND */
110
111 /* Structure that holds information about a drag in progress.
112  * this is used on both source and destination sides.
113  */
114 struct _GdkDragContextPrivate {
115   GdkDragContext context;
116
117   guint   ref_count;
118
119   guint16 last_x;               /* Coordinates from last event */
120   guint16 last_y;
121   HWND  dest_xid;
122   guint drag_status;            /* Current status of drag */
123 };
124
125 GdkDragContext *current_dest_drag = NULL;
126
127 /* Drag Contexts */
128
129 static GList *contexts;
130
131 GdkDragContext *
132 gdk_drag_context_new        (void)
133 {
134   GdkDragContextPrivate *result;
135
136   result = g_new0 (GdkDragContextPrivate, 1);
137
138   result->ref_count = 1;
139
140   contexts = g_list_prepend (contexts, result);
141
142   return (GdkDragContext *)result;
143 }
144
145 #if OLE2_DND
146
147 typedef struct {
148   IDropTarget idt;
149   GdkDragContext *context;
150 } target_drag_context;
151
152 typedef struct {
153   IDropSource ids;
154   GdkDragContext *context;
155 } source_drag_context;
156
157 HRESULT STDMETHODCALLTYPE
158 m_query_interface_target (IDropTarget __RPC_FAR *This,
159                           /* [in] */ REFIID riid,
160                           /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
161 {
162   GDK_NOTE (DND, g_print ("m_query_interface_target\n"));
163
164   *ppvObject = NULL;
165
166   g_print ("riid = %.08x-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x",
167            ((gulong *) riid)[0],
168            ((gushort *) riid)[2],
169            ((gushort *) riid)[3],
170            ((guchar *) riid)[8],
171            ((guchar *) riid)[9],
172            ((guchar *) riid)[10],
173            ((guchar *) riid)[11],
174            ((guchar *) riid)[12],
175            ((guchar *) riid)[13],
176            ((guchar *) riid)[14],
177            ((guchar *) riid)[15]);
178   if (IsEqualGUID (riid, &IID_IUnknown))
179     {
180       m_add_ref_target (This);
181       *ppvObject = This;
182       g_print ("...IUnknown\n");
183       return S_OK;
184     }
185   else if (IsEqualGUID (riid, &IID_IDropTarget))
186     {
187       m_add_ref_target (This);
188       *ppvObject = This;
189       g_print ("...IDropTarget\n");
190       return S_OK;
191     }
192   else
193     {
194       g_print ("...Huh?\n");
195       return E_NOINTERFACE;
196     }
197 }
198
199 ULONG STDMETHODCALLTYPE
200 m_add_ref_target (IDropTarget __RPC_FAR *This)
201 {
202   target_drag_context *ctx = (target_drag_context *) This;
203   GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
204
205   GDK_NOTE (DND, g_print ("m_add_ref_target\n"));
206   gdk_drag_context_ref (ctx->context);
207   
208   return private->ref_count;
209 }
210
211 ULONG STDMETHODCALLTYPE
212 m_release_target (IDropTarget __RPC_FAR *This)
213 {
214   target_drag_context *ctx = (target_drag_context *) This;
215   GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
216
217   GDK_NOTE (DND, g_print ("m_release_target\n"));
218   gdk_drag_context_unref (ctx->context);
219
220   if (private->ref_count == 1)
221     {
222       gdk_drag_context_unref (ctx->context);
223       return 0;
224     }
225   else
226     return private->ref_count - 1;
227 }
228
229 HRESULT STDMETHODCALLTYPE 
230 m_drag_enter (IDropTarget __RPC_FAR *This,
231               /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
232               /* [in] */ DWORD grfKeyState,
233               /* [in] */ POINTL pt,
234               /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
235 {
236   GDK_NOTE (DND, g_print ("m_drag_enter\n"));
237   return E_UNEXPECTED;
238 }
239
240 HRESULT STDMETHODCALLTYPE
241 m_drag_over (IDropTarget __RPC_FAR *This,
242              /* [in] */ DWORD grfKeyState,
243              /* [in] */ POINTL pt,
244              /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
245 {
246   GDK_NOTE (DND, g_print ("m_drag_over\n"));
247   return E_UNEXPECTED;
248 }
249
250 HRESULT STDMETHODCALLTYPE
251 m_drag_leave (IDropTarget __RPC_FAR *This)
252 {
253   GDK_NOTE (DND, g_print ("m_drag_leave\n"));
254   return E_UNEXPECTED;
255 }
256
257 HRESULT STDMETHODCALLTYPE
258 m_drop (IDropTarget __RPC_FAR *This,
259         /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
260         /* [in] */ DWORD grfKeyState,
261         /* [in] */ POINTL pt,
262         /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
263 {
264   GDK_NOTE (DND, g_print ("m_drop\n"));
265   return E_UNEXPECTED;
266 }
267  
268 HRESULT STDMETHODCALLTYPE
269 m_query_interface_source (IDropSource __RPC_FAR *This,
270                           /* [in] */ REFIID riid,
271                           /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
272 {
273   GDK_NOTE (DND, g_print ("m_query_interface_source\n"));
274
275   *ppvObject = NULL;
276
277   g_print ("riid = %.02x%.02x%.02x%.02x-%.02x%.02x-%.02x%.02x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x",
278            ((guchar *) riid)[0],
279            ((guchar *) riid)[1],
280            ((guchar *) riid)[2],
281            ((guchar *) riid)[3],
282            ((guchar *) riid)[4],
283            ((guchar *) riid)[5],
284            ((guchar *) riid)[6],
285            ((guchar *) riid)[7],
286            ((guchar *) riid)[8],
287            ((guchar *) riid)[9],
288            ((guchar *) riid)[10],
289            ((guchar *) riid)[11],
290            ((guchar *) riid)[12],
291            ((guchar *) riid)[13],
292            ((guchar *) riid)[14],
293            ((guchar *) riid)[15]);
294   if (IsEqualGUID (riid, &IID_IUnknown))
295     {
296       m_add_ref_source (This);
297       *ppvObject = This;
298       g_print ("...IUnknown\n");
299       return S_OK;
300     }
301   else if (IsEqualGUID (riid, &IID_IDropSource))
302     {
303       m_add_ref_source (This);
304       *ppvObject = This;
305       g_print ("...IDropSource\n");
306       return S_OK;
307     }
308   else
309     {
310       g_print ("...Huh?\n");
311       return E_NOINTERFACE;
312     }
313 }
314
315 ULONG STDMETHODCALLTYPE
316 m_add_ref_source (IDropSource __RPC_FAR *This)
317 {
318   source_drag_context *ctx = (source_drag_context *) This;
319   GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
320
321   GDK_NOTE (DND, g_print ("m_add_ref_source\n"));
322   gdk_drag_context_ref (ctx->context);
323   
324   return private->ref_count;
325 }
326
327 ULONG STDMETHODCALLTYPE
328 m_release_source (IDropSource __RPC_FAR *This)
329 {
330   source_drag_context *ctx = (source_drag_context *) This;
331   GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
332
333   GDK_NOTE (DND, g_print ("m_release_source\n"));
334   gdk_drag_context_unref (ctx->context);
335
336   if (private->ref_count == 1)
337     {
338       gdk_drag_context_unref (ctx->context);
339       return 0;
340     }
341   else
342     return private->ref_count - 1;
343 }
344
345 HRESULT STDMETHODCALLTYPE
346 m_query_continue_drag (IDropSource __RPC_FAR *This,
347                        /* [in] */ BOOL fEscapePressed,
348                        /* [in] */ DWORD grfKeyState)
349 {
350   GDK_NOTE (DND, g_print ("m_query_continue_drag\n"));
351   return E_UNEXPECTED;
352 }
353
354 HRESULT STDMETHODCALLTYPE
355 m_give_feedback (IDropSource __RPC_FAR *This,
356                  /* [in] */ DWORD dwEffect)
357 {
358   GDK_NOTE (DND, g_print ("m_give_feedback\n"));
359   return E_UNEXPECTED;
360 }
361
362 static IDropTargetVtbl idt_vtbl = {
363   m_query_interface_target,
364   m_add_ref_target,
365   m_release_target,
366   m_drag_enter,
367   m_drag_over,
368   m_drag_leave,
369   m_drop
370 };
371
372 static IDropSourceVtbl ids_vtbl = {
373   m_query_interface_source,
374   m_add_ref_source,
375   m_release_source,
376   m_query_continue_drag,
377   m_give_feedback
378 };
379
380 target_drag_context *
381 target_context_new (void)
382 {
383   target_drag_context *result;
384
385   result = g_new0 (target_drag_context, 1);
386
387   result->idt.lpVtbl = &idt_vtbl;
388
389   result->context = gdk_drag_context_new ();
390
391   return result;
392 }
393
394 source_drag_context *
395 source_context_new (void)
396 {
397   source_drag_context *result;
398
399   result = g_new0 (source_drag_context, 1);
400
401   result->ids.lpVtbl = &ids_vtbl;
402
403   result->context = gdk_drag_context_new ();
404
405   return result;
406 }
407
408 #endif /* OLE2_DND */
409
410 void            
411 gdk_drag_context_ref (GdkDragContext *context)
412 {
413   g_return_if_fail (context != NULL);
414
415   ((GdkDragContextPrivate *)context)->ref_count++;
416 }
417
418 void            
419 gdk_drag_context_unref (GdkDragContext *context)
420 {
421   GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
422   
423   g_return_if_fail (context != NULL);
424
425   private->ref_count--;
426
427   GDK_NOTE (DND, g_print ("gdk_drag_context_unref: %d%s\n",
428                           private->ref_count,
429                           (private->ref_count == 0 ? " freeing" : "")));
430
431   if (private->ref_count == 0)
432     {
433       g_dataset_destroy (private);
434       
435       g_list_free (context->targets);
436
437       if (context->source_window)
438         gdk_window_unref (context->source_window);
439
440       if (context->dest_window)
441         gdk_window_unref (context->dest_window);
442
443       contexts = g_list_remove (contexts, private);
444       g_free (private);
445     }
446 }
447
448 #if 0
449
450 static GdkDragContext *
451 gdk_drag_context_find (gboolean is_source,
452                        HWND     source_xid,
453                        HWND     dest_xid)
454 {
455   GList *tmp_list = contexts;
456   GdkDragContext *context;
457
458   while (tmp_list)
459     {
460       context = (GdkDragContext *)tmp_list->data;
461
462       if ((!context->is_source == !is_source) &&
463           ((source_xid == None) || (context->source_window &&
464             (GDK_WINDOW_XWINDOW (context->source_window) == source_xid))) &&
465           ((dest_xid == None) || (context->dest_window &&
466             (GDK_WINDOW_XWINDOW (context->dest_window) == dest_xid))))
467         return context;
468       
469       tmp_list = tmp_list->next;
470     }
471
472   return NULL;
473 }
474
475 #endif
476
477 /* From MS Knowledge Base article Q130698 */
478
479 /* resolve_link() fills the filename and path buffer
480  * with relevant information
481  * hWnd         - calling app's window handle.
482  *
483  * lpszLinkName - name of the link file passed into the function.
484  *
485  * lpszPath     - the buffer that will receive the file pathname.
486  */
487
488 static HRESULT 
489 resolve_link(HWND hWnd,
490              LPCTSTR lpszLinkName,
491              LPSTR lpszPath,
492              LPSTR lpszDescription)
493 {
494   HRESULT hres;
495   IShellLink *psl;
496   WIN32_FIND_DATA wfd;
497
498   /* Assume Failure to start with: */
499   *lpszPath = 0;
500   if (lpszDescription)
501     *lpszDescription = 0;
502
503   /* Call CoCreateInstance to obtain the IShellLink interface
504    * pointer. This call fails if CoInitialize is not called, so it is
505    * assumed that CoInitialize has been called.
506    */
507
508   hres = CoCreateInstance (&CLSID_ShellLink,
509                            NULL,
510                            CLSCTX_INPROC_SERVER,
511                            &IID_IShellLink,
512                            (LPVOID *)&psl);
513   if (SUCCEEDED (hres))
514    {
515      IPersistFile *ppf;
516      
517      /* The IShellLink interface supports the IPersistFile
518       * interface. Get an interface pointer to it.
519       */
520      hres = psl->lpVtbl->QueryInterface (psl,
521                                          &IID_IPersistFile,
522                                          (LPVOID *) &ppf);
523      if (SUCCEEDED (hres))
524        {
525          WORD wsz[MAX_PATH];
526
527          /* Convert the given link name string to wide character string. */
528          MultiByteToWideChar (CP_ACP, 0,
529                               lpszLinkName,
530                               -1, wsz, MAX_PATH);
531          /* Load the file. */
532          hres = ppf->lpVtbl->Load (ppf, wsz, STGM_READ);
533          if (SUCCEEDED (hres))
534            {
535              /* Resolve the link by calling the Resolve()
536               * interface function.
537               */
538              hres = psl->lpVtbl->Resolve(psl,  hWnd,
539                                          SLR_ANY_MATCH |
540                                          SLR_NO_UI);
541              if (SUCCEEDED (hres))
542                {
543                  hres = psl->lpVtbl->GetPath (psl, lpszPath,
544                                               MAX_PATH,
545                                               (WIN32_FIND_DATA*)&wfd,
546                                               0);
547
548                  if (SUCCEEDED (hres) && lpszDescription != NULL)
549                    {
550                      hres = psl->lpVtbl->GetDescription (psl,
551                                                          lpszDescription,
552                                                          MAX_PATH );
553
554                      if (!SUCCEEDED (hres))
555                        return FALSE;
556                    }
557                }
558            }
559          ppf->lpVtbl->Release (ppf);
560        }
561      psl->lpVtbl->Release (psl);
562    }
563   return SUCCEEDED (hres);
564 }
565
566 static GdkFilterReturn
567 gdk_dropfiles_filter (GdkXEvent *xev,
568                       GdkEvent  *event,
569                       gpointer   data)
570 {
571   GdkDragContext *context;
572   GdkDragContextPrivate *private;
573   static GdkAtom text_uri_list_atom = GDK_NONE;
574   GString *result;
575   MSG *msg = (MSG *) xev;
576   HANDLE hdrop;
577   POINT pt;
578   gint nfiles, i, k;
579   guchar fileName[MAX_PATH], linkedFile[MAX_PATH];
580   
581   if (text_uri_list_atom == GDK_NONE)
582     text_uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE);
583
584   if (msg->message == WM_DROPFILES)
585     {
586       GDK_NOTE (DND, g_print ("WM_DROPFILES: %#x\n", msg->hwnd));
587
588       context = gdk_drag_context_new ();
589       private = (GdkDragContextPrivate *) context;
590       context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
591       context->is_source = FALSE;
592       context->source_window = (GdkWindow *) &gdk_root_parent;
593       context->dest_window = event->any.window;
594       gdk_window_ref (context->dest_window);
595       /* WM_DROPFILES drops are always file names */
596       context->targets =
597         g_list_append (NULL, GUINT_TO_POINTER (text_uri_list_atom));
598       current_dest_drag = context;
599
600       event->dnd.type = GDK_DROP_START;
601       event->dnd.context = current_dest_drag;
602       gdk_drag_context_ref (current_dest_drag);
603       
604       hdrop = (HANDLE) msg->wParam;
605       DragQueryPoint (hdrop, &pt);
606       ClientToScreen (msg->hwnd, &pt);
607
608       event->dnd.x_root = pt.x;
609       event->dnd.y_root = pt.y;
610       event->dnd.time = msg->time;
611
612       nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
613
614       result = g_string_new (NULL);
615       for (i = 0; i < nfiles; i++)
616         {
617           g_string_append (result, "file:");
618           DragQueryFile (hdrop, i, fileName, MAX_PATH);
619
620           /* Resolve shortcuts */
621           if (resolve_link (msg->hwnd, fileName, linkedFile, NULL))
622             {
623               g_string_append (result, linkedFile);
624               GDK_NOTE (DND, g_print ("...%s link to %s\n",
625                                       fileName, linkedFile));
626             }
627           else
628             {
629               g_string_append (result, fileName);
630               GDK_NOTE (DND, g_print ("...%s\n", fileName));
631             }
632           g_string_append (result, "\015\012");
633         }
634       gdk_sel_prop_store ((GdkWindow *) &gdk_root_parent,
635                           text_uri_list_atom, 8, result->str, result->len + 1);
636
637       DragFinish (hdrop);
638       
639       return GDK_FILTER_TRANSLATE;
640     }
641   else
642     return GDK_FILTER_CONTINUE;
643 }
644                      
645
646 /*************************************************************
647  ************************** Public API ***********************
648  *************************************************************/
649
650 void
651 gdk_dnd_init (void)
652 {
653   HRESULT hres;
654
655   hres = OleInitialize (NULL);
656
657   if (! SUCCEEDED (hres))
658     g_error ("OleInitialize failed");
659 }                     
660
661 void
662 gdk_dnd_exit (void)
663 {
664   OleUninitialize ();
665 }
666
667 /* Source side */
668
669 static void
670 gdk_drag_do_leave (GdkDragContext *context, guint32 time)
671 {
672   if (context->dest_window)
673     {
674       GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n"));
675       gdk_window_unref (context->dest_window);
676       context->dest_window = NULL;
677     }
678 }
679
680 GdkDragContext * 
681 gdk_drag_begin (GdkWindow     *window,
682                 GList         *targets)
683 {
684   GList *tmp_list;
685   GdkDragContext *new_context;
686   
687   g_return_val_if_fail (window != NULL, NULL);
688
689   GDK_NOTE (DND, g_print ("gdk_drag_begin\n"));
690
691   new_context = gdk_drag_context_new ();
692   new_context->is_source = TRUE;
693   new_context->source_window = window;
694   gdk_window_ref (window);
695
696   tmp_list = g_list_last (targets);
697   new_context->targets = NULL;
698   while (tmp_list)
699     {
700       new_context->targets = g_list_prepend (new_context->targets,
701                                              tmp_list->data);
702       tmp_list = tmp_list->prev;
703     }
704
705   new_context->actions = 0;
706
707   return new_context;
708 }
709
710 guint32
711 gdk_drag_get_protocol (guint32          xid,
712                        GdkDragProtocol *protocol)
713 {
714   /* This isn't used */
715   return 0;
716 }
717
718 void
719 gdk_drag_find_window (GdkDragContext  *context,
720                       GdkWindow       *drag_window,
721                       gint             x_root,
722                       gint             y_root,
723                       GdkWindow      **dest_window,
724                       GdkDragProtocol *protocol)
725 {
726   GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
727   GdkWindowPrivate *drag_window_private = (GdkWindowPrivate *) drag_window;
728   HWND recipient;
729   POINT pt;
730
731   GDK_NOTE (DND, g_print ("gdk_drag_find_window: %#x +%d+%d\n",
732                           (drag_window ? drag_window_private->xwindow : 0),
733                           x_root, y_root));
734
735   pt.x = x_root;
736   pt.y = y_root;
737   recipient = WindowFromPoint (pt);
738   if (recipient == NULL)
739     *dest_window = NULL;
740   else
741     {
742       *dest_window = gdk_window_lookup (recipient);
743       if (*dest_window)
744         gdk_window_ref (*dest_window);
745       *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
746     }
747 }
748
749 gboolean        
750 gdk_drag_motion (GdkDragContext *context,
751                  GdkWindow      *dest_window,
752                  GdkDragProtocol protocol,
753                  gint            x_root, 
754                  gint            y_root,
755                  GdkDragAction   suggested_action,
756                  GdkDragAction   possible_actions,
757                  guint32         time)
758 {
759   return FALSE;
760 }
761
762 void
763 gdk_drag_drop (GdkDragContext *context,
764                guint32         time)
765 {
766   g_return_if_fail (context != NULL);
767
768   g_warning ("gdk_drag_drop: not implemented\n");
769 }
770
771 void
772 gdk_drag_abort (GdkDragContext *context,
773                 guint32         time)
774 {
775   g_return_if_fail (context != NULL);
776
777   gdk_drag_do_leave (context, time);
778 }
779
780 /* Destination side */
781
782 void             
783 gdk_drag_status (GdkDragContext   *context,
784                  GdkDragAction     action,
785                  guint32           time)
786 {
787   GDK_NOTE (DND, g_print ("gdk_drag_status\n"));
788 }
789
790 void 
791 gdk_drop_reply (GdkDragContext   *context,
792                 gboolean          ok,
793                 guint32           time)
794 {
795 }
796
797 void             
798 gdk_drop_finish (GdkDragContext   *context,
799                  gboolean          success,
800                  guint32           time)
801 {
802 }
803
804
805 void            
806 gdk_window_register_dnd (GdkWindow      *window)
807 {
808   GdkWindowPrivate *private = (GdkWindowPrivate *) window;
809 #if OLE2_DND
810   target_drag_context *context;
811   HRESULT hres;
812 #endif
813
814   g_return_if_fail (window != NULL);
815
816   GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %#x\n", private->xwindow));
817
818   /* We always claim to accept dropped files, but in fact we might not,
819    * of course. This function is called in such a way that it cannot know
820    * whether the window (widget) in question actually accepts files
821    * (in gtk, data of type text/uri-list) or not.
822    */
823   gdk_window_add_filter (window, gdk_dropfiles_filter, NULL);
824   DragAcceptFiles (private->xwindow, TRUE);
825
826 #if OLE2_DND
827   /* Register for OLE2 d&d */
828   context = target_context_new ();
829   hres = CoLockObjectExternal ((IUnknown *) &context->idt, TRUE, FALSE);
830   if (!SUCCEEDED (hres))
831     g_warning ("gdk_window_register_dnd: CoLockObjectExternal failed");
832   else
833     {
834       hres = RegisterDragDrop (private->xwindow, &context->idt);
835       if (hres == DRAGDROP_E_ALREADYREGISTERED)
836         {
837           g_print ("DRAGDROP_E_ALREADYREGISTERED\n");
838           CoLockObjectExternal ((IUnknown *) &context->idt, FALSE, FALSE);
839         }
840       else if (!SUCCEEDED (hres))
841         g_warning ("gdk_window_register_dnd: RegisterDragDrop failed");
842     }
843 #endif
844 }
845
846 /*************************************************************
847  * gdk_drag_get_selection:
848  *     Returns the selection atom for the current source window
849  *   arguments:
850  *     
851  *   results:
852  *************************************************************/
853
854 GdkAtom       
855 gdk_drag_get_selection (GdkDragContext *context)
856 {
857   if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES)
858     return gdk_win32_dropfiles_atom;
859   else if (context->protocol == GDK_DRAG_PROTO_OLE2)
860     return gdk_ole2_dnd_atom;
861   else
862     return GDK_NONE;
863 }