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