]> Pileus Git - ~andy/gtk/blobdiff - gdk/win32/gdkdnd-win32.c
Merge from stable:
[~andy/gtk] / gdk / win32 / gdkdnd-win32.c
index da6da4bb5e0339164c867b73593749af56c186cc..08cdcdef3e0a9d8ab29201c4d0fe64bb32b5395c 100644 (file)
@@ -1,32 +1,30 @@
 /* GDK - The GIMP Drawing Kit
  * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
- * Copyright (C) 1998-1999 Tor Lillqvist
+ * Copyright (C) 1998-2002 Tor Lillqvist
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
 
 /*
- * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GTK+ Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include "config.h"
-
 #include <string.h>
 
 /* #define OLE2_DND */
@@ -35,8 +33,8 @@
 
 #include "gdkdnd.h"
 #include "gdkproperty.h"
-#include "gdkprivate.h"
-#include "gdkx.h"
+#include "gdkinternals.h"
+#include "gdkprivate-win32.h"
 
 #ifdef OLE2_DND
 #include <ole2.h>
 #include <objbase.h>
 #endif
 
-#ifdef _MSC_VER                        /* These aren't in mingw32 */
 #include <shlobj.h>
 #include <shlguid.h>
-#endif
-
-#ifndef _MSC_VER
-static IID IID_IUnknown = {
-  0x00000000, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
-static IID IID_IDropSource = {
-  0x00000121, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
-static IID IID_IDropTarget = {
-  0x00000122, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
-#endif
 
 #include <gdk/gdk.h>
 
-typedef struct _GdkDragContextPrivate GdkDragContextPrivate;
+typedef struct _GdkDragContextPrivateWin32 GdkDragContextPrivateWin32;
 
 typedef enum {
   GDK_DRAG_STATUS_DRAG,
@@ -91,108 +78,158 @@ typedef enum {
           ((guchar *)  guid)[15]);
 
 
+static FORMATETC *formats;
+static int nformats;
+
 #endif /* OLE2_DND */
 
 /* Structure that holds information about a drag in progress.
  * this is used on both source and destination sides.
  */
-struct _GdkDragContextPrivate {
-  GdkDragContext context;
-
-  guint   ref_count;
+struct _GdkDragContextPrivateWin32 {
+  gint    ref_count;
 
   guint16 last_x;              /* Coordinates from last event */
   guint16 last_y;
-  HWND  dest_xid;
-  guint drag_status;           /* Current status of drag */
+  HWND    dest_xid;
+  guint   drag_status;         /* Current status of drag */
 };
 
+#define GDK_DRAG_CONTEXT_PRIVATE_DATA(context) ((GdkDragContextPrivateWin32 *) GDK_DRAG_CONTEXT (context)->windowing_data)
+
 GdkDragContext *current_dest_drag = NULL;
 
-/* Drag Contexts */
+static void gdk_drag_context_init       (GdkDragContext      *dragcontext);
+static void gdk_drag_context_class_init (GdkDragContextClass *klass);
+static void gdk_drag_context_finalize   (GObject              *object);
 
+static gpointer parent_class = NULL;
 static GList *contexts;
 
-GdkDragContext *
-gdk_drag_context_new        (void)
+GType
+gdk_drag_context_get_type (void)
 {
-  GdkDragContextPrivate *result;
+  static GType object_type = 0;
 
-  result = g_new0 (GdkDragContextPrivate, 1);
+  if (!object_type)
+    {
+      static const GTypeInfo object_info =
+      {
+        sizeof (GdkDragContextClass),
+        (GBaseInitFunc) NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc) gdk_drag_context_class_init,
+        NULL,           /* class_finalize */
+        NULL,           /* class_data */
+        sizeof (GdkDragContext),
+        0,              /* n_preallocs */
+        (GInstanceInitFunc) gdk_drag_context_init,
+      };
+      
+      object_type = g_type_register_static (G_TYPE_OBJECT,
+                                            "GdkDragContext",
+                                            &object_info, 0);
+    }
+  
+  return object_type;
+}
 
-  result->ref_count = 1;
+static void
+gdk_drag_context_init (GdkDragContext *dragcontext)
+{
+  GdkDragContextPrivateWin32 *private = g_new0 (GdkDragContextPrivateWin32, 1);
 
-  contexts = g_list_prepend (contexts, result);
+  dragcontext->windowing_data = private;
+  private->ref_count = 1;
 
-  return (GdkDragContext *)result;
+  contexts = g_list_prepend (contexts, dragcontext);
 }
 
-void
-gdk_drag_context_ref (GdkDragContext *context)
+static void
+gdk_drag_context_class_init (GdkDragContextClass *klass)
 {
-  g_return_if_fail (context != NULL);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
 
-  ((GdkDragContextPrivate *)context)->ref_count++;
+  object_class->finalize = gdk_drag_context_finalize;
 }
 
-void
-gdk_drag_context_unref (GdkDragContext *context)
+static void
+gdk_drag_context_finalize (GObject *object)
 {
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+  GdkDragContext *context = GDK_DRAG_CONTEXT (object);
+  GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
   
-  g_return_if_fail (context != NULL);
+  g_list_free (context->targets);
 
-  private->ref_count--;
+  if (context->source_window)
+    {
+      gdk_window_unref (context->source_window);
+    }
+  
+  if (context->dest_window)
+    gdk_window_unref (context->dest_window);
+  
+  contexts = g_list_remove (contexts, context);
 
-  GDK_NOTE (DND, g_print ("gdk_drag_context_unref: %d%s\n",
-                         private->ref_count,
-                         (private->ref_count == 0 ? " freeing" : "")));
+  g_free (private);
+  
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
 
-  if (private->ref_count == 0)
-    {
-      g_dataset_destroy (private);
-      
-      g_list_free (context->targets);
+/* Drag Contexts */
 
-      if (context->source_window)
-       gdk_window_unref (context->source_window);
+GdkDragContext *
+gdk_drag_context_new (void)
+{
+  return g_object_new (gdk_drag_context_get_type (), NULL);
+}
+
+void
+gdk_drag_context_ref (GdkDragContext *context)
+{
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
 
-      if (context->dest_window)
-       gdk_window_unref (context->dest_window);
+  GDK_NOTE (DND, g_print ("gdk_drag_context_ref: %p %d\n", context, G_OBJECT(context)->ref_count));
 
-      contexts = g_list_remove (contexts, private);
-      g_free (private);
-    }
+  g_object_ref (context);
 }
 
-#if 0
+void
+gdk_drag_context_unref (GdkDragContext *context)
+{
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+
+  GDK_NOTE (DND, g_print ("gdk_drag_context_unref: %p %d\n", context, G_OBJECT(context)->ref_count));
+  g_object_unref (context);
+}
 
 static GdkDragContext *
-gdk_drag_context_find (gboolean is_source,
-                      HWND     source_xid,
-                      HWND     dest_xid)
+gdk_drag_context_find (gboolean   is_source,
+                      GdkWindow *source,
+                      GdkWindow *dest)
 {
   GList *tmp_list = contexts;
   GdkDragContext *context;
+  GdkDragContextPrivateWin32 *private;
 
   while (tmp_list)
     {
       context = (GdkDragContext *)tmp_list->data;
+      private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
 
       if ((!context->is_source == !is_source) &&
-         ((source_xid == None) || (context->source_window &&
-           (GDK_WINDOW_XWINDOW (context->source_window) == source_xid))) &&
-         ((dest_xid == None) || (context->dest_window &&
-           (GDK_WINDOW_XWINDOW (context->dest_window) == dest_xid))))
+         ((source == NULL) || (context->source_window && (context->source_window == source))) &&
+         ((dest == NULL) || (context->dest_window && (context->dest_window == dest))))
        return context;
       
       tmp_list = tmp_list->next;
     }
-
+  
   return NULL;
 }
 
-#endif
 
 typedef struct {
 #ifdef OLE2_DND
@@ -210,24 +247,38 @@ typedef struct {
 
 #ifdef OLE2_DND
 
+typedef struct {
+  IDataObject ido;
+  int ref_count;
+} data_object;
+
+typedef struct {
+  IEnumFORMATETC ief;
+  int ref_count;
+  int ix;
+} enum_formats;
+
+static enum_formats *enum_formats_new (void);
+
 static ULONG STDMETHODCALLTYPE
-m_add_ref_target (IDropTarget __RPC_FAR *This)
+idroptarget_addref (LPDROPTARGET This)
 {
   target_drag_context *ctx = (target_drag_context *) This;
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+  GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
+  int ref_count = ++private->ref_count;
 
-  GDK_NOTE (DND, g_print ("m_add_ref_target\n"));
   gdk_drag_context_ref (ctx->context);
+  GDK_NOTE (DND, g_print ("idroptarget_addref %#x %d\n", This, ref_count));
   
-  return private->ref_count;
+  return ref_count;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_query_interface_target (IDropTarget __RPC_FAR *This,
-                         REFIID riid,
-                         void __RPC_FAR *__RPC_FAR *ppvObject)
+idroptarget_queryinterface (LPDROPTARGET This,
+                           REFIID       riid,
+                           LPVOID      *ppvObject)
 {
-  GDK_NOTE (DND, g_print ("m_query_interface_target\n"));
+  GDK_NOTE (DND, g_print ("idroptarget_queryinterface %#x\n", This));
 
   *ppvObject = NULL;
 
@@ -236,14 +287,14 @@ m_query_interface_target (IDropTarget __RPC_FAR *This,
   if (IsEqualGUID (riid, &IID_IUnknown))
     {
       g_print ("...IUnknown\n");
-      m_add_ref_target (This);
+      idroptarget_addref (This);
       *ppvObject = This;
       return S_OK;
     }
   else if (IsEqualGUID (riid, &IID_IDropTarget))
     {
       g_print ("...IDropTarget\n");
-      m_add_ref_target (This);
+      idroptarget_addref (This);
       *ppvObject = This;
       return S_OK;
     }
@@ -255,80 +306,83 @@ m_query_interface_target (IDropTarget __RPC_FAR *This,
 }
 
 static ULONG STDMETHODCALLTYPE
-m_release_target (IDropTarget __RPC_FAR *This)
+idroptarget_release (LPDROPTARGET This)
 {
   target_drag_context *ctx = (target_drag_context *) This;
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+  GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
+  int ref_count = --private->ref_count;
 
-  GDK_NOTE (DND, g_print ("m_release_target\n"));
   gdk_drag_context_unref (ctx->context);
+  GDK_NOTE (DND, g_print ("idroptarget_release %#x %d\n", This, ref_count));
 
-  if (private->ref_count == 1)
-    {
-      gdk_drag_context_unref (ctx->context);
-      return 0;
-    }
-  else
-    return private->ref_count - 1;
+  if (ref_count == 0)
+    g_free (This);
+
+  return ref_count;
 }
 
 static HRESULT STDMETHODCALLTYPE 
-m_drag_enter (IDropTarget __RPC_FAR *This,
-             IDataObject __RPC_FAR *pDataObj,
-             DWORD grfKeyState,
-             POINTL pt,
-             DWORD __RPC_FAR *pdwEffect)
+idroptarget_dragenter (LPDROPTARGET This,
+                      LPDATAOBJECT pDataObj,
+                      DWORD        grfKeyState,
+                      POINTL       pt,
+                      LPDWORD      pdwEffect)
 {
-  GDK_NOTE (DND, g_print ("m_drag_enter\n"));
+  GDK_NOTE (DND, g_print ("idroptarget_dragenter %#x\n", This));
+
   return E_UNEXPECTED;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_drag_over (IDropTarget __RPC_FAR *This,
-            DWORD grfKeyState,
-            POINTL pt,
-            DWORD __RPC_FAR *pdwEffect)
+idroptarget_dragover (LPDROPTARGET This,
+                     DWORD        grfKeyState,
+                     POINTL       pt,
+                     LPDWORD      pdwEffect)
 {
-  GDK_NOTE (DND, g_print ("m_drag_over\n"));
+  GDK_NOTE (DND, g_print ("idroptarget_dragover %#x\n", This));
+
   return E_UNEXPECTED;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_drag_leave (IDropTarget __RPC_FAR *This)
+idroptarget_dragleave (LPDROPTARGET This)
 {
-  GDK_NOTE (DND, g_print ("m_drag_leave\n"));
+  GDK_NOTE (DND, g_print ("idroptarget_dragleave %#x\n", This));
+
   return E_UNEXPECTED;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_drop (IDropTarget __RPC_FAR *This,
-       IDataObject __RPC_FAR *pDataObj,
-       DWORD grfKeyState,
-       POINTL pt,
-       DWORD __RPC_FAR *pdwEffect)
+idroptarget_drop (LPDROPTARGET This,
+                 LPDATAOBJECT pDataObj,
+                 DWORD        grfKeyState,
+                 POINTL       pt,
+                 LPDWORD      pdwEffect)
 {
-  GDK_NOTE (DND, g_print ("m_drop\n"));
+  GDK_NOTE (DND, g_print ("idroptarget_drop %#x\n", This));
+
   return E_UNEXPECTED;
 }
 
 static ULONG STDMETHODCALLTYPE
-m_add_ref_source (IDropSource __RPC_FAR *This)
+idropsource_addref (LPDROPSOURCE This)
 {
   source_drag_context *ctx = (source_drag_context *) This;
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+  GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
 
-  GDK_NOTE (DND, g_print ("m_add_ref_source\n"));
   gdk_drag_context_ref (ctx->context);
+  GDK_NOTE (DND, g_print ("idropsource_addref %#x %d\n",
+                         This, private->ref_count));
   
   return private->ref_count;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_query_interface_source (IDropSource __RPC_FAR *This,
-                         REFIID riid,
-                         void __RPC_FAR *__RPC_FAR *ppvObject)
+idropsource_queryinterface (LPDROPSOURCE This,
+                           REFIID       riid,
+                           LPVOID      *ppvObject)
 {
-  GDK_NOTE (DND, g_print ("m_query_interface_source\n"));
+  GDK_NOTE (DND, g_print ("idropsource_queryinterface %#x\n", This));
 
   *ppvObject = NULL;
 
@@ -336,14 +390,14 @@ m_query_interface_source (IDropSource __RPC_FAR *This,
   if (IsEqualGUID (riid, &IID_IUnknown))
     {
       g_print ("...IUnknown\n");
-      m_add_ref_source (This);
+      idropsource_addref (This);
       *ppvObject = This;
       return S_OK;
     }
   else if (IsEqualGUID (riid, &IID_IDropSource))
     {
       g_print ("...IDropSource\n");
-      m_add_ref_source (This);
+      idropsource_addref (This);
       *ppvObject = This;
       return S_OK;
     }
@@ -355,163 +409,368 @@ m_query_interface_source (IDropSource __RPC_FAR *This,
 }
 
 static ULONG STDMETHODCALLTYPE
-m_release_source (IDropSource __RPC_FAR *This)
+idropsource_release (LPDROPSOURCE This)
 {
   source_drag_context *ctx = (source_drag_context *) This;
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+  GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context);
+  int ref_count = --private->ref_count;
 
-  GDK_NOTE (DND, g_print ("m_release_source\n"));
   gdk_drag_context_unref (ctx->context);
+  GDK_NOTE (DND, g_print ("idropsource_release %#x %d\n", This, ref_count));
 
-  if (private->ref_count == 1)
-    {
-      gdk_drag_context_unref (ctx->context);
-      return 0;
-    }
-  else
-    return private->ref_count - 1;
+  if (ref_count == 0)
+    g_free (This);
+
+  return ref_count;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_query_continue_drag (IDropSource __RPC_FAR *This,
-                      BOOL fEscapePressed,
-                      DWORD grfKeyState)
+idropsource_querycontinuedrag (LPDROPSOURCE This,
+                              BOOL         fEscapePressed,
+                              DWORD        grfKeyState)
 {
-  GDK_NOTE (DND, g_print ("m_query_continue_drag\n"));
+  GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag %#x\n", This));
+
   return E_UNEXPECTED;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_give_feedback (IDropSource __RPC_FAR *This,
-                DWORD dwEffect)
+idropsource_givefeedback (LPDROPSOURCE This,
+                         DWORD        dwEffect)
 {
-  GDK_NOTE (DND, g_print ("m_give_feedback\n"));
+  GDK_NOTE (DND, g_print ("idropsource_givefeedback %#x\n", This));
+
   return E_UNEXPECTED;
 }
 
-static HRESULT STDMETHODCALLTYPE
-m_query_interface_object (IDataObject __RPC_FAR *This,
-                         REFIID riid,
-                         void __RPC_FAR *__RPC_FAR *ppvObject)
+static ULONG STDMETHODCALLTYPE
+idataobject_addref (LPDATAOBJECT This)
 {
-  return E_UNEXPECTED;
+  data_object *dobj = (data_object *) This;
+  int ref_count = ++dobj->ref_count;
+
+  GDK_NOTE (DND, g_print ("idataobject_addref %#x %d\n", This, ref_count));
+
+  return ref_count;
 }
 
-static ULONG STDMETHODCALLTYPE
-m_add_ref_object (IDataObject __RPC_FAR *This)
+static HRESULT STDMETHODCALLTYPE
+idataobject_queryinterface (LPDATAOBJECT This,
+                           REFIID       riid,
+                           LPVOID      *ppvObject)
 {
-  return E_UNEXPECTED;
+  GDK_NOTE (DND, g_print ("idataobject_queryinterface %#x\n", This));
+
+  *ppvObject = NULL;
+
+  PRINT_GUID (riid);
+  if (IsEqualGUID (riid, &IID_IUnknown))
+    {
+      g_print ("...IUnknown\n");
+      idataobject_addref (This);
+      *ppvObject = This;
+      return S_OK;
+    }
+  else if (IsEqualGUID (riid, &IID_IDataObject))
+    {
+      g_print ("...IDataObject\n");
+      idataobject_addref (This);
+      *ppvObject = This;
+      return S_OK;
+    }
+  else
+    {
+      g_print ("...Huh?\n");
+      return E_NOINTERFACE;
+    }
 }
 
 static ULONG STDMETHODCALLTYPE
-m_release_object (IDataObject __RPC_FAR *This)
+idataobject_release (LPDATAOBJECT This)
 {
-  return E_UNEXPECTED;
+  data_object *dobj = (data_object *) This;
+  int ref_count = --dobj->ref_count;
+
+  GDK_NOTE (DND, g_print ("idataobject_release %#x %d\n", This, ref_count));
+
+  if (ref_count == 0)
+    g_free (This);
+
+  return ref_count;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_get_data (IDataObject __RPC_FAR *This,
-           FORMATETC *pFormatEtc,
-           STGMEDIUM *pMedium)
+idataobject_getdata (LPDATAOBJECT This,
+                    LPFORMATETC  pFormatEtc,
+                    LPSTGMEDIUM  pMedium)
 {
+  GDK_NOTE (DND, g_print ("idataobject_getdata %#x\n", This));
+
   return E_UNEXPECTED;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_get_data_here (IDataObject __RPC_FAR *This,
-                FORMATETC *pFormatEtc,
-                STGMEDIUM *pMedium)
+idataobject_getdatahere (LPDATAOBJECT This,
+                        LPFORMATETC  pFormatEtc,
+                        LPSTGMEDIUM  pMedium)
 {
+  GDK_NOTE (DND, g_print ("idataobject_getdatahere %#x\n", This));
+
   return E_UNEXPECTED;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_query_get_data (IDataObject __RPC_FAR *This,
-                 FORMATETC *pFormatEtc)
+idataobject_querygetdata (LPDATAOBJECT This,
+                         LPFORMATETC  pFormatEtc)
 {
-  return E_UNEXPECTED;
+  int i;
+
+  GDK_NOTE (DND, g_print ("idataobject_querygetdata %#x %#x", This, pFormatEtc->cfFormat));
+
+  for (i = 0; i < nformats; i++)
+    if (pFormatEtc->cfFormat == formats[i].cfFormat)
+      {
+       GDK_NOTE (DND, g_print (" S_OK\n"));
+       return S_OK;
+      }
+
+  GDK_NOTE (DND, g_print (" DV_E_FORMATETC\n"));
+  return DV_E_FORMATETC;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_get_canonical_format_etc (IDataObject __RPC_FAR *This,
-                           FORMATETC *pFormatEtcIn,
-                           FORMATETC *pFormatEtcOut)
+idataobject_getcanonicalformatetc (LPDATAOBJECT This,
+                                  LPFORMATETC  pFormatEtcIn,
+                                  LPFORMATETC  pFormatEtcOut)
 {
-  return E_UNEXPECTED;
+  GDK_NOTE (DND, g_print ("idataobject_getcanonicalformatetc %#x\n", This));
+
+  return E_FAIL;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_set_data (IDataObject __RPC_FAR *This,
-           FORMATETC *pFormatEtc,
-           STGMEDIUM *pMedium,
-           BOOL fRelease)
+idataobject_setdata (LPDATAOBJECT This,
+                    LPFORMATETC  pFormatEtc,
+                    LPSTGMEDIUM  pMedium,
+                    BOOL         fRelease)
 {
+  GDK_NOTE (DND, g_print ("idataobject_setdata %#x\n", This));
+
   return E_UNEXPECTED;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_enum_format_etc (IDataObject __RPC_FAR *This,
-                  DWORD dwDirection,
-                  IEnumFORMATETC **ppEnumFormatEtc)
+idataobject_enumformatetc (LPDATAOBJECT     This,
+                          DWORD            dwDirection,
+                          LPENUMFORMATETC *ppEnumFormatEtc)
 {
-  return E_UNEXPECTED;
+  GDK_NOTE (DND, g_print ("idataobject_enumformatetc %#x\n", This));
+
+  if (dwDirection != DATADIR_GET)
+    return E_NOTIMPL;
+
+  *ppEnumFormatEtc = &enum_formats_new ()->ief;
+  return S_OK;
 }
 
 static HRESULT STDMETHODCALLTYPE
- m_d_advise (IDataObject __RPC_FAR *This,
-            FORMATETC *pFormatetc,
-            DWORD advf,
-            IAdviseSink *pAdvSink,
-            DWORD *pdwConnection)
+idataobject_dadvise (LPDATAOBJECT This,
+                    LPFORMATETC  pFormatetc,
+                    DWORD        advf,
+                    LPADVISESINK pAdvSink,
+                    DWORD       *pdwConnection)
 {
-  return E_UNEXPECTED;
+  GDK_NOTE (DND, g_print ("idataobject_dadvise %#x\n", This));
+
+  return E_FAIL;
 }
 
 static HRESULT STDMETHODCALLTYPE
- m_d_unadvise (IDataObject __RPC_FAR *This,
-              DWORD dwConnection)
+idataobject_dunadvise (LPDATAOBJECT This,
+                      DWORD         dwConnection)
 {
-  return E_UNEXPECTED;
+  GDK_NOTE (DND, g_print ("idataobject_dunadvise %#x\n", This));
+
+  return E_FAIL;
 }
 
 static HRESULT STDMETHODCALLTYPE
-m_enum_d_advise (IDataObject __RPC_FAR *This,
-                IEnumSTATDATA **ppenumAdvise)
+idataobject_enumdadvise (LPDATAOBJECT    This,
+                        LPENUMSTATDATA *ppenumAdvise)
 {
-  return E_UNEXPECTED;
+  GDK_NOTE (DND, g_print ("idataobject_enumdadvise %#x\n", This));
+
+  return E_FAIL;
 }
                
+static ULONG STDMETHODCALLTYPE
+ienumformatetc_addref (LPENUMFORMATETC This)
+{
+  enum_formats *en = (enum_formats *) This;
+  int ref_count = ++en->ref_count;
+
+  GDK_NOTE (DND, g_print ("ienumformatetc_addref %#x %d\n", This, ref_count));
+
+  return ref_count;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ienumformatetc_queryinterface (LPENUMFORMATETC This,
+                              REFIID          riid,
+                              LPVOID         *ppvObject)
+{
+  GDK_NOTE (DND, g_print ("ienumformatetc_queryinterface %#x\n", This));
+
+  *ppvObject = NULL;
+
+  PRINT_GUID (riid);
+  if (IsEqualGUID (riid, &IID_IUnknown))
+    {
+      g_print ("...IUnknown\n");
+      ienumformatetc_addref (This);
+      *ppvObject = This;
+      return S_OK;
+    }
+  else if (IsEqualGUID (riid, &IID_IEnumFORMATETC))
+    {
+      g_print ("...IEnumFORMATETC\n");
+      ienumformatetc_addref (This);
+      *ppvObject = This;
+      return S_OK;
+    }
+  else
+    {
+      g_print ("...Huh?\n");
+      return E_NOINTERFACE;
+    }
+}
+
+static ULONG STDMETHODCALLTYPE
+ienumformatetc_release (LPENUMFORMATETC This)
+{
+  enum_formats *en = (enum_formats *) This;
+  int ref_count = --en->ref_count;
+
+  GDK_NOTE (DND, g_print ("ienumformatetc_release %#x %d\n", This, ref_count));
+
+  if (ref_count == 0)
+    g_free (This);
+
+  return ref_count;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ienumformatetc_next (LPENUMFORMATETC This,
+                    ULONG           celt,
+                    LPFORMATETC     elts,
+                    ULONG          *nelt)
+{
+  enum_formats *en = (enum_formats *) This;
+  int i, n;
+
+  GDK_NOTE (DND, g_print ("ienumformatetc_next %#x %d %d\n", This, en->ix, celt));
+
+  n = 0;
+  for (i = 0; i < celt; i++)
+    {
+      if (en->ix >= nformats)
+       break;
+      elts[i] = formats[en->ix++];
+      n++;
+    }
+
+  if (nelt != NULL)
+    *nelt = n;
+
+  if (n == celt)
+    return S_OK;
+  else
+    return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ienumformatetc_skip (LPENUMFORMATETC This,
+                    ULONG           celt)
+{
+  enum_formats *en = (enum_formats *) This;
+
+  GDK_NOTE (DND, g_print ("ienumformatetc_skip %#x %d %d\n", This, en->ix, celt));
+  en->ix += celt;
+
+  return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ienumformatetc_reset (LPENUMFORMATETC This)
+{
+  enum_formats *en = (enum_formats *) This;
+
+  GDK_NOTE (DND, g_print ("ienumformatetc_reset %#x\n", This));
+
+  en->ix = 0;
+
+  return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE
+ienumformatetc_clone (LPENUMFORMATETC  This,
+                     LPENUMFORMATETC *ppEnumFormatEtc)
+{
+  enum_formats *en = (enum_formats *) This;
+  enum_formats *new;
+
+  GDK_NOTE (DND, g_print ("ienumformatetc_clone %#x\n", This));
+
+  new = enum_formats_new ();
+
+  new->ix = en->ix;
+
+  *ppEnumFormatEtc = &new->ief;
+
+  return S_OK;
+}
+
 static IDropTargetVtbl idt_vtbl = {
-  m_query_interface_target,
-  m_add_ref_target,
-  m_release_target,
-  m_drag_enter,
-  m_drag_over,
-  m_drag_leave,
-  m_drop
+  idroptarget_queryinterface,
+  idroptarget_addref,
+  idroptarget_release,
+  idroptarget_dragenter,
+  idroptarget_dragover,
+  idroptarget_dragleave,
+  idroptarget_drop
 };
 
 static IDropSourceVtbl ids_vtbl = {
-  m_query_interface_source,
-  m_add_ref_source,
-  m_release_source,
-  m_query_continue_drag,
-  m_give_feedback
+  idropsource_queryinterface,
+  idropsource_addref,
+  idropsource_release,
+  idropsource_querycontinuedrag,
+  idropsource_givefeedback
 };
 
 static IDataObjectVtbl ido_vtbl = {
-  m_query_interface_object,
-  m_add_ref_object,
-  m_release_object,
-  m_get_data,
-  m_get_data_here,
-  m_query_get_data,
-  m_get_canonical_format_etc,
-  m_set_data,
-  m_enum_format_etc,
-  m_d_advise,
-  m_d_unadvise,
-  m_enum_d_advise
+  idataobject_queryinterface,
+  idataobject_addref,
+  idataobject_release,
+  idataobject_getdata,
+  idataobject_getdatahere,
+  idataobject_querygetdata,
+  idataobject_getcanonicalformatetc,
+  idataobject_setdata,
+  idataobject_enumformatetc,
+  idataobject_dadvise,
+  idataobject_dunadvise,
+  idataobject_enumdadvise
+};
+
+static IEnumFORMATETCVtbl ief_vtbl = {
+  ienumformatetc_queryinterface,
+  ienumformatetc_addref,
+  ienumformatetc_release,
+  ienumformatetc_next,
+  ienumformatetc_skip,
+  ienumformatetc_reset,
+  ienumformatetc_clone
 };
 
 #endif /* OLE2_DND */
@@ -528,6 +787,9 @@ target_context_new (void)
 #endif
 
   result->context = gdk_drag_context_new ();
+  result->context->is_source = FALSE;
+
+  GDK_NOTE (DND, g_print ("target_context_new: %p\n", result));
 
   return result;
 }
@@ -544,11 +806,47 @@ source_context_new (void)
 #endif
 
   result->context = gdk_drag_context_new ();
+  result->context->is_source = TRUE;
+
+  GDK_NOTE (DND, g_print ("source_context_new: %p\n", result));
+
+  return result;
+}
+
+#ifdef OLE2_DND
+static data_object *
+data_object_new (void)
+{
+  data_object *result;
+
+  result = g_new0 (data_object, 1);
+
+  result->ido.lpVtbl = &ido_vtbl;
+  result->ref_count = 1;
+
+  GDK_NOTE (DND, g_print ("data_object_new: %#x\n", result));
 
   return result;
 }
 
-#ifdef _MSC_VER
+
+static enum_formats *
+enum_formats_new (void)
+{
+  enum_formats *result;
+
+  result = g_new0 (enum_formats, 1);
+
+  result->ief.lpVtbl = &ief_vtbl;
+  result->ref_count = 1;
+  result->ix = 0;
+
+  GDK_NOTE (DND, g_print ("enum_formats_new: %#x\n", result));
+
+  return result;
+}
+
+#endif
 
 /* From MS Knowledge Base article Q130698 */
 
@@ -562,10 +860,10 @@ source_context_new (void)
  */
 
 static HRESULT 
-resolve_link(HWND hWnd,
+resolve_link(HWND    hWnd,
             LPCTSTR lpszLinkName,
-            LPSTR lpszPath,
-            LPSTR lpszDescription)
+            LPSTR   lpszPath,
+            LPSTR   lpszDescription)
 {
   HRESULT hres;
   IShellLink *psl;
@@ -639,49 +937,39 @@ resolve_link(HWND hWnd,
   return SUCCEEDED (hres);
 }
 
-#else
-
-#define resolve_link(hWnd, lpszLinkName, lpszPath, lpszDescription) FALSE
-
-#endif
-
 static GdkFilterReturn
 gdk_dropfiles_filter (GdkXEvent *xev,
                      GdkEvent  *event,
                      gpointer   data)
 {
   GdkDragContext *context;
-  GdkDragContextPrivate *private;
-  static GdkAtom text_uri_list_atom = GDK_NONE;
+  GdkDragContextPrivateWin32 *private;
   GString *result;
   MSG *msg = (MSG *) xev;
   HANDLE hdrop;
   POINT pt;
-  gint nfiles, i, k;
+  gint nfiles, i;
   guchar fileName[MAX_PATH], linkedFile[MAX_PATH];
   
-  if (text_uri_list_atom == GDK_NONE)
-    text_uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE);
-
   if (msg->message == WM_DROPFILES)
     {
-      GDK_NOTE (DND, g_print ("WM_DROPFILES: %#x\n", msg->hwnd));
+      GDK_NOTE (DND, g_print ("WM_DROPFILES: %#x\n", (guint) msg->hwnd));
 
       context = gdk_drag_context_new ();
-      private = (GdkDragContextPrivate *) context;
+      private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
       context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
       context->is_source = FALSE;
-      context->source_window = (GdkWindow *) gdk_root_parent;
+      context->source_window = _gdk_parent_root;
+      gdk_drawable_ref (context->source_window);
       context->dest_window = event->any.window;
-      gdk_window_ref (context->dest_window);
+      gdk_drawable_ref (context->dest_window);
       /* WM_DROPFILES drops are always file names */
       context->targets =
-       g_list_append (NULL, GUINT_TO_POINTER (text_uri_list_atom));
+       g_list_append (NULL, GUINT_TO_POINTER (_text_uri_list));
       current_dest_drag = context;
 
       event->dnd.type = GDK_DROP_START;
       event->dnd.context = current_dest_drag;
-      gdk_drag_context_ref (current_dest_drag);
       
       hdrop = (HANDLE) msg->wParam;
       DragQueryPoint (hdrop, &pt);
@@ -689,32 +977,43 @@ gdk_dropfiles_filter (GdkXEvent *xev,
 
       event->dnd.x_root = pt.x;
       event->dnd.y_root = pt.y;
-      event->dnd.time = msg->time;
+      event->dnd.time = _gdk_win32_get_next_tick (msg->time);
 
       nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
 
       result = g_string_new (NULL);
       for (i = 0; i < nfiles; i++)
        {
-         g_string_append (result, "file:");
+         gchar *uri;
+
          DragQueryFile (hdrop, i, fileName, MAX_PATH);
 
          /* Resolve shortcuts */
          if (resolve_link (msg->hwnd, fileName, linkedFile, NULL))
            {
-             g_string_append (result, linkedFile);
-             GDK_NOTE (DND, g_print ("...%s link to %s\n",
-                                     fileName, linkedFile));
+             uri = g_filename_to_uri (linkedFile, NULL, NULL);
+             if (uri != NULL)
+               {
+                 g_string_append (result, uri);
+                 GDK_NOTE (DND, g_print ("...%s link to %s: %s\n",
+                                         fileName, linkedFile, uri));
+                 g_free (uri);
+               }
            }
          else
            {
-             g_string_append (result, fileName);
-             GDK_NOTE (DND, g_print ("...%s\n", fileName));
+             uri = g_filename_to_uri (fileName, NULL, NULL);
+             if (uri != NULL)
+               {
+                 g_string_append (result, uri);
+                 GDK_NOTE (DND, g_print ("...%s: %s\n", fileName, uri));
+                 g_free (uri);
+               }
            }
          g_string_append (result, "\015\012");
        }
-      gdk_sel_prop_store ((GdkWindow *) gdk_root_parent,
-                         text_uri_list_atom, 8, result->str, result->len + 1);
+      _gdk_dropfiles_store (result->str);
+      g_string_free (result, FALSE);
 
       DragFinish (hdrop);
       
@@ -729,19 +1028,34 @@ gdk_dropfiles_filter (GdkXEvent *xev,
  *************************************************************/
 
 void
-gdk_dnd_init (void)
+_gdk_dnd_init (void)
 {
-  HRESULT hres;
 #ifdef OLE2_DND
+  HRESULT hres;
   hres = OleInitialize (NULL);
 
   if (! SUCCEEDED (hres))
     g_error ("OleInitialize failed");
+
+  nformats = 2;
+  formats = g_new (FORMATETC, nformats);
+
+  formats[0].cfFormat = CF_TEXT;
+  formats[0].ptd = NULL;
+  formats[0].dwAspect = DVASPECT_CONTENT;
+  formats[0].lindex = -1;
+  formats[0].tymed = TYMED_HGLOBAL;
+  
+  formats[1].cfFormat = CF_GDIOBJFIRST;
+  formats[1].ptd = NULL;
+  formats[1].dwAspect = DVASPECT_CONTENT;
+  formats[1].lindex = -1;
+  formats[1].tymed = TYMED_HGLOBAL;
 #endif
 }      
 
 void
-gdk_dnd_exit (void)
+_gdk_win32_dnd_exit (void)
 {
 #ifdef OLE2_DND
   OleUninitialize ();
@@ -751,31 +1065,199 @@ gdk_dnd_exit (void)
 /* Source side */
 
 static void
-gdk_drag_do_leave (GdkDragContext *context, guint32 time)
+local_send_leave (GdkDragContext *context,
+                 guint32         time)
+{
+  GdkEvent tmp_event;
+  
+  if ((current_dest_drag != NULL) &&
+      (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
+      (current_dest_drag->source_window == context->source_window))
+    {
+      tmp_event.dnd.type = GDK_DRAG_LEAVE;
+      tmp_event.dnd.window = context->dest_window;
+      /* Pass ownership of context to the event */
+      tmp_event.dnd.send_event = FALSE;
+      tmp_event.dnd.context = current_dest_drag;
+      tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+
+      current_dest_drag = NULL;
+      
+      gdk_event_put (&tmp_event);
+    }
+}
+
+static void
+local_send_enter (GdkDragContext *context,
+                 guint32         time)
+{
+  GdkEvent tmp_event;
+  GdkDragContextPrivateWin32 *private;
+  GdkDragContext *new_context;
+
+  private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
+  
+  if (current_dest_drag != NULL)
+    {
+      gdk_drag_context_unref (current_dest_drag);
+      current_dest_drag = NULL;
+    }
+
+  new_context = gdk_drag_context_new ();
+  new_context->protocol = GDK_DRAG_PROTO_LOCAL;
+  new_context->is_source = FALSE;
+
+  new_context->source_window = context->source_window;
+  gdk_window_ref (new_context->source_window);
+  new_context->dest_window = context->dest_window;
+  gdk_window_ref (new_context->dest_window);
+
+  new_context->targets = g_list_copy (context->targets);
+
+  gdk_window_set_events (new_context->source_window,
+                        gdk_window_get_events (new_context->source_window) |
+                        GDK_PROPERTY_CHANGE_MASK);
+  new_context->actions = context->actions;
+
+  tmp_event.dnd.type = GDK_DRAG_ENTER;
+  tmp_event.dnd.window = context->dest_window;
+  tmp_event.dnd.send_event = FALSE;
+  tmp_event.dnd.context = new_context;
+  tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+  
+  current_dest_drag = new_context;
+  
+  gdk_event_put (&tmp_event);
+}
+
+static void
+local_send_motion (GdkDragContext *context,
+                  gint            x_root, 
+                  gint            y_root,
+                  GdkDragAction   action,
+                  guint32         time)
+{
+  GdkEvent tmp_event;
+  
+  if ((current_dest_drag != NULL) &&
+      (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
+      (current_dest_drag->source_window == context->source_window))
+    {
+      tmp_event.dnd.type = GDK_DRAG_MOTION;
+      tmp_event.dnd.window = current_dest_drag->dest_window;
+      tmp_event.dnd.send_event = FALSE;
+      tmp_event.dnd.context = current_dest_drag;
+      tmp_event.dnd.time = time;
+
+      current_dest_drag->suggested_action = action;
+      current_dest_drag->actions = current_dest_drag->suggested_action;
+
+      tmp_event.dnd.x_root = x_root;
+      tmp_event.dnd.y_root = y_root;
+
+      (GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag))->last_x = x_root;
+      (GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag))->last_y = y_root;
+
+      GDK_DRAG_CONTEXT_PRIVATE_DATA (context)->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
+      
+      gdk_event_put (&tmp_event);
+    }
+}
+
+static void
+local_send_drop (GdkDragContext *context,
+                guint32         time)
+{
+  GdkEvent tmp_event;
+  
+  if ((current_dest_drag != NULL) &&
+      (current_dest_drag->protocol == GDK_DRAG_PROTO_LOCAL) &&
+      (current_dest_drag->source_window == context->source_window))
+    {
+      GdkDragContextPrivateWin32 *private;
+      private = GDK_DRAG_CONTEXT_PRIVATE_DATA (current_dest_drag);
+
+      tmp_event.dnd.type = GDK_DROP_START;
+      tmp_event.dnd.window = current_dest_drag->dest_window;
+      tmp_event.dnd.send_event = FALSE;
+      tmp_event.dnd.context = current_dest_drag;
+      tmp_event.dnd.time = GDK_CURRENT_TIME;
+      
+      tmp_event.dnd.x_root = private->last_x;
+      tmp_event.dnd.y_root = private->last_y;
+      
+      gdk_event_put (&tmp_event);
+    }
+
+}
+
+static void
+gdk_drag_do_leave (GdkDragContext *context,
+                  guint32         time)
 {
   if (context->dest_window)
     {
       GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n"));
-      gdk_window_unref (context->dest_window);
+
+      switch (context->protocol)
+       {
+       case GDK_DRAG_PROTO_LOCAL:
+         local_send_leave (context, time);
+         break;
+       default:
+         break;
+       }
+
+      gdk_drawable_unref (context->dest_window);
       context->dest_window = NULL;
     }
 }
 
 GdkDragContext * 
-gdk_drag_begin (GdkWindow     *window,
-               GList         *targets)
+gdk_drag_begin (GdkWindow *window,
+               GList     *targets)
 {
+#ifndef OLE2_DND
   GList *tmp_list;
+  GdkDragContext *new_context;
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  new_context = gdk_drag_context_new ();
+  new_context->is_source = TRUE;
+  new_context->source_window = window;
+  gdk_window_ref (window);
+
+  tmp_list = g_list_last (targets);
+  new_context->targets = NULL;
+  while (tmp_list)
+    {
+      new_context->targets = g_list_prepend (new_context->targets,
+                                            tmp_list->data);
+      tmp_list = tmp_list->prev;
+    }
+
+  new_context->actions = 0;
+
+  return new_context;
+#else
   source_drag_context *ctx;
-  
+  GList *tmp_list;
+  data_object *dobj;
+  HRESULT hResult;
+  DWORD dwEffect;
+  HGLOBAL global;
+  FORMATETC format;
+  STGMEDIUM medium;
+
   g_return_val_if_fail (window != NULL, NULL);
 
   GDK_NOTE (DND, g_print ("gdk_drag_begin\n"));
 
   ctx = source_context_new ();
-  ctx->context->is_source = TRUE;
+  ctx->context->protocol = GDK_DRAG_PROTO_OLE2;
   ctx->context->source_window = window;
-  gdk_window_ref (window);
+  gdk_drawable_ref (window);
 
   tmp_list = g_list_last (targets);
   ctx->context->targets = NULL;
@@ -788,37 +1270,65 @@ gdk_drag_begin (GdkWindow     *window,
 
   ctx->context->actions = 0;
 
-#if 0
-  DoDragDrop (...);
-#endif
+  dobj = data_object_new ();
+
+  global = GlobalAlloc (GMEM_FIXED, sizeof (ctx));
+
+  memcpy (&global, ctx, sizeof (ctx));
+
+  medium.tymed = TYMED_HGLOBAL;
+  medium.hGlobal = global;
+  medium.pUnkForRelease = NULL;
+
+  dobj->ido.lpVtbl->SetData (&dobj->ido, &formats[1], &medium, TRUE);
+
+  hResult = DoDragDrop (&dobj->ido, &ctx->ids, DROPEFFECT_MOVE|DROPEFFECT_COPY, &dwEffect);
+
+  GDK_NOTE (DND, g_print ("DoDragDrop returned %s\n",
+                         (hResult == DRAGDROP_S_DROP ? "DRAGDROP_S_DROP" :
+                          (hResult == DRAGDROP_S_CANCEL ? "DRAGDROP_S_CANCEL" :
+                           (hResult == E_UNEXPECTED ? "E_UNEXPECTED" :
+                            g_strdup_printf ("%#.8x", hResult))))));
+
+  dobj->ido.lpVtbl->Release (&dobj->ido);
+  ctx->ids.lpVtbl->Release (&ctx->ids);
+
   return ctx->context;
+#endif
 }
 
 guint32
-gdk_drag_get_protocol (guint32          xid,
-                      GdkDragProtocol *protocol)
+gdk_drag_get_protocol_for_display (GdkDisplay      *display,
+                                  guint32          xid,
+                                  GdkDragProtocol *protocol)
 {
-  /* This isn't used */
+  GdkWindow *window;
+
+  GDK_NOTE (DND, g_print ("gdk_drag_get_protocol\n"));
+
+  window = gdk_window_lookup (xid);
+
+  if (GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
+    {
+      *protocol = GDK_DRAG_PROTO_LOCAL;
+      return xid;
+    }
+
   return 0;
 }
 
 void
-gdk_drag_find_window (GdkDragContext  *context,
-                     GdkWindow       *drag_window,
-                     gint             x_root,
-                     gint             y_root,
-                     GdkWindow      **dest_window,
-                     GdkDragProtocol *protocol)
-{
-  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
-  GdkDrawablePrivate *drag_window_private = (GdkDrawablePrivate*) drag_window;
+gdk_drag_find_window_for_screen (GdkDragContext  *context,
+                                GdkWindow       *drag_window,
+                                GdkScreen       *screen,
+                                gint             x_root,
+                                gint             y_root,
+                                GdkWindow      **dest_window,
+                                GdkDragProtocol *protocol)
+{
   HWND recipient;
   POINT pt;
 
-  GDK_NOTE (DND, g_print ("gdk_drag_find_window: %#x +%d+%d\n",
-                         (drag_window ? drag_window_private->xwindow : 0),
-                         x_root, y_root));
-
   pt.x = x_root;
   pt.y = y_root;
   recipient = WindowFromPoint (pt);
@@ -826,11 +1336,22 @@ gdk_drag_find_window (GdkDragContext  *context,
     *dest_window = NULL;
   else
     {
-      *dest_window = gdk_window_lookup (recipient);
+      *dest_window = gdk_win32_handle_table_lookup (GPOINTER_TO_UINT(recipient));
       if (*dest_window)
-       gdk_window_ref (*dest_window);
-      *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
+       {
+         *dest_window = gdk_window_get_toplevel (*dest_window);
+         gdk_drawable_ref (*dest_window);
+       }
+
+      if (context->source_window)
+        *protocol = GDK_DRAG_PROTO_LOCAL;
+      else
+        *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
     }
+
+  GDK_NOTE (DND, g_print ("gdk_drag_find_window: %#x +%d+%d Protocol: %d\n",
+                         (drag_window ? (guint) GDK_WINDOW_HWND (drag_window) : 0),
+                         x_root, y_root, *protocol));
 }
 
 gboolean
@@ -843,6 +1364,94 @@ gdk_drag_motion (GdkDragContext *context,
                 GdkDragAction   possible_actions,
                 guint32         time)
 {
+  GdkDragContextPrivateWin32 *private;
+
+  g_return_val_if_fail (context != NULL, FALSE);
+
+  GDK_NOTE (DND, g_print ("gdk_drag_motion\n"));
+
+  private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
+  
+  if (context->dest_window != dest_window)
+    {
+      GdkEvent temp_event;
+
+      /* Send a leave to the last destination */
+      gdk_drag_do_leave (context, time);
+      private->drag_status = GDK_DRAG_STATUS_DRAG;
+
+      /* Check if new destination accepts drags, and which protocol */
+      if (dest_window)
+       {
+         context->dest_window = dest_window;
+         gdk_window_ref (context->dest_window);
+         context->protocol = protocol;
+
+         switch (protocol)
+           {
+           case GDK_DRAG_PROTO_LOCAL:
+             local_send_enter (context, time);
+             break;
+
+           default:
+             break;
+           }
+         context->suggested_action = suggested_action;
+       }
+      else
+       {
+         context->dest_window = NULL;
+         context->action = 0;
+       }
+
+      /* Push a status event, to let the client know that
+       * the drag changed 
+       */
+
+      temp_event.dnd.type = GDK_DRAG_STATUS;
+      temp_event.dnd.window = context->source_window;
+      /* We use this to signal a synthetic status. Perhaps
+       * we should use an extra field...
+       */
+      temp_event.dnd.send_event = TRUE;
+
+      temp_event.dnd.context = context;
+      temp_event.dnd.time = time;
+
+      gdk_event_put (&temp_event);
+    }
+  else
+    {
+      context->suggested_action = suggested_action;
+    }
+
+  /* Send a drag-motion event */
+
+  private->last_x = x_root;
+  private->last_y = y_root;
+      
+  if (context->dest_window)
+    {
+      if (private->drag_status == GDK_DRAG_STATUS_DRAG)
+       {
+         switch (context->protocol)
+           {
+           case GDK_DRAG_PROTO_LOCAL:
+             local_send_motion (context, x_root, y_root, suggested_action, time);
+             break;
+             
+           case GDK_DRAG_PROTO_NONE:
+             g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_motion()");
+             break;
+
+           default:
+             break;
+           }
+       }
+      else
+       return TRUE;
+    }
+
   return FALSE;
 }
 
@@ -852,7 +1461,24 @@ gdk_drag_drop (GdkDragContext *context,
 {
   g_return_if_fail (context != NULL);
 
-  g_warning ("gdk_drag_drop: not implemented\n");
+  GDK_NOTE (DND, g_print ("gdk_drag_drop\n"));
+
+  if (context->dest_window)
+    {
+      switch (context->protocol)
+       {
+       case GDK_DRAG_PROTO_LOCAL:
+         local_send_drop (context, time);
+         break;
+
+       case GDK_DRAG_PROTO_NONE:
+         g_warning ("GDK_DRAG_PROTO_NONE is not valid in gdk_drag_drop()");
+         break;
+
+       default:
+         break;
+       }
+    }
 }
 
 void
@@ -861,39 +1487,111 @@ gdk_drag_abort (GdkDragContext *context,
 {
   g_return_if_fail (context != NULL);
 
+  GDK_NOTE (DND, g_print ("gdk_drag_abort\n"));
+
   gdk_drag_do_leave (context, time);
 }
 
 /* Destination side */
 
 void
-gdk_drag_status (GdkDragContext   *context,
-                GdkDragAction     action,
-                guint32           time)
+gdk_drag_status (GdkDragContext *context,
+                GdkDragAction   action,
+                guint32         time)
 {
-  GDK_NOTE (DND, g_print ("gdk_drag_status\n"));
+  GdkDragContextPrivateWin32 *private;
+  GdkDragContext *src_context;
+  GdkEvent tmp_event;
+
+  g_return_if_fail (context != NULL);
+
+  private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
+
+  src_context = gdk_drag_context_find (TRUE,
+                                      context->source_window,
+                                      context->dest_window);
+
+  if (src_context)
+    {
+      GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (src_context);
+      
+      if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
+       private->drag_status = GDK_DRAG_STATUS_DRAG;
+
+      tmp_event.dnd.type = GDK_DRAG_STATUS;
+      tmp_event.dnd.window = context->source_window;
+      tmp_event.dnd.send_event = FALSE;
+      tmp_event.dnd.context = src_context;
+      tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
+
+      if (action == GDK_ACTION_DEFAULT)
+       action = 0;
+      
+      src_context->action = action;
+      
+      gdk_event_put (&tmp_event);
+    }
 }
 
 void 
-gdk_drop_reply (GdkDragContext   *context,
-               gboolean          ok,
-               guint32           time)
+gdk_drop_reply (GdkDragContext *context,
+               gboolean        ok,
+               guint32         time)
 {
+  g_return_if_fail (context != NULL);
+
+  GDK_NOTE (DND, g_print ("gdk_drop_reply\n"));
+
+  if (context->dest_window)
+    {
+      switch (context->protocol)
+       {
+       case GDK_DRAG_PROTO_WIN32_DROPFILES:
+         _gdk_dropfiles_store (NULL);
+         break;
+
+       default:
+         break;
+       }
+    }
 }
 
 void
-gdk_drop_finish (GdkDragContext   *context,
-                gboolean          success,
-                guint32           time)
+gdk_drop_finish (GdkDragContext *context,
+                gboolean        success,
+                guint32         time)
 {
+  GdkDragContextPrivateWin32 *private;
+  GdkDragContext *src_context;
+  GdkEvent tmp_event;
+       
+  g_return_if_fail (context != NULL);
+
+  GDK_NOTE (DND, g_print ("gdk_drop_finish\n"));
+
+  private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context);
+
+  src_context = gdk_drag_context_find (TRUE,
+                                      context->source_window,
+                                      context->dest_window);
+  if (src_context)
+    {
+      tmp_event.dnd.type = GDK_DROP_FINISHED;
+      tmp_event.dnd.window = src_context->source_window;
+      tmp_event.dnd.send_event = FALSE;
+      tmp_event.dnd.context = src_context;
+
+      gdk_event_put (&tmp_event);
+    }
 }
 
+#ifdef OLE2_DND
+
 static GdkFilterReturn
 gdk_destroy_filter (GdkXEvent *xev,
                    GdkEvent  *event,
                    gpointer   data)
 {
-#ifdef OLE2_DND
   MSG *msg = (MSG *) xev;
 
   if (msg->message == WM_DESTROY)
@@ -901,25 +1599,33 @@ gdk_destroy_filter (GdkXEvent *xev,
       IDropTarget *idtp = (IDropTarget *) data;
 
       GDK_NOTE (DND, g_print ("gdk_destroy_filter: WM_DESTROY: %#x\n", msg->hwnd));
+#if 0
+      idtp->lpVtbl->Release (idtp);
+#endif
       RevokeDragDrop (msg->hwnd);
       CoLockObjectExternal (idtp, FALSE, TRUE);
     }
-#endif
   return GDK_FILTER_CONTINUE;
 }
+#endif
 
 void
-gdk_window_register_dnd (GdkWindow      *window)
+gdk_window_register_dnd (GdkWindow *window)
 {
-  GdkDrawablePrivate *private = (GdkDrawablePrivate *) window;
 #ifdef OLE2_DND
-  target_drag_context *context;
+  target_drag_context *ctx;
   HRESULT hres;
 #endif
 
   g_return_if_fail (window != NULL);
 
-  GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %#x\n", private->xwindow));
+  if (GPOINTER_TO_INT (gdk_drawable_get_data (window, "gdk-dnd-registered")))
+    return;
+
+  gdk_drawable_set_data (window, "gdk-dnd-registered", GINT_TO_POINTER(TRUE), NULL);
+
+  GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %#x\n",
+                         (guint) GDK_WINDOW_HWND (window)));
 
   /* We always claim to accept dropped files, but in fact we might not,
    * of course. This function is called in such a way that it cannot know
@@ -927,27 +1633,31 @@ gdk_window_register_dnd (GdkWindow      *window)
    * (in gtk, data of type text/uri-list) or not.
    */
   gdk_window_add_filter (window, gdk_dropfiles_filter, NULL);
-  DragAcceptFiles (private->xwindow, TRUE);
+  DragAcceptFiles (GDK_WINDOW_HWND (window), TRUE);
 
 #ifdef OLE2_DND
   /* Register for OLE2 d&d */
-  context = target_context_new ();
-  hres = CoLockObjectExternal ((IUnknown *) &context->idt, TRUE, FALSE);
+  ctx = target_context_new ();
+  ctx->context->protocol = GDK_DRAG_PROTO_OLE2;
+  hres = CoLockObjectExternal ((IUnknown *) &ctx->idt, TRUE, FALSE);
   if (!SUCCEEDED (hres))
-    g_warning ("gdk_window_register_dnd: CoLockObjectExternal failed");
+    OTHER_API_FAILED ("CoLockObjectExternal");
   else
     {
-      hres = RegisterDragDrop (private->xwindow, &context->idt);
+      hres = RegisterDragDrop (GDK_WINDOW_HWND (window), &ctx->idt);
       if (hres == DRAGDROP_E_ALREADYREGISTERED)
        {
          g_print ("DRAGDROP_E_ALREADYREGISTERED\n");
-         CoLockObjectExternal ((IUnknown *) &context->idt, FALSE, FALSE);
+#if 0
+         ctx->idt.lpVtbl->Release (&ctx->idt);
+#endif
+         CoLockObjectExternal ((IUnknown *) &ctx->idt, FALSE, FALSE);
        }
       else if (!SUCCEEDED (hres))
-       g_warning ("gdk_window_register_dnd: RegisterDragDrop failed");
+       OTHER_API_FAILED ("RegisterDragDrop");
       else
        {
-         gdk_window_add_filter (window, gdk_destroy_filter, &context->idt);
+         gdk_window_add_filter (window, gdk_destroy_filter, &ctx->idt);
        }
     }
 #endif
@@ -964,10 +1674,12 @@ gdk_window_register_dnd (GdkWindow      *window)
 GdkAtom
 gdk_drag_get_selection (GdkDragContext *context)
 {
-  if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES)
-    return gdk_win32_dropfiles_atom;
+  if (context->protocol == GDK_DRAG_PROTO_LOCAL)
+    return _local_dnd;
+  else if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES)
+    return _gdk_win32_dropfiles;
   else if (context->protocol == GDK_DRAG_PROTO_OLE2)
-    return gdk_ole2_dnd_atom;
+    return _gdk_ole2_dnd;
   else
     return GDK_NONE;
 }