X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gdk%2Fwin32%2Fgdkdnd-win32.c;h=08cdcdef3e0a9d8ab29201c4d0fe64bb32b5395c;hb=af9b53fc58e40613b1f08e7e9aae0a21da321be2;hp=45891291734be07c7ed1457b5957b72927056779;hpb=c50941c82dbef8fb6122ab4f19bd592cb7fc58ef;p=~andy%2Fgtk diff --git a/gdk/win32/gdkdnd-win32.c b/gdk/win32/gdkdnd-win32.c index 458912917..08cdcdef3 100644 --- a/gdk/win32/gdkdnd-win32.c +++ b/gdk/win32/gdkdnd-win32.c @@ -1,53 +1,53 @@ /* 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 +/* #define OLE2_DND */ + #define INITGUID #include "gdkdnd.h" #include "gdkproperty.h" -#include "gdkprivate.h" -#include "gdkx.h" +#include "gdkinternals.h" +#include "gdkprivate-win32.h" #ifdef OLE2_DND #include +#else +#include #endif -#ifdef _MSC_VER /* These aren't in mingw32 */ #include #include -#endif #include -typedef struct _GdkDragContextPrivate GdkDragContextPrivate; +typedef struct _GdkDragContextPrivateWin32 GdkDragContextPrivateWin32; typedef enum { GDK_DRAG_STATUS_DRAG, @@ -63,144 +63,238 @@ typedef enum { #ifdef OLE2_DND -#define PRINT_RIID(riid) \ - g_print ("riid = %.08x-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", \ - ((gulong *) riid)[0], \ - ((gushort *) riid)[2], \ - ((gushort *) riid)[3], \ - ((guchar *) riid)[8], \ - ((guchar *) riid)[9], \ - ((guchar *) riid)[10], \ - ((guchar *) riid)[11], \ - ((guchar *) riid)[12], \ - ((guchar *) riid)[13], \ - ((guchar *) riid)[14], \ - ((guchar *) riid)[15]); - - -HRESULT STDMETHODCALLTYPE - m_query_interface_target (IDropTarget __RPC_FAR *This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - -ULONG STDMETHODCALLTYPE - m_add_ref_target (IDropTarget __RPC_FAR *This); - -ULONG STDMETHODCALLTYPE - m_release_target (IDropTarget __RPC_FAR *This); - -HRESULT STDMETHODCALLTYPE - m_drag_enter (IDropTarget __RPC_FAR *This, - /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, - /* [in] */ DWORD grfKeyState, - /* [in] */ POINTL pt, - /* [out][in] */ DWORD __RPC_FAR *pdwEffect); - -HRESULT STDMETHODCALLTYPE - m_drag_over (IDropTarget __RPC_FAR *This, - /* [in] */ DWORD grfKeyState, - /* [in] */ POINTL pt, - /* [out][in] */ DWORD __RPC_FAR *pdwEffect); - -HRESULT STDMETHODCALLTYPE - m_drag_leave (IDropTarget __RPC_FAR *This); - -HRESULT STDMETHODCALLTYPE - m_drop (IDropTarget __RPC_FAR *This, - /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, - /* [in] */ DWORD grfKeyState, - /* [in] */ POINTL pt, - /* [out][in] */ DWORD __RPC_FAR *pdwEffect); - -HRESULT STDMETHODCALLTYPE - m_query_interface_source (IDropSource __RPC_FAR *This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); - -ULONG STDMETHODCALLTYPE - m_add_ref_source (IDropSource __RPC_FAR *This); - -ULONG STDMETHODCALLTYPE - m_release_source (IDropSource __RPC_FAR *This); - -HRESULT STDMETHODCALLTYPE - m_query_continue_drag (IDropSource __RPC_FAR *This, - /* [in] */ BOOL fEscapePressed, - /* [in] */ DWORD grfKeyState); -HRESULT STDMETHODCALLTYPE - m_give_feedback (IDropSource __RPC_FAR *This, - /* [in] */ DWORD dwEffect); +#define PRINT_GUID(guid) \ + g_print ("guid = %.08x-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", \ + ((gulong *) guid)[0], \ + ((gushort *) guid)[2], \ + ((gushort *) guid)[3], \ + ((guchar *) guid)[8], \ + ((guchar *) guid)[9], \ + ((guchar *) guid)[10], \ + ((guchar *) guid)[11], \ + ((guchar *) guid)[12], \ + ((guchar *) guid)[13], \ + ((guchar *) guid)[14], \ + ((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; +GType +gdk_drag_context_get_type (void) +{ + static GType object_type = 0; + + 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; +} + +static void +gdk_drag_context_init (GdkDragContext *dragcontext) +{ + GdkDragContextPrivateWin32 *private = g_new0 (GdkDragContextPrivateWin32, 1); + + dragcontext->windowing_data = private; + private->ref_count = 1; + + contexts = g_list_prepend (contexts, dragcontext); +} + +static void +gdk_drag_context_class_init (GdkDragContextClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = gdk_drag_context_finalize; +} + +static void +gdk_drag_context_finalize (GObject *object) +{ + GdkDragContext *context = GDK_DRAG_CONTEXT (object); + GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (context); + + g_list_free (context->targets); + + 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); + + g_free (private); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +/* Drag Contexts */ + GdkDragContext * -gdk_drag_context_new (void) +gdk_drag_context_new (void) +{ + return g_object_new (gdk_drag_context_get_type (), NULL); +} + +void +gdk_drag_context_ref (GdkDragContext *context) { - GdkDragContextPrivate *result; + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); - result = g_new0 (GdkDragContextPrivate, 1); + GDK_NOTE (DND, g_print ("gdk_drag_context_ref: %p %d\n", context, G_OBJECT(context)->ref_count)); - result->ref_count = 1; + g_object_ref (context); +} - contexts = g_list_prepend (contexts, result); +void +gdk_drag_context_unref (GdkDragContext *context) +{ + g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); - return (GdkDragContext *)result; + 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, + 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 == 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; } -#ifdef OLE2_DND typedef struct { +#ifdef OLE2_DND IDropTarget idt; +#endif GdkDragContext *context; } target_drag_context; typedef struct { +#ifdef OLE2_DND IDropSource ids; +#endif GdkDragContext *context; } source_drag_context; -HRESULT STDMETHODCALLTYPE -m_query_interface_target (IDropTarget __RPC_FAR *This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) +#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 +idroptarget_addref (LPDROPTARGET This) +{ + target_drag_context *ctx = (target_drag_context *) This; + GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context); + int ref_count = ++private->ref_count; + + gdk_drag_context_ref (ctx->context); + GDK_NOTE (DND, g_print ("idroptarget_addref %#x %d\n", This, ref_count)); + + return ref_count; +} + +static HRESULT STDMETHODCALLTYPE +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; - PRINT_RIID (riid); + PRINT_GUID (riid); 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; } @@ -211,96 +305,336 @@ m_query_interface_target (IDropTarget __RPC_FAR *This, } } -ULONG STDMETHODCALLTYPE -m_add_ref_target (IDropTarget __RPC_FAR *This) +static ULONG STDMETHODCALLTYPE +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_drag_context_unref (ctx->context); + GDK_NOTE (DND, g_print ("idroptarget_release %#x %d\n", This, ref_count)); + + if (ref_count == 0) + g_free (This); + + return ref_count; +} + +static HRESULT STDMETHODCALLTYPE +idroptarget_dragenter (LPDROPTARGET This, + LPDATAOBJECT pDataObj, + DWORD grfKeyState, + POINTL pt, + LPDWORD pdwEffect) +{ + GDK_NOTE (DND, g_print ("idroptarget_dragenter %#x\n", This)); + + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +idroptarget_dragover (LPDROPTARGET This, + DWORD grfKeyState, + POINTL pt, + LPDWORD pdwEffect) +{ + GDK_NOTE (DND, g_print ("idroptarget_dragover %#x\n", This)); + + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +idroptarget_dragleave (LPDROPTARGET This) +{ + GDK_NOTE (DND, g_print ("idroptarget_dragleave %#x\n", This)); + + return E_UNEXPECTED; +} + +static HRESULT STDMETHODCALLTYPE +idroptarget_drop (LPDROPTARGET This, + LPDATAOBJECT pDataObj, + DWORD grfKeyState, + POINTL pt, + LPDWORD pdwEffect) +{ + GDK_NOTE (DND, g_print ("idroptarget_drop %#x\n", This)); + + return E_UNEXPECTED; +} + +static ULONG STDMETHODCALLTYPE +idropsource_addref (LPDROPSOURCE This) +{ + source_drag_context *ctx = (source_drag_context *) This; + GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context); - GDK_NOTE (DND, g_print ("m_add_ref_target\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; } -ULONG STDMETHODCALLTYPE -m_release_target (IDropTarget __RPC_FAR *This) +static HRESULT STDMETHODCALLTYPE +idropsource_queryinterface (LPDROPSOURCE This, + REFIID riid, + LPVOID *ppvObject) { - target_drag_context *ctx = (target_drag_context *) This; - GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context; + GDK_NOTE (DND, g_print ("idropsource_queryinterface %#x\n", This)); - GDK_NOTE (DND, g_print ("m_release_target\n")); - gdk_drag_context_unref (ctx->context); + *ppvObject = NULL; - if (private->ref_count == 1) + PRINT_GUID (riid); + if (IsEqualGUID (riid, &IID_IUnknown)) + { + g_print ("...IUnknown\n"); + idropsource_addref (This); + *ppvObject = This; + return S_OK; + } + else if (IsEqualGUID (riid, &IID_IDropSource)) { - gdk_drag_context_unref (ctx->context); - return 0; + g_print ("...IDropSource\n"); + idropsource_addref (This); + *ppvObject = This; + return S_OK; } else - return private->ref_count - 1; + { + g_print ("...Huh?\n"); + return E_NOINTERFACE; + } } -HRESULT STDMETHODCALLTYPE -m_drag_enter (IDropTarget __RPC_FAR *This, - /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, - /* [in] */ DWORD grfKeyState, - /* [in] */ POINTL pt, - /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +static ULONG STDMETHODCALLTYPE +idropsource_release (LPDROPSOURCE This) { - GDK_NOTE (DND, g_print ("m_drag_enter\n")); + source_drag_context *ctx = (source_drag_context *) This; + GdkDragContextPrivateWin32 *private = GDK_DRAG_CONTEXT_PRIVATE_DATA (ctx->context); + int ref_count = --private->ref_count; + + gdk_drag_context_unref (ctx->context); + GDK_NOTE (DND, g_print ("idropsource_release %#x %d\n", This, ref_count)); + + if (ref_count == 0) + g_free (This); + + return ref_count; +} + +static HRESULT STDMETHODCALLTYPE +idropsource_querycontinuedrag (LPDROPSOURCE This, + BOOL fEscapePressed, + DWORD grfKeyState) +{ + GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag %#x\n", This)); + return E_UNEXPECTED; } -HRESULT STDMETHODCALLTYPE -m_drag_over (IDropTarget __RPC_FAR *This, - /* [in] */ DWORD grfKeyState, - /* [in] */ POINTL pt, - /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +static HRESULT STDMETHODCALLTYPE +idropsource_givefeedback (LPDROPSOURCE This, + DWORD dwEffect) { - GDK_NOTE (DND, g_print ("m_drag_over\n")); + GDK_NOTE (DND, g_print ("idropsource_givefeedback %#x\n", This)); + return E_UNEXPECTED; } -HRESULT STDMETHODCALLTYPE -m_drag_leave (IDropTarget __RPC_FAR *This) +static ULONG STDMETHODCALLTYPE +idataobject_addref (LPDATAOBJECT This) { - GDK_NOTE (DND, g_print ("m_drag_leave\n")); + 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 HRESULT STDMETHODCALLTYPE +idataobject_queryinterface (LPDATAOBJECT This, + REFIID riid, + LPVOID *ppvObject) +{ + 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 +idataobject_release (LPDATAOBJECT This) +{ + 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 +idataobject_getdata (LPDATAOBJECT This, + LPFORMATETC pFormatEtc, + LPSTGMEDIUM pMedium) +{ + GDK_NOTE (DND, g_print ("idataobject_getdata %#x\n", This)); + return E_UNEXPECTED; } -HRESULT STDMETHODCALLTYPE -m_drop (IDropTarget __RPC_FAR *This, - /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, - /* [in] */ DWORD grfKeyState, - /* [in] */ POINTL pt, - /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +static HRESULT STDMETHODCALLTYPE +idataobject_getdatahere (LPDATAOBJECT This, + LPFORMATETC pFormatEtc, + LPSTGMEDIUM pMedium) { - GDK_NOTE (DND, g_print ("m_drop\n")); + GDK_NOTE (DND, g_print ("idataobject_getdatahere %#x\n", This)); + return E_UNEXPECTED; } -HRESULT STDMETHODCALLTYPE -m_query_interface_source (IDropSource __RPC_FAR *This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) +static HRESULT STDMETHODCALLTYPE +idataobject_querygetdata (LPDATAOBJECT This, + LPFORMATETC pFormatEtc) { - GDK_NOTE (DND, g_print ("m_query_interface_source\n")); + 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 +idataobject_getcanonicalformatetc (LPDATAOBJECT This, + LPFORMATETC pFormatEtcIn, + LPFORMATETC pFormatEtcOut) +{ + GDK_NOTE (DND, g_print ("idataobject_getcanonicalformatetc %#x\n", This)); + + return E_FAIL; +} + +static HRESULT STDMETHODCALLTYPE +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 +idataobject_enumformatetc (LPDATAOBJECT This, + DWORD dwDirection, + LPENUMFORMATETC *ppEnumFormatEtc) +{ + 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 +idataobject_dadvise (LPDATAOBJECT This, + LPFORMATETC pFormatetc, + DWORD advf, + LPADVISESINK pAdvSink, + DWORD *pdwConnection) +{ + GDK_NOTE (DND, g_print ("idataobject_dadvise %#x\n", This)); + + return E_FAIL; +} + +static HRESULT STDMETHODCALLTYPE +idataobject_dunadvise (LPDATAOBJECT This, + DWORD dwConnection) +{ + GDK_NOTE (DND, g_print ("idataobject_dunadvise %#x\n", This)); + + return E_FAIL; +} + +static HRESULT STDMETHODCALLTYPE +idataobject_enumdadvise (LPDATAOBJECT This, + LPENUMSTATDATA *ppenumAdvise) +{ + 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_RIID (riid); + PRINT_GUID (riid); if (IsEqualGUID (riid, &IID_IUnknown)) { g_print ("...IUnknown\n"); - m_add_ref_source (This); + ienumformatetc_addref (This); *ppvObject = This; return S_OK; } - else if (IsEqualGUID (riid, &IID_IDropSource)) + else if (IsEqualGUID (riid, &IID_IEnumFORMATETC)) { - g_print ("...IDropSource\n"); - m_add_ref_source (This); + g_print ("...IEnumFORMATETC\n"); + ienumformatetc_addref (This); *ppvObject = This; return S_OK; } @@ -311,170 +645,209 @@ m_query_interface_source (IDropSource __RPC_FAR *This, } } -ULONG STDMETHODCALLTYPE -m_add_ref_source (IDropSource __RPC_FAR *This) +static ULONG STDMETHODCALLTYPE +ienumformatetc_release (LPENUMFORMATETC This) { - source_drag_context *ctx = (source_drag_context *) This; - GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context; + enum_formats *en = (enum_formats *) This; + int ref_count = --en->ref_count; - GDK_NOTE (DND, g_print ("m_add_ref_source\n")); - gdk_drag_context_ref (ctx->context); - - return private->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; } -ULONG STDMETHODCALLTYPE -m_release_source (IDropSource __RPC_FAR *This) +static HRESULT STDMETHODCALLTYPE +ienumformatetc_next (LPENUMFORMATETC This, + ULONG celt, + LPFORMATETC elts, + ULONG *nelt) { - source_drag_context *ctx = (source_drag_context *) This; - GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context; + enum_formats *en = (enum_formats *) This; + int i, n; - GDK_NOTE (DND, g_print ("m_release_source\n")); - gdk_drag_context_unref (ctx->context); + GDK_NOTE (DND, g_print ("ienumformatetc_next %#x %d %d\n", This, en->ix, celt)); - if (private->ref_count == 1) + n = 0; + for (i = 0; i < celt; i++) { - gdk_drag_context_unref (ctx->context); - return 0; + if (en->ix >= nformats) + break; + elts[i] = formats[en->ix++]; + n++; } + + if (nelt != NULL) + *nelt = n; + + if (n == celt) + return S_OK; else - return private->ref_count - 1; + return S_FALSE; } -HRESULT STDMETHODCALLTYPE -m_query_continue_drag (IDropSource __RPC_FAR *This, - /* [in] */ BOOL fEscapePressed, - /* [in] */ DWORD grfKeyState) +static HRESULT STDMETHODCALLTYPE +ienumformatetc_skip (LPENUMFORMATETC This, + ULONG celt) { - GDK_NOTE (DND, g_print ("m_query_continue_drag\n")); - return E_UNEXPECTED; + 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; } -HRESULT STDMETHODCALLTYPE -m_give_feedback (IDropSource __RPC_FAR *This, - /* [in] */ DWORD dwEffect) +static HRESULT STDMETHODCALLTYPE +ienumformatetc_reset (LPENUMFORMATETC This) { - GDK_NOTE (DND, g_print ("m_give_feedback\n")); - return E_UNEXPECTED; + 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 = { + 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 }; -target_drag_context * +#endif /* OLE2_DND */ + +static target_drag_context * target_context_new (void) { target_drag_context *result; result = g_new0 (target_drag_context, 1); +#ifdef OLE2_DND result->idt.lpVtbl = &idt_vtbl; +#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; } -source_drag_context * +static source_drag_context * source_context_new (void) { source_drag_context *result; result = g_new0 (source_drag_context, 1); +#ifdef OLE2_DND result->ids.lpVtbl = &ids_vtbl; +#endif result->context = gdk_drag_context_new (); + result->context->is_source = TRUE; - return result; -} - -#endif /* OLE2_DND */ + GDK_NOTE (DND, g_print ("source_context_new: %p\n", result)); -void -gdk_drag_context_ref (GdkDragContext *context) -{ - g_return_if_fail (context != NULL); - - ((GdkDragContextPrivate *)context)->ref_count++; + return result; } -void -gdk_drag_context_unref (GdkDragContext *context) +#ifdef OLE2_DND +static data_object * +data_object_new (void) { - GdkDragContextPrivate *private = (GdkDragContextPrivate *)context; - - g_return_if_fail (context != NULL); - - private->ref_count--; + data_object *result; - GDK_NOTE (DND, g_print ("gdk_drag_context_unref: %d%s\n", - private->ref_count, - (private->ref_count == 0 ? " freeing" : ""))); - - if (private->ref_count == 0) - { - g_dataset_destroy (private); - - g_list_free (context->targets); + result = g_new0 (data_object, 1); - if (context->source_window) - gdk_window_unref (context->source_window); + result->ido.lpVtbl = &ido_vtbl; + result->ref_count = 1; - if (context->dest_window) - gdk_window_unref (context->dest_window); + GDK_NOTE (DND, g_print ("data_object_new: %#x\n", result)); - contexts = g_list_remove (contexts, private); - g_free (private); - } + return result; } -#if 0 -static GdkDragContext * -gdk_drag_context_find (gboolean is_source, - HWND source_xid, - HWND dest_xid) +static enum_formats * +enum_formats_new (void) { - GList *tmp_list = contexts; - GdkDragContext *context; + enum_formats *result; - while (tmp_list) - { - context = (GdkDragContext *)tmp_list->data; + result = g_new0 (enum_formats, 1); - 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)))) - return context; - - tmp_list = tmp_list->next; - } + result->ief.lpVtbl = &ief_vtbl; + result->ref_count = 1; + result->ix = 0; - return NULL; + GDK_NOTE (DND, g_print ("enum_formats_new: %#x\n", result)); + + return result; } #endif -#ifdef _MSC_VER - /* From MS Knowledge Base article Q130698 */ /* resolve_link() fills the filename and path buffer @@ -487,10 +860,10 @@ gdk_drag_context_find (gboolean is_source, */ static HRESULT -resolve_link(HWND hWnd, +resolve_link(HWND hWnd, LPCTSTR lpszLinkName, - LPSTR lpszPath, - LPSTR lpszDescription) + LPSTR lpszPath, + LPSTR lpszDescription) { HRESULT hres; IShellLink *psl; @@ -564,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); @@ -614,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); @@ -654,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 (); @@ -676,26 +1065,163 @@ 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); - GDK_NOTE (DND, g_print ("gdk_drag_begin\n")); + g_return_val_if_fail (window != NULL, NULL); new_context = gdk_drag_context_new (); new_context->is_source = TRUE; @@ -714,33 +1240,95 @@ gdk_drag_begin (GdkWindow *window, 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->protocol = GDK_DRAG_PROTO_OLE2; + ctx->context->source_window = window; + gdk_drawable_ref (window); + + tmp_list = g_list_last (targets); + ctx->context->targets = NULL; + while (tmp_list) + { + ctx->context->targets = g_list_prepend (ctx->context->targets, + tmp_list->data); + tmp_list = tmp_list->prev; + } + + ctx->context->actions = 0; + + 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; - GdkWindowPrivate *drag_window_private = (GdkWindowPrivate *) 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); @@ -748,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 @@ -765,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; } @@ -774,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 @@ -783,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) @@ -823,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) { - GdkWindowPrivate *private = (GdkWindowPrivate *) 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 @@ -849,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 @@ -886,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; }