[gtk+] Work on OLE2-based generic DND
- From: Tor Lillqvist <tml src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gtk+] Work on OLE2-based generic DND
- Date: Wed, 16 Dec 2009 11:11:30 +0000 (UTC)
commit eb21a7df290936223f6a80cef36b52a8c68a1d22
Author: Tor Lillqvist <tml iki fi>
Date: Wed Dec 16 13:04:29 2009 +0200
Work on OLE2-based generic DND
Intermediate commit of work in progress on integrating the old code
for OLE2-based generic drag and drop from Arhaeopteryx Software, from
a long time ago in the GTK+ 1.3 timeframe. Does still not work and is
as before not compiled in unless OLE2_DND is defined in
gdkdnd-win32.c. (Thus, for inter-process DND, still only WM_DROPFILES
style dropping of files on GTK+ apps works.)
Related slight refactoring of other code that shouldn't change how it
works. Add more global variables for run-time constants (once
initialized) representing well-known GdkAtoms and registered Windows
clipboard formats, as they with the generic DND code will be needed in
several source files. Some improved debugging output.
gdk/win32/gdkdnd-win32.c | 1284 ++++++++++++++++++++++++++++------------
gdk/win32/gdkevents-win32.c | 104 +++--
gdk/win32/gdkglobals-win32.c | 14 +-
gdk/win32/gdkinput-win32.c | 2 +-
gdk/win32/gdkmain-win32.c | 47 +-
gdk/win32/gdkprivate-win32.h | 38 ++-
gdk/win32/gdkproperty-win32.c | 5 +
gdk/win32/gdkselection-win32.c | 26 +-
gdk/win32/gdkwindow-win32.c | 2 +-
9 files changed, 1060 insertions(+), 462 deletions(-)
---
diff --git a/gdk/win32/gdkdnd-win32.c b/gdk/win32/gdkdnd-win32.c
index 674643d..861a3d0 100644
--- a/gdk/win32/gdkdnd-win32.c
+++ b/gdk/win32/gdkdnd-win32.c
@@ -22,7 +22,7 @@
* 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/.
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "config.h"
@@ -59,34 +59,7 @@ typedef enum {
GDK_DRAG_STATUS_MOTION_WAIT,
GDK_DRAG_STATUS_ACTION_WAIT,
GDK_DRAG_STATUS_DROP
-} GtkDragStatus;
-
-typedef enum {
- GDK_DRAG_SOURCE,
- GDK_DRAG_TARGET
-} GdkDragKind;
-
-#ifdef OLE2_DND
-
-#define PRINT_GUID(guid) \
- g_print ("guid = %.08lx-%.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 */
+} GdkDragStatus;
/* Structure that holds information about a drag in progress.
* this is used on both source and destination sides.
@@ -96,24 +69,27 @@ struct _GdkDragContextPrivateWin32 {
gboolean being_finalized;
gint ref_count;
IUnknown *iface;
+ DWORD last_key_state;
#endif
- guint16 last_x; /* Coordinates from last event */
- guint16 last_y;
- HWND dest_xid;
+ POINT last_pt; /* Coordinates from last event */
guint drag_status : 4; /* Current status of drag */
guint drop_failed : 1; /* Whether the drop was unsuccessful */
};
#define PRIVATE_DATA(context) ((GdkDragContextPrivateWin32 *) GDK_DRAG_CONTEXT (context)->windowing_data)
+#ifndef OLE2_DND
+
+static GList *contexts;
static GdkDragContext *current_dest_drag = NULL;
+#endif
+
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;
G_DEFINE_TYPE (GdkDragContext, gdk_drag_context, G_TYPE_OBJECT)
@@ -122,19 +98,20 @@ gdk_drag_context_init (GdkDragContext *dragcontext)
{
GdkDragContextPrivateWin32 *private;
- private = G_TYPE_INSTANCE_GET_PRIVATE (dragcontext,
- GDK_TYPE_DRAG_CONTEXT,
+ private = G_TYPE_INSTANCE_GET_PRIVATE (dragcontext,
+ GDK_TYPE_DRAG_CONTEXT,
GdkDragContextPrivateWin32);
-
+
dragcontext->windowing_data = private;
-#ifdef OLE2_DND
+
+#ifndef OLE2_DND
+ contexts = g_list_prepend (contexts, dragcontext);
+#else
private->being_finalized = FALSE;
private->ref_count = 1;
private->iface = NULL;
#endif
- contexts = g_list_prepend (contexts, dragcontext);
-
GDK_NOTE (DND, g_print ("gdk_drag_context_init %p\n", dragcontext));
}
@@ -154,23 +131,23 @@ static void
gdk_drag_context_finalize (GObject *object)
{
GdkDragContext *context = GDK_DRAG_CONTEXT (object);
-
+
GDK_NOTE (DND, g_print ("gdk_drag_context_finalize %p\n", object));
-
+
g_list_free (context->targets);
if (context->source_window)
g_object_unref (context->source_window);
-
+
if (context->dest_window)
g_object_unref (context->dest_window);
-
+
+#ifndef OLE2_DND
contexts = g_list_remove (contexts, context);
if (context == current_dest_drag)
current_dest_drag = NULL;
-
-#ifdef OLE2_DND
+#else
{
GdkDragContextPrivateWin32 *private = PRIVATE_DATA (context);
if (private->iface)
@@ -181,7 +158,7 @@ gdk_drag_context_finalize (GObject *object)
}
}
#endif
-
+
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -209,6 +186,8 @@ gdk_drag_context_unref (GdkDragContext *context)
g_object_unref (context);
}
+#ifndef OLE2_DND
+
static GdkDragContext *
gdk_drag_context_find (gboolean is_source,
GdkWindow *source,
@@ -227,15 +206,35 @@ gdk_drag_context_find (gboolean 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;
}
+#endif
+
#ifdef OLE2_DND
+#define PRINT_GUID(guid) \
+ g_print ("%.08lx-%.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;
+
typedef struct {
IDropTarget idt;
GdkDragContext *context;
@@ -249,6 +248,7 @@ typedef struct {
typedef struct {
IDataObject ido;
int ref_count;
+ GdkDragContext *context;
} data_object;
typedef struct {
@@ -257,8 +257,16 @@ typedef struct {
int ix;
} enum_formats;
+static source_drag_context *pending_src_context = NULL;
+static IDataObject *dnd_data = NULL;
+
static enum_formats *enum_formats_new (void);
+/* map windows -> target drag contexts. The table
+ * owns a ref to both objects.
+ */
+static GHashTable* target_ctx_for_window = NULL;
+
static ULONG STDMETHODCALLTYPE
idroptarget_addref (LPDROPTARGET This)
{
@@ -268,7 +276,7 @@ idroptarget_addref (LPDROPTARGET This)
GDK_NOTE (DND, g_print ("idroptarget_addref %p %d\n", This, ref_count));
g_object_ref (G_OBJECT (ctx->context));
-
+
return ref_count;
}
@@ -277,29 +285,30 @@ idroptarget_queryinterface (LPDROPTARGET This,
REFIID riid,
LPVOID *ppvObject)
{
- GDK_NOTE (DND, g_print ("idroptarget_queryinterface %p\n", This));
+ GDK_NOTE (DND, {
+ g_print ("idroptarget_queryinterface %p ", This);
+ PRINT_GUID (riid);
+ });
*ppvObject = NULL;
- PRINT_GUID (riid);
-
if (IsEqualGUID (riid, &IID_IUnknown))
{
- g_print ("...IUnknown\n");
+ GDK_NOTE (DND, g_print ("...IUnknown S_OK\n"));
idroptarget_addref (This);
*ppvObject = This;
return S_OK;
}
else if (IsEqualGUID (riid, &IID_IDropTarget))
{
- g_print ("...IDropTarget\n");
+ GDK_NOTE (DND, g_print ("...IDropTarget S_OK\n"));
idroptarget_addref (This);
*ppvObject = This;
return S_OK;
}
else
{
- g_print ("...Nope\n");
+ GDK_NOTE (DND, g_print ("...E_NOINTERFACE\n"));
return E_NOINTERFACE;
}
}
@@ -322,26 +331,128 @@ idroptarget_release (LPDROPTARGET This)
return ref_count;
}
-static HRESULT STDMETHODCALLTYPE
+#if 0
+
+static GdkAtom
+cf_to_atom (CLIPFORMAT cf)
+{
+ switch (cf)
+ {
+ case CF_UNICODETEXT:
+ return _utf8_string;
+ case CF_HDROP:
+ return _text_uri_list;
+ case CF_DIB:
+ return _image_bmp;
+ }
+
+ if (cf == _cf_url)
+ return _text_uri_list;
+
+ if (cf == _cf_html_format || cf == _cf_text_html)
+ return _text_html;
+
+ return GDK_NONE;
+}
+
+#endif
+
+static GdkDragAction
+get_suggested_action (DWORD grfKeyState)
+{
+ /* This is the yucky Windows standard: Force link action if both
+ * Control and Alt are down, copy if Control is down alone, move if
+ * Alt is down alone, or use default of move within the app or copy
+ * when origin of the drag is in another app.
+ */
+ if (grfKeyState & MK_CONTROL && grfKeyState & MK_SHIFT)
+ return GDK_ACTION_LINK; /* Link action not supported */
+ else if (grfKeyState & MK_CONTROL)
+ return GDK_ACTION_COPY;
+ else if (grfKeyState & MK_ALT)
+ return GDK_ACTION_MOVE;
+#if 0 /* Default is always copy for now */
+ else if (_dnd_source_state == GDK_WIN32_DND_DRAGGING)
+ return GDK_ACTION_MOVE;
+#endif
+ else
+ return GDK_ACTION_COPY;
+ /* Any way to determine when to add in DROPEFFECT_SCROLL? */
+}
+
+/* Process pending events -- we don't want to service non-GUI events
+ * forever so do one iteration and then do more only if there's a
+ * pending GDK event.
+ */
+static void
+process_pending_events ()
+{
+ g_main_context_iteration (NULL, FALSE);
+ while (_gdk_event_queue_find_first (_gdk_display))
+ g_main_context_iteration (NULL, FALSE);
+}
+
+static DWORD
+drop_effect_for_action (GdkDragAction action)
+{
+ switch (action)
+ {
+ case GDK_ACTION_MOVE:
+ return DROPEFFECT_MOVE;
+ case GDK_ACTION_LINK:
+ return DROPEFFECT_LINK;
+ case GDK_ACTION_COPY:
+ return DROPEFFECT_COPY;
+ default:
+ return DROPEFFECT_NONE;
+ }
+}
+
+static void
+dnd_event_put (GdkEventType type,
+ GdkDragContext *context,
+ const POINTL pt,
+ gboolean to_dest_window)
+{
+ GdkEvent e;
+ e.type = type;
+ if (to_dest_window)
+ e.dnd.window = context->dest_window;
+ else
+ e.dnd.window = context->source_window;
+ e.dnd.send_event = FALSE;
+ e.dnd.context = context;
+ e.dnd.time = GDK_CURRENT_TIME;
+ e.dnd.x_root = pt.x + _gdk_offset_x;
+ e.dnd.y_root = pt.x + _gdk_offset_y;
+
+ gdk_drag_context_ref (e.dnd.context);
+ if (e.dnd.window != NULL)
+ g_object_ref (e.dnd.window);
+
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (&e));
+ gdk_event_put (&e);
+}
+
+static HRESULT STDMETHODCALLTYPE
idroptarget_dragenter (LPDROPTARGET This,
LPDATAOBJECT pDataObj,
DWORD grfKeyState,
POINTL pt,
LPDWORD pdwEffect)
{
- IEnumFORMATETC* iefp;
- FORMATETC formatetc;
+ target_drag_context *ctx = (target_drag_context *) This;
- GDK_NOTE (DND, g_print ("idroptarget_dragenter %p formats:\n", This));
+ GDK_NOTE (DND, g_print ("idroptarget_dragenter %p S_OK\n", This));
- pDataObj->lpVtbl->EnumFormatEtc (pDataObj, DATADIR_GET, &iefp);
- while (iefp->lpVtbl->Next (iefp, 1, &formatetc, NULL) == S_OK)
- {
- GDK_NOTE (DND, g_print (" %s\n", _gdk_win32_cf_to_string (formatetc.cfFormat)));
- }
- iefp->lpVtbl->Release (iefp);
-
- *pdwEffect = DROPEFFECT_COPY;
+ ctx->context->suggested_action = get_suggested_action (grfKeyState);
+ dnd_event_put (GDK_DRAG_ENTER, ctx->context, pt, TRUE);
+ process_pending_events ();
+ *pdwEffect = drop_effect_for_action (ctx->context->action);
+
+ /* Assume that target can accept the data: In fact it may fail but
+ * we are not really set up to query the target!
+ */
return S_OK;
}
@@ -351,16 +462,28 @@ idroptarget_dragover (LPDROPTARGET This,
POINTL pt,
LPDWORD pdwEffect)
{
- GDK_NOTE (DND, g_print ("idroptarget_dragover %p\n", This));
+ target_drag_context *ctx = (target_drag_context *) This;
+
+ GDK_NOTE (DND, g_print ("idroptarget_dragover %p S_OK\n", This));
+
+ ctx->context->suggested_action = get_suggested_action (grfKeyState);
+ dnd_event_put (GDK_DRAG_MOTION, ctx->context, pt, TRUE);
+ process_pending_events ();
+ *pdwEffect = drop_effect_for_action (ctx->context->action);
- *pdwEffect = DROPEFFECT_COPY;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
idroptarget_dragleave (LPDROPTARGET This)
{
- GDK_NOTE (DND, g_print ("idroptarget_dragleave %p\n", This));
+ target_drag_context *ctx = (target_drag_context *) This;
+ POINTL pt = { 0, 0 };
+
+ GDK_NOTE (DND, g_print ("idroptarget_dragleave %p S_OK\n", This));
+
+ dnd_event_put (GDK_DRAG_LEAVE, ctx->context, pt, TRUE);
+ process_pending_events ();
return S_OK;
}
@@ -372,9 +495,32 @@ idroptarget_drop (LPDROPTARGET This,
POINTL pt,
LPDWORD pdwEffect)
{
- GDK_NOTE (DND, g_print ("idroptarget_drop %p\n", This));
+ target_drag_context *ctx = (target_drag_context *) This;
+
+ GDK_NOTE (DND, g_print ("idroptarget_drop %p ", This));
+
+ if (pDataObj == NULL)
+ {
+ GDK_NOTE (DND, g_print ("E_POINTER\n"));
+ return E_POINTER;
+ }
+
+ dnd_data = pDataObj;
+
+ ctx->context->suggested_action = get_suggested_action (grfKeyState);
+ dnd_event_put (GDK_DROP_START, ctx->context, pt, TRUE);
+ process_pending_events ();
+
+ dnd_data = NULL;
+
+ /* Notify OLE of copy or move */
+ if (_dnd_target_state != GDK_WIN32_DND_DROPPED)
+ *pdwEffect = DROPEFFECT_NONE;
+ else
+ *pdwEffect = drop_effect_for_action (ctx->context->action);
+
+ GDK_NOTE (DND, g_print ("S_OK\n"));
- *pdwEffect = DROPEFFECT_COPY;
return S_OK;
}
@@ -387,7 +533,7 @@ idropsource_addref (LPDROPSOURCE This)
GDK_NOTE (DND, g_print ("idropsource_addref %p %d\n", This, ref_count));
g_object_ref (G_OBJECT (ctx->context));
-
+
return ref_count;
}
@@ -396,28 +542,30 @@ idropsource_queryinterface (LPDROPSOURCE This,
REFIID riid,
LPVOID *ppvObject)
{
- GDK_NOTE (DND, g_print ("idropsource_queryinterface %p\n", This));
+ GDK_NOTE (DND, {
+ g_print ("idropsource_queryinterface %p ", This);
+ PRINT_GUID (riid);
+ });
*ppvObject = NULL;
- PRINT_GUID (riid);
if (IsEqualGUID (riid, &IID_IUnknown))
{
- g_print ("...IUnknown\n");
+ GDK_NOTE (DND, g_print ("...IUnknown S_OK\n"));
idropsource_addref (This);
*ppvObject = This;
return S_OK;
}
else if (IsEqualGUID (riid, &IID_IDropSource))
{
- g_print ("...IDropSource\n");
+ GDK_NOTE (DND, g_print ("...IDropSource S_OK\n"));
idropsource_addref (This);
*ppvObject = This;
return S_OK;
}
else
{
- g_print ("...Nope\n");
+ GDK_NOTE (DND, g_print ("...E_NOINTERFACE\n"));
return E_NOINTERFACE;
}
}
@@ -440,23 +588,149 @@ idropsource_release (LPDROPSOURCE This)
return ref_count;
}
+/* Emit GDK events for any changes in mouse events or control key
+ * state since the last recorded state. Return true if any events
+ * have been emitted and false otherwise.
+ */
+static gboolean
+send_change_events (GdkDragContext *ctx,
+ DWORD key_state,
+ gboolean esc_pressed)
+{
+ GdkDragContextPrivateWin32 *private = PRIVATE_DATA (ctx);
+ POINT pt;
+ gboolean changed = FALSE;
+ HWND hwnd = GDK_WINDOW_HWND (ctx->source_window);
+ LPARAM lparam;
+ WPARAM wparam;
+
+ if (!API_CALL (GetCursorPos, (&pt)))
+ return FALSE;
+
+ if (!API_CALL (ScreenToClient, (hwnd, &pt)))
+ return FALSE;
+
+ if (pt.x != private->last_pt.x || pt.y != private->last_pt.y ||
+ key_state != private->last_key_state)
+ {
+ lparam = MAKELPARAM (pt.x, pt.y);
+ wparam = key_state;
+ if (pt.x != private->last_pt.x || pt.y != private->last_pt.y)
+ {
+ GDK_NOTE (DND, g_print ("Sending WM_MOUSEMOVE (%ld,%ld)\n", pt.x, pt.y));
+ SendMessage (hwnd, WM_MOUSEMOVE, wparam, lparam);
+ }
+
+ if ((key_state & MK_LBUTTON) != (private->last_key_state & MK_LBUTTON))
+ {
+ if (key_state & MK_LBUTTON)
+ SendMessage (hwnd, WM_LBUTTONDOWN, wparam, lparam);
+ else
+ SendMessage (hwnd, WM_LBUTTONUP, wparam, lparam);
+ }
+ if ((key_state & MK_MBUTTON) != (private->last_key_state & MK_MBUTTON))
+ {
+ if (key_state & MK_MBUTTON)
+ SendMessage (hwnd, WM_MBUTTONDOWN, wparam, lparam);
+ else
+ SendMessage (hwnd, WM_MBUTTONUP, wparam, lparam);
+ }
+ if ((key_state & MK_RBUTTON) != (private->last_key_state & MK_RBUTTON))
+ {
+ if (key_state & MK_RBUTTON)
+ SendMessage (hwnd, WM_RBUTTONDOWN, wparam, lparam);
+ else
+ SendMessage (hwnd, WM_RBUTTONUP, wparam, lparam);
+ }
+ if ((key_state & MK_CONTROL) != (private->last_key_state & MK_CONTROL))
+ {
+ if (key_state & MK_CONTROL)
+ SendMessage (hwnd, WM_KEYDOWN, VK_CONTROL, 0);
+ else
+ SendMessage (hwnd, WM_KEYUP, VK_CONTROL, 0);
+ }
+ if ((key_state & MK_SHIFT) != (private->last_key_state & MK_SHIFT))
+ {
+ if (key_state & MK_CONTROL)
+ SendMessage (hwnd, WM_KEYDOWN, VK_SHIFT, 0);
+ else
+ SendMessage (hwnd, WM_KEYUP, VK_SHIFT, 0);
+ }
+
+ changed = TRUE;
+ private->last_key_state = key_state;
+ private->last_pt = pt;
+ }
+
+ if (esc_pressed)
+ {
+ GDK_NOTE (DND, g_print ("Sending a escape key down message to %p\n", hwnd));
+ SendMessage (hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
+ changed = TRUE;
+ }
+
+ return changed;
+}
+
static HRESULT STDMETHODCALLTYPE
idropsource_querycontinuedrag (LPDROPSOURCE This,
BOOL fEscapePressed,
DWORD grfKeyState)
{
- GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag %p\n", This));
+ source_drag_context *ctx = (source_drag_context *) This;
- return E_UNEXPECTED;
+ GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag %p ", This));
+
+ if (send_change_events (ctx->context, grfKeyState, fEscapePressed))
+ process_pending_events ();
+
+ if (_dnd_source_state == GDK_WIN32_DND_DROPPED)
+ {
+ GDK_NOTE (DND, g_print ("DRAGDROP_S_DROP\n"));
+ return DRAGDROP_S_DROP;
+ }
+ else if (_dnd_source_state == GDK_WIN32_DND_NONE)
+ {
+ GDK_NOTE (DND, g_print ("DRAGDROP_S_CANCEL\n"));
+ return DRAGDROP_S_CANCEL;
+ }
+ else
+ {
+ GDK_NOTE (DND, g_print ("S_OK\n"));
+ return S_OK;
+ }
}
static HRESULT STDMETHODCALLTYPE
idropsource_givefeedback (LPDROPSOURCE This,
DWORD dwEffect)
{
- GDK_NOTE (DND, g_print ("idropsource_givefeedback %p\n", This));
+ source_drag_context *ctx = (source_drag_context *) This;
+ GdkDragAction suggested_action;
- return E_UNEXPECTED;
+ GDK_NOTE (DND, g_print ("idropsource_givefeedback %p DRAGDROP_S_USEDEFAULTCURSORS\n", This));
+
+ if (dwEffect == DROPEFFECT_MOVE)
+ suggested_action = GDK_ACTION_MOVE;
+ else
+ suggested_action = GDK_ACTION_COPY;
+ ctx->context->action = suggested_action;
+
+ if (dwEffect == DROPEFFECT_NONE)
+ {
+ if (ctx->context->dest_window != NULL)
+ {
+ g_object_unref (ctx->context->dest_window);
+ ctx->context->dest_window = NULL;
+ }
+ }
+ else
+ {
+ if (ctx->context->dest_window == NULL)
+ ctx->context->dest_window = g_object_ref (_gdk_root);
+ }
+
+ return DRAGDROP_S_USEDEFAULTCURSORS;
}
static ULONG STDMETHODCALLTYPE
@@ -475,28 +749,30 @@ idataobject_queryinterface (LPDATAOBJECT This,
REFIID riid,
LPVOID *ppvObject)
{
- GDK_NOTE (DND, g_print ("idataobject_queryinterface %p\n", This));
+ GDK_NOTE (DND, {
+ g_print ("idataobject_queryinterface %p ", This);
+ PRINT_GUID (riid);
+ });
*ppvObject = NULL;
- PRINT_GUID (riid);
if (IsEqualGUID (riid, &IID_IUnknown))
{
- g_print ("...IUnknown\n");
+ GDK_NOTE (DND, g_print ("...IUnknown S_OK\n"));
idataobject_addref (This);
*ppvObject = This;
return S_OK;
}
else if (IsEqualGUID (riid, &IID_IDataObject))
{
- g_print ("...IDataObject\n");
+ GDK_NOTE (DND, g_print ("...IDataObject S_OK\n"));
idataobject_addref (This);
*ppvObject = This;
return S_OK;
}
else
{
- g_print ("...Nope\n");
+ GDK_NOTE (DND, g_print ("...E_NOINTERFACE\n"));
return E_NOINTERFACE;
}
}
@@ -515,14 +791,85 @@ idataobject_release (LPDATAOBJECT This)
return ref_count;
}
+static HRESULT
+query (LPDATAOBJECT This,
+ LPFORMATETC pFormatEtc)
+{
+ int i;
+
+ if (!pFormatEtc)
+ return DV_E_FORMATETC;
+
+ if (pFormatEtc->lindex != -1)
+ return DV_E_LINDEX;
+
+ if ((pFormatEtc->tymed & TYMED_HGLOBAL) == 0)
+ return DV_E_TYMED;
+
+ if ((pFormatEtc->dwAspect & DVASPECT_CONTENT) == 0)
+ return DV_E_DVASPECT;
+
+ for (i = 0; i < nformats; i++)
+ if (pFormatEtc->cfFormat == formats[i].cfFormat)
+ return S_OK;
+
+ return DV_E_FORMATETC;
+}
+
+static FORMATETC *active_pFormatEtc = NULL;
+static STGMEDIUM *active_pMedium = NULL;
+
static HRESULT STDMETHODCALLTYPE
idataobject_getdata (LPDATAOBJECT This,
LPFORMATETC pFormatEtc,
LPSTGMEDIUM pMedium)
{
- GDK_NOTE (DND, g_print ("idataobject_getdata %p\n", This));
+ data_object *ctx = (data_object *) This;
+ GdkAtom target;
+ HRESULT hr;
+ GdkEvent e;
- return E_UNEXPECTED;
+ GDK_NOTE (DND, g_print ("idataobject_getdata %p %s ",
+ This, _gdk_win32_cf_to_string (pFormatEtc->cfFormat)));
+
+ /* Check whether we can provide requested format */
+ hr = query (This, pFormatEtc);
+ if (hr != S_OK)
+ return hr;
+
+ /* Append a GDK_SELECTION_GET event and then hope the app sets the
+ * property associated with the _gdk_ole2_dnd atom
+ */
+
+ active_pFormatEtc = pFormatEtc;
+ active_pMedium = pMedium;
+
+ target = GDK_TARGET_STRING;
+
+ e.type = GDK_SELECTION_REQUEST;
+ e.selection.window = ctx->context->source_window;
+ e.selection.send_event = FALSE; /* ??? */
+ /* FIXME: Should really both selection and property be _gdk_ole2_dnd? */
+ e.selection.selection = _gdk_ole2_dnd;
+ /* FIXME: Target? */
+ e.selection.target = _utf8_string;
+ e.selection.property = _gdk_ole2_dnd;
+ e.selection.time = GDK_CURRENT_TIME;
+
+ g_object_ref (e.selection.window);
+
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (&e));
+ gdk_event_put (&e);
+ process_pending_events ();
+
+ active_pFormatEtc = NULL;
+ active_pMedium = NULL;
+
+ if (pMedium->hGlobal == NULL) {
+ return E_UNEXPECTED;
+ }
+
+ return S_OK;
}
static HRESULT STDMETHODCALLTYPE
@@ -530,7 +877,8 @@ idataobject_getdatahere (LPDATAOBJECT This,
LPFORMATETC pFormatEtc,
LPSTGMEDIUM pMedium)
{
- GDK_NOTE (DND, g_print ("idataobject_getdatahere %p\n", This));
+ GDK_NOTE (DND, g_print ("idataobject_getdatahere %p %s E_UNEXPECTED\n",
+ This, _gdk_win32_cf_to_string (pFormatEtc->cfFormat)));
return E_UNEXPECTED;
}
@@ -539,19 +887,26 @@ static HRESULT STDMETHODCALLTYPE
idataobject_querygetdata (LPDATAOBJECT This,
LPFORMATETC pFormatEtc)
{
- int i;
+ HRESULT hr;
- GDK_NOTE (DND, g_print ("idataobject_querygetdata %p %#x", This, pFormatEtc->cfFormat));
+ hr = query (This, pFormatEtc);
- for (i = 0; i < nformats; i++)
- if (pFormatEtc->cfFormat == formats[i].cfFormat)
- {
- GDK_NOTE (DND, g_print (" S_OK\n"));
- return S_OK;
- }
+#define CASE(x) case x: g_print (#x)
+ GDK_NOTE (DND, {
+ g_print ("idataobject_querygetdata %p %s \n",
+ This, _gdk_win32_cf_to_string (pFormatEtc->cfFormat));
+ switch (hr)
+ {
+ CASE (DV_E_FORMATETC);
+ CASE (DV_E_LINDEX);
+ CASE (DV_E_TYMED);
+ CASE (DV_E_DVASPECT);
+ CASE (S_OK);
+ default: g_print ("%#lx", hr);
+ }
+ });
- GDK_NOTE (DND, g_print (" DV_E_FORMATETC\n"));
- return DV_E_FORMATETC;
+ return hr;
}
static HRESULT STDMETHODCALLTYPE
@@ -559,9 +914,9 @@ idataobject_getcanonicalformatetc (LPDATAOBJECT This,
LPFORMATETC pFormatEtcIn,
LPFORMATETC pFormatEtcOut)
{
- GDK_NOTE (DND, g_print ("idataobject_getcanonicalformatetc %p\n", This));
+ GDK_NOTE (DND, g_print ("idataobject_getcanonicalformatetc %p E_UNEXPECTED\n", This));
- return E_FAIL;
+ return E_UNEXPECTED;
}
static HRESULT STDMETHODCALLTYPE
@@ -570,7 +925,8 @@ idataobject_setdata (LPDATAOBJECT This,
LPSTGMEDIUM pMedium,
BOOL fRelease)
{
- GDK_NOTE (DND, g_print ("idataobject_setdata %p\n", This));
+ GDK_NOTE (DND, g_print ("idataobject_setdata %p %s E_UNEXPECTED\n",
+ This, _gdk_win32_cf_to_string (pFormatEtc->cfFormat)));
return E_UNEXPECTED;
}
@@ -580,12 +936,18 @@ idataobject_enumformatetc (LPDATAOBJECT This,
DWORD dwDirection,
LPENUMFORMATETC *ppEnumFormatEtc)
{
- GDK_NOTE (DND, g_print ("idataobject_enumformatetc %p\n", This));
+ GDK_NOTE (DND, g_print ("idataobject_enumformatetc %p ", This));
if (dwDirection != DATADIR_GET)
- return E_NOTIMPL;
+ {
+ GDK_NOTE (DND, g_print ("E_NOTIMPL\n"));
+ return E_NOTIMPL;
+ }
*ppEnumFormatEtc = &enum_formats_new ()->ief;
+
+ GDK_NOTE (DND, g_print ("%p S_OK\n", *ppEnumFormatEtc));
+
return S_OK;
}
@@ -596,29 +958,29 @@ idataobject_dadvise (LPDATAOBJECT This,
LPADVISESINK pAdvSink,
DWORD *pdwConnection)
{
- GDK_NOTE (DND, g_print ("idataobject_dadvise %p\n", This));
+ GDK_NOTE (DND, g_print ("idataobject_dadvise %p E_NOTIMPL\n", This));
- return E_FAIL;
+ return E_NOTIMPL;
}
static HRESULT STDMETHODCALLTYPE
idataobject_dunadvise (LPDATAOBJECT This,
DWORD dwConnection)
{
- GDK_NOTE (DND, g_print ("idataobject_dunadvise %p\n", This));
+ GDK_NOTE (DND, g_print ("idataobject_dunadvise %p E_NOTIMPL\n", This));
- return E_FAIL;
+ return E_NOTIMPL;
}
static HRESULT STDMETHODCALLTYPE
idataobject_enumdadvise (LPDATAOBJECT This,
LPENUMSTATDATA *ppenumAdvise)
{
- GDK_NOTE (DND, g_print ("idataobject_enumdadvise %p\n", This));
+ GDK_NOTE (DND, g_print ("idataobject_enumdadvise %p OLE_E_ADVISENOTSUPPORTED\n", This));
- return E_FAIL;
+ return OLE_E_ADVISENOTSUPPORTED;
}
-
+
static ULONG STDMETHODCALLTYPE
ienumformatetc_addref (LPENUMFORMATETC This)
{
@@ -635,28 +997,30 @@ ienumformatetc_queryinterface (LPENUMFORMATETC This,
REFIID riid,
LPVOID *ppvObject)
{
- GDK_NOTE (DND, g_print ("ienumformatetc_queryinterface %p\n", This));
+ GDK_NOTE (DND, {
+ g_print ("ienumformatetc_queryinterface %p", This);
+ PRINT_GUID (riid);
+ });
*ppvObject = NULL;
- PRINT_GUID (riid);
if (IsEqualGUID (riid, &IID_IUnknown))
{
- g_print ("...IUnknown\n");
+ GDK_NOTE (DND, g_print ("...IUnknown S_OK\n"));
ienumformatetc_addref (This);
*ppvObject = This;
return S_OK;
}
else if (IsEqualGUID (riid, &IID_IEnumFORMATETC))
{
- g_print ("...IEnumFORMATETC\n");
+ GDK_NOTE (DND, g_print ("...IEnumFORMATETC S_OK\n"));
ienumformatetc_addref (This);
*ppvObject = This;
return S_OK;
}
else
{
- g_print ("...Nope\n");
+ GDK_NOTE (DND, g_print ("...E_NOINTERFACE\n"));
return E_NOINTERFACE;
}
}
@@ -684,7 +1048,7 @@ ienumformatetc_next (LPENUMFORMATETC This,
enum_formats *en = (enum_formats *) This;
int i, n;
- GDK_NOTE (DND, g_print ("ienumformatetc_next %p %d %ld\n", This, en->ix, celt));
+ GDK_NOTE (DND, g_print ("ienumformatetc_next %p %d %ld ", This, en->ix, celt));
n = 0;
for (i = 0; i < celt; i++)
@@ -698,6 +1062,8 @@ ienumformatetc_next (LPENUMFORMATETC This,
if (nelt != NULL)
*nelt = n;
+ GDK_NOTE (DND, g_print ("%s\n", (n == celt) ? "S_OK" : "S_FALSE"));
+
if (n == celt)
return S_OK;
else
@@ -710,7 +1076,8 @@ ienumformatetc_skip (LPENUMFORMATETC This,
{
enum_formats *en = (enum_formats *) This;
- GDK_NOTE (DND, g_print ("ienumformatetc_skip %p %d %ld\n", This, en->ix, celt));
+ GDK_NOTE (DND, g_print ("ienumformatetc_skip %p %d %ld S_OK\n", This, en->ix, celt));
+
en->ix += celt;
return S_OK;
@@ -721,7 +1088,7 @@ ienumformatetc_reset (LPENUMFORMATETC This)
{
enum_formats *en = (enum_formats *) This;
- GDK_NOTE (DND, g_print ("ienumformatetc_reset %p\n", This));
+ GDK_NOTE (DND, g_print ("ienumformatetc_reset %p S_OK\n", This));
en->ix = 0;
@@ -735,7 +1102,7 @@ ienumformatetc_clone (LPENUMFORMATETC This,
enum_formats *en = (enum_formats *) This;
enum_formats *new;
- GDK_NOTE (DND, g_print ("ienumformatetc_clone %p\n", This));
+ GDK_NOTE (DND, g_print ("ienumformatetc_clone %p S_OK\n", This));
new = enum_formats_new ();
@@ -791,7 +1158,7 @@ static IEnumFORMATETCVtbl ief_vtbl = {
static target_drag_context *
-target_context_new (void)
+target_context_new (GdkWindow *window)
{
target_drag_context *result;
GdkDragContextPrivateWin32 *private;
@@ -801,8 +1168,20 @@ target_context_new (void)
result->idt.lpVtbl = &idt_vtbl;
result->context = gdk_drag_context_new ();
+ result->context->protocol = GDK_DRAG_PROTO_OLE2;
result->context->is_source = FALSE;
+ result->context->source_window = NULL;
+
+ result->context->dest_window = window;
+ g_object_ref (window);
+
+ /* FIXME: result->context->targets? */
+
+ result->context->actions = GDK_ACTION_DEFAULT | GDK_ACTION_COPY | GDK_ACTION_MOVE;
+ result->context->suggested_action = GDK_ACTION_MOVE;
+ result->context->action = GDK_ACTION_MOVE;
+
private = result->context->windowing_data;
private->iface = (IUnknown *) &result->idt;
idroptarget_addref (&result->idt);
@@ -813,7 +1192,8 @@ target_context_new (void)
}
static source_drag_context *
-source_context_new (void)
+source_context_new (GdkWindow *window,
+ GList *targets)
{
source_drag_context *result;
GdkDragContextPrivateWin32 *private;
@@ -823,8 +1203,15 @@ source_context_new (void)
result->ids.lpVtbl = &ids_vtbl;
result->context = gdk_drag_context_new ();
+ result->context->protocol = GDK_DRAG_PROTO_OLE2;
result->context->is_source = TRUE;
+ result->context->source_window = window;
+ g_object_ref (window);
+
+ result->context->dest_window = NULL;
+ result->context->targets = g_list_copy (targets);
+
private = result->context->windowing_data;
private->iface = (IUnknown *) &result->ids;
idropsource_addref (&result->ids);
@@ -835,7 +1222,7 @@ source_context_new (void)
}
static data_object *
-data_object_new (void)
+data_object_new (GdkDragContext *context)
{
data_object *result;
@@ -843,13 +1230,13 @@ data_object_new (void)
result->ido.lpVtbl = &ido_vtbl;
result->ref_count = 1;
+ result->context = context;
GDK_NOTE (DND, g_print ("data_object_new: %p\n", result));
return result;
}
-
static enum_formats *
enum_formats_new (void)
{
@@ -861,13 +1248,56 @@ enum_formats_new (void)
result->ref_count = 1;
result->ix = 0;
- GDK_NOTE (DND, g_print ("enum_formats_new: %p\n", result));
-
return result;
}
#endif
+/* Needs to be compiled (even if empty) also in the non-OLE2_DND
+ * case as called from gdk_property_change() in gdkproperty-win32.c
+ * and we want to have the OLE2_DND conditionals just in this
+ * source file.
+ */
+void
+_gdk_win32_ole2_dnd_property_change (GdkAtom type,
+ gint format,
+ const guchar *data,
+ gint nelements)
+{
+#ifdef OLE2_DND
+ HGLOBAL hdata = NULL;
+
+ if (active_pFormatEtc == NULL || active_pMedium == NULL)
+ return;
+
+ /* Set up the data buffer for wide character text request */
+ if (active_pFormatEtc->cfFormat == CF_UNICODETEXT)
+ {
+ gunichar2 *wdata;
+ glong wlen;
+
+ wdata = g_utf8_to_utf16 ((const char *) data, -1, NULL, &wlen, NULL);
+ hdata = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (wlen + 1) * 2);
+ if (hdata)
+ {
+ wchar_t *ptr = (wchar_t *) GlobalLock(hdata);
+ memcpy (ptr, wdata, (wlen + 1) * 2);
+ GlobalUnlock(hdata);
+ }
+ g_free (wdata);
+ }
+ else
+ g_warning ("Only text handled for now");
+
+ /* Pack up data */
+ active_pMedium->tymed = TYMED_HGLOBAL;
+ active_pMedium->hGlobal = hdata;
+ active_pMedium->pUnkForRelease = 0;
+#endif
+}
+
+#ifndef OLE2_DND
+
/* From MS Knowledge Base article Q130698 */
static gboolean
@@ -876,7 +1306,7 @@ resolve_link (HWND hWnd,
gchar **lpszPath)
{
WIN32_FILE_ATTRIBUTE_DATA wfad;
- HRESULT hres;
+ HRESULT hr;
IShellLinkW *pslW = NULL;
IPersistFile *ppf = NULL;
@@ -896,53 +1326,52 @@ resolve_link (HWND hWnd,
* assumed that CoInitialize has been called.
*/
- hres = CoCreateInstance (&CLSID_ShellLink,
- NULL,
- CLSCTX_INPROC_SERVER,
- &IID_IShellLinkW,
- (LPVOID *)&pslW);
+ hr = CoCreateInstance (&CLSID_ShellLink,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ &IID_IShellLinkW,
+ (LPVOID *)&pslW);
- if (SUCCEEDED (hres))
+ if (SUCCEEDED (hr))
{
-
/* The IShellLink interface supports the IPersistFile
* interface. Get an interface pointer to it.
*/
- hres = pslW->lpVtbl->QueryInterface (pslW,
- &IID_IPersistFile,
- (LPVOID *) &ppf);
- }
+ hr = pslW->lpVtbl->QueryInterface (pslW,
+ &IID_IPersistFile,
+ (LPVOID *) &ppf);
+ }
- if (SUCCEEDED (hres))
+ if (SUCCEEDED (hr))
{
/* Load the file. */
- hres = ppf->lpVtbl->Load (ppf, link, STGM_READ);
+ hr = ppf->lpVtbl->Load (ppf, link, STGM_READ);
}
-
- if (SUCCEEDED (hres))
+
+ if (SUCCEEDED (hr))
{
/* Resolve the link by calling the Resolve()
* interface function.
*/
- hres = pslW->lpVtbl->Resolve (pslW, hWnd, SLR_ANY_MATCH | SLR_NO_UI);
+ hr = pslW->lpVtbl->Resolve (pslW, hWnd, SLR_ANY_MATCH | SLR_NO_UI);
}
- if (SUCCEEDED (hres))
+ if (SUCCEEDED (hr))
{
wchar_t wtarget[MAX_PATH];
- hres = pslW->lpVtbl->GetPath (pslW, wtarget, MAX_PATH, NULL, 0);
- if (SUCCEEDED (hres))
+ hr = pslW->lpVtbl->GetPath (pslW, wtarget, MAX_PATH, NULL, 0);
+ if (SUCCEEDED (hr))
*lpszPath = g_utf16_to_utf8 (wtarget, -1, NULL, NULL, NULL);
}
-
+
if (ppf)
ppf->lpVtbl->Release (ppf);
if (pslW)
pslW->lpVtbl->Release (pslW);
- return SUCCEEDED (hres);
+ return SUCCEEDED (hr);
}
#if 0
@@ -990,36 +1419,37 @@ gdk_dropfiles_filter (GdkXEvent *xev,
gpointer data)
{
GdkDragContext *context;
- GdkDragContextPrivateWin32 *private;
GString *result;
MSG *msg = (MSG *) xev;
HANDLE hdrop;
POINT pt;
gint nfiles, i;
gchar *fileName, *linkedFile;
-
+
if (msg->message == WM_DROPFILES)
{
GDK_NOTE (DND, g_print ("WM_DROPFILES: %p\n", msg->hwnd));
context = gdk_drag_context_new ();
- private = PRIVATE_DATA (context);
context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
context->is_source = FALSE;
+
context->source_window = _gdk_root;
g_object_ref (context->source_window);
+
context->dest_window = event->any.window;
g_object_ref (context->dest_window);
+
/* WM_DROPFILES drops are always file names */
context->targets =
- g_list_append (NULL, GUINT_TO_POINTER (_text_uri_list));
+ g_list_append (NULL, _text_uri_list);
context->actions = GDK_ACTION_COPY;
context->suggested_action = GDK_ACTION_COPY;
current_dest_drag = context;
event->dnd.type = GDK_DROP_START;
event->dnd.context = current_dest_drag;
-
+
hdrop = (HANDLE) msg->wParam;
DragQueryPoint (hdrop, &pt);
ClientToScreen (msg->hwnd, &pt);
@@ -1102,43 +1532,71 @@ gdk_dropfiles_filter (GdkXEvent *xev,
g_string_free (result, FALSE);
DragFinish (hdrop);
-
+
return GDK_FILTER_TRANSLATE;
}
else
return GDK_FILTER_CONTINUE;
}
-/*************************************************************
- ************************** Public API ***********************
- *************************************************************/
+#endif /* !OLE2_DND */
+
+#ifdef OLE2_DND
+
+static void
+add_format (GArray *fmts,
+ CLIPFORMAT cf)
+{
+ FORMATETC fmt;
+
+ fmt.cfFormat = cf;
+ fmt.ptd = NULL;
+ fmt.dwAspect = DVASPECT_CONTENT;
+ fmt.lindex = -1;
+ fmt.tymed = TYMED_HGLOBAL;
+
+ g_array_append_val (fmts, fmt);
+}
+
+#endif
void
_gdk_dnd_init (void)
{
#ifdef OLE2_DND
- HRESULT hres;
- hres = OleInitialize (NULL);
+ HRESULT hr;
+ GArray *fmts;
+
+ hr = OleInitialize (NULL);
- if (! SUCCEEDED (hres))
+ if (! SUCCEEDED (hr))
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;
+ fmts = g_array_new (FALSE, FALSE, sizeof (FORMATETC));
+
+ /* The most important presumably */
+ add_format (fmts, CF_UNICODETEXT);
+
+ /* Used for GTK+ internal DND, I think was the intent? Anyway, code below assumes
+ * this is at index 1.
+ */
+ add_format (fmts, CF_GDIOBJFIRST);
+
+ add_format (fmts, CF_HDROP);
+
+ add_format (fmts, _cf_png);
+ add_format (fmts, CF_DIB);
+
+ add_format (fmts, _cf_url);
+ add_format (fmts, _cf_html_format);
+ add_format (fmts, _cf_text_html);
+
+ nformats = fmts->len;
+ formats = (FORMATETC*) g_array_free (fmts, FALSE);
+
+ target_ctx_for_window = g_hash_table_new (g_direct_hash, g_direct_equal);
#endif
-}
+}
void
_gdk_win32_dnd_exit (void)
@@ -1150,12 +1608,14 @@ _gdk_win32_dnd_exit (void)
/* Source side */
+#ifndef OLE2_DND
+
static void
local_send_leave (GdkDragContext *context,
guint32 time)
{
GdkEvent tmp_event;
-
+
GDK_NOTE (DND, g_print ("local_send_leave: context=%p current_dest_drag=%p\n",
context,
current_dest_drag));
@@ -1172,7 +1632,8 @@ local_send_leave (GdkDragContext *context,
tmp_event.dnd.time = GDK_CURRENT_TIME; /* FIXME? */
current_dest_drag = NULL;
-
+
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
gdk_event_put (&tmp_event);
}
}
@@ -1190,7 +1651,7 @@ local_send_enter (GdkDragContext *context,
current_dest_drag));
private = PRIVATE_DATA (context);
-
+
if (current_dest_drag != NULL)
{
g_object_unref (G_OBJECT (current_dest_drag));
@@ -1203,6 +1664,7 @@ local_send_enter (GdkDragContext *context,
new_context->source_window = context->source_window;
g_object_ref (new_context->source_window);
+
new_context->dest_window = context->dest_window;
g_object_ref (new_context->dest_window);
@@ -1213,35 +1675,36 @@ local_send_enter (GdkDragContext *context,
GDK_PROPERTY_CHANGE_MASK);
new_context->actions = context->actions;
- tmp_event.dnd.type = GDK_DRAG_ENTER;
+ tmp_event.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_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
gdk_event_put (&tmp_event);
}
static void
local_send_motion (GdkDragContext *context,
- gint x_root,
+ gint x_root,
gint y_root,
GdkDragAction action,
guint32 time)
{
GdkEvent tmp_event;
-
- GDK_NOTE (DND, g_print ("local_send_motion: context=%p current_dest_drag=%p\n",
- context,
+
+ GDK_NOTE (DND, g_print ("local_send_motion: context=%p (%d,%d) current_dest_drag=%p\n",
+ context, x_root, y_root,
current_dest_drag));
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.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;
@@ -1252,11 +1715,12 @@ local_send_motion (GdkDragContext *context,
tmp_event.dnd.x_root = x_root;
tmp_event.dnd.y_root = y_root;
- PRIVATE_DATA (current_dest_drag)->last_x = x_root;
- PRIVATE_DATA (current_dest_drag)->last_y = y_root;
+ PRIVATE_DATA (current_dest_drag)->last_pt.x = x_root - _gdk_offset_x;
+ PRIVATE_DATA (current_dest_drag)->last_pt.y = y_root - _gdk_offset_y;
PRIVATE_DATA (context)->drag_status = GDK_DRAG_STATUS_MOTION_WAIT;
-
+
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
gdk_event_put (&tmp_event);
}
}
@@ -1279,22 +1743,25 @@ local_send_drop (GdkDragContext *context,
private = PRIVATE_DATA (current_dest_drag);
/* Pass ownership of context to the event */
- tmp_event.dnd.type = GDK_DROP_START;
+ tmp_event.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;
-
+
+ tmp_event.dnd.x_root = private->last_pt.x + _gdk_offset_x;
+ tmp_event.dnd.y_root = private->last_pt.y + _gdk_offset_y;
+
current_dest_drag = NULL;
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
gdk_event_put (&tmp_event);
}
}
+#endif
+
static void
gdk_drag_do_leave (GdkDragContext *context,
guint32 time)
@@ -1303,47 +1770,94 @@ gdk_drag_do_leave (GdkDragContext *context,
{
GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n"));
- switch (context->protocol)
- {
- case GDK_DRAG_PROTO_LOCAL:
- local_send_leave (context, time);
- break;
- default:
- break;
- }
+#ifndef OLE2_DND
+ if (context->protocol == GDK_DRAG_PROTO_LOCAL)
+ local_send_leave (context, time);
+#endif
g_object_unref (context->dest_window);
context->dest_window = NULL;
}
}
-GdkDragContext *
+GdkDragContext *
gdk_drag_begin (GdkWindow *window,
GList *targets)
{
-#ifdef OLE2_DND
+#ifndef OLE2_DND
+ 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;
+ g_object_ref (window);
+
+ new_context->targets = g_list_copy (targets);
+ new_context->actions = 0;
+
+ return new_context;
+#else
source_drag_context *ctx;
+
+ g_return_val_if_fail (window != NULL, NULL);
+
+ GDK_NOTE (DND, g_print ("gdk_drag_begin\n"));
+
+ ctx = source_context_new (window, targets);
+
+ _dnd_source_state = GDK_WIN32_DND_PENDING;
+
+ pending_src_context = ctx;
+ gdk_drag_context_ref (ctx->context);
+
+ return ctx->context;
+#endif
+}
+
+void
+_gdk_win32_dnd_do_dragdrop (void)
+{
+#ifdef OLE2_DND
+ GdkDragContext* drag_ctx;
+ GdkDragContextPrivateWin32 *private;
+ BYTE kbd_state[256];
data_object *dobj;
- HRESULT hResult;
+ HRESULT hr;
DWORD dwEffect;
+#if 0
HGLOBAL global;
STGMEDIUM medium;
+#endif
- g_return_val_if_fail (window != NULL, NULL);
-
- GDK_NOTE (DND, g_print ("gdk_drag_begin\n"));
+ if (pending_src_context == NULL)
+ return;
- ctx = source_context_new ();
- ctx->context->protocol = GDK_DRAG_PROTO_OLE2;
- ctx->context->source_window = window;
- g_object_ref (window);
+ drag_ctx = pending_src_context->context;
+ private = PRIVATE_DATA (drag_ctx);
- ctx->context->targets = g_list_copy (targets);
+ dobj = data_object_new (drag_ctx);
- ctx->context->actions = 0;
+ API_CALL (GetCursorPos, (&private->last_pt));
+ API_CALL (ScreenToClient, (GDK_WINDOW_HWND (drag_ctx->source_window), &private->last_pt));
+ private->last_key_state = 0;
+ API_CALL (GetKeyboardState, (kbd_state));
- dobj = data_object_new ();
+ if (kbd_state[VK_CONTROL])
+ private->last_key_state |= MK_CONTROL;
+ if (kbd_state[VK_SHIFT])
+ private->last_key_state |= MK_SHIFT;
+ if (kbd_state[VK_LBUTTON])
+ private->last_key_state |= MK_LBUTTON;
+ if (kbd_state[VK_MBUTTON])
+ private->last_key_state |= MK_MBUTTON;
+ if (kbd_state[VK_RBUTTON])
+ private->last_key_state |= MK_RBUTTON;
+#if 0
global = GlobalAlloc (GMEM_FIXED, sizeof (ctx));
memcpy (&global, ctx, sizeof (ctx));
@@ -1352,35 +1866,62 @@ gdk_drag_begin (GdkWindow *window,
medium.hGlobal = global;
medium.pUnkForRelease = NULL;
+ /* FIXME I wish I remember what I was thinking of here, i.e. what
+ * the formats[1] signifies, i.e. the CF_GDIOBJFIRST FORMATETC?
+ */
dobj->ido.lpVtbl->SetData (&dobj->ido, &formats[1], &medium, TRUE);
+#endif
- hResult = DoDragDrop (&dobj->ido, &ctx->ids, DROPEFFECT_MOVE|DROPEFFECT_COPY, &dwEffect);
+ /* Start dragging with mainloop inside the OLE2 API. Exits only when done */
- 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 ("%#.8lx", hResult))))));
+ GDK_NOTE (DND, g_print ("Calling DoDragDrop\n"));
- dobj->ido.lpVtbl->Release (&dobj->ido);
- ctx->ids.lpVtbl->Release (&ctx->ids);
+ _gdk_win32_begin_modal_call ();
+ hr = DoDragDrop (&dobj->ido, &pending_src_context->ids,
+ DROPEFFECT_COPY | DROPEFFECT_MOVE,
+ &dwEffect);
+ _gdk_win32_end_modal_call ();
- return ctx->context;
-#else
- 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;
- g_object_ref (window);
+ GDK_NOTE (DND, g_print ("DoDragDrop returned %s\n",
+ (hr == DRAGDROP_S_DROP ? "DRAGDROP_S_DROP" :
+ (hr == DRAGDROP_S_CANCEL ? "DRAGDROP_S_CANCEL" :
+ (hr == E_UNEXPECTED ? "E_UNEXPECTED" :
+ g_strdup_printf ("%#.8lx", hr))))));
- new_context->targets = g_list_copy (targets);
+ /* Delete dnd selection after successful move */
+ if (hr == DRAGDROP_S_DROP && dwEffect == DROPEFFECT_MOVE)
+ {
+ GdkEvent tmp_event;
+
+ tmp_event.type = GDK_SELECTION_REQUEST;
+ tmp_event.selection.window = drag_ctx->source_window;
+ tmp_event.selection.send_event = FALSE;
+ tmp_event.selection.selection = _gdk_ole2_dnd;
+ tmp_event.selection.target = _delete;
+ tmp_event.selection.property = _gdk_ole2_dnd; /* ??? */
+ tmp_event.selection.time = GDK_CURRENT_TIME; /* ??? */
+ g_object_ref (tmp_event.selection.window);
+
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
+ gdk_event_put (&tmp_event);
+ }
- new_context->actions = 0;
+#if 0
+ // Send a GDK_DROP_FINISHED to the source window
+ GetCursorPos (&pt);
+ ptl.x = pt.x;
+ ptl.y = pt.y;
+ if ( pending_src_context != NULL && pending_src_context->context != NULL
+ && pending_src_context->context->source_window != NULL )
+ push_dnd_event (GDK_DROP_FINISHED, pending_src_context->context, ptl, FALSE);
+#endif
- return new_context;
+ dobj->ido.lpVtbl->Release (&dobj->ido);
+ if (pending_src_context != NULL)
+ {
+ pending_src_context->ids.lpVtbl->Release (&pending_src_context->ids);
+ pending_src_context = NULL;
+ }
#endif
}
@@ -1409,43 +1950,6 @@ gdk_drag_get_protocol_for_display (GdkDisplay *display,
return 0;
}
-typedef struct {
- gint x;
- gint y;
- HWND ignore;
- HWND result;
-} find_window_enum_arg;
-
-static BOOL CALLBACK
-find_window_enum_proc (HWND hwnd,
- LPARAM lparam)
-{
- RECT rect;
- POINT tl, br;
- find_window_enum_arg *a = (find_window_enum_arg *) lparam;
-
- if (hwnd == a->ignore)
- return TRUE;
-
- if (!IsWindowVisible (hwnd))
- return TRUE;
-
- tl.x = tl.y = 0;
- ClientToScreen (hwnd, &tl);
- GetClientRect (hwnd, &rect);
- br.x = rect.right;
- br.y = rect.bottom;
- ClientToScreen (hwnd, &br);
-
- if (a->x >= tl.x && a->y >= tl.y && a->x < br.x && a->y < br.y)
- {
- a->result = hwnd;
- return FALSE;
- }
- else
- return TRUE;
-}
-
void
gdk_drag_find_window_for_screen (GdkDragContext *context,
GdkWindow *drag_window,
@@ -1455,50 +1959,48 @@ gdk_drag_find_window_for_screen (GdkDragContext *context,
GdkWindow **dest_window,
GdkDragProtocol *protocol)
{
- find_window_enum_arg a;
+ POINT pt;
+ HWND hwnd;
- a.x = x_root - _gdk_offset_x;
- a.y = y_root - _gdk_offset_y;
- a.ignore = drag_window ? GDK_WINDOW_HWND (drag_window) : NULL;
- a.result = NULL;
+ pt.x = x_root - _gdk_offset_x;
+ pt.y = y_root - _gdk_offset_y;
- EnumWindows (find_window_enum_proc, (LPARAM) &a);
+ hwnd = WindowFromPoint (pt);
- if (a.result == NULL)
+ if (hwnd == NULL)
*dest_window = NULL;
else
{
- *dest_window = gdk_win32_handle_table_lookup (a.result);
+ *dest_window = gdk_win32_handle_table_lookup (hwnd);
if (*dest_window)
- {
- *dest_window = gdk_window_get_toplevel (*dest_window);
- g_object_ref (*dest_window);
- }
+ g_object_ref (*dest_window);
+ else
+ *dest_window = gdk_window_foreign_new_for_display (_gdk_display, hwnd);
- if (context->source_window)
#ifdef OLE2_DND
- *protocol = GDK_DRAG_PROTO_OLE2;
+ *protocol = GDK_DRAG_PROTO_OLE2;
#else
+ if (context->source_window)
*protocol = GDK_DRAG_PROTO_LOCAL;
-#endif
else
- *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
+ *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
+#endif
}
GDK_NOTE (DND,
- g_print ("gdk_drag_find_window: %p %+d%+d: %p: %p %d\n",
+ g_print ("gdk_drag_find_window: %p %+d%+d: %p: %p %s\n",
(drag_window ? GDK_WINDOW_HWND (drag_window) : NULL),
x_root, y_root,
- a.result,
+ hwnd,
(*dest_window ? GDK_WINDOW_HWND (*dest_window) : NULL),
- *protocol));
+ _gdk_win32_drag_protocol_to_string (*protocol)));
}
gboolean
gdk_drag_motion (GdkDragContext *context,
GdkWindow *dest_window,
GdkDragProtocol protocol,
- gint x_root,
+ gint x_root,
gint y_root,
GdkDragAction suggested_action,
GdkDragAction possible_actions,
@@ -1509,10 +2011,9 @@ gdk_drag_motion (GdkDragContext *context,
g_return_val_if_fail (context != NULL, FALSE);
context->actions = possible_actions;
-
- GDK_NOTE (DND, g_print ("gdk_drag_motion: protocol=%s\n"
- " suggested_action=%s, possible_actions=%s\n"
- " context=%p:actions=%s, suggested_action=%s, action=%s\n",
+
+ GDK_NOTE (DND, g_print ("gdk_drag_motion: %s suggested=%s, possible=%s\n"
+ " context=%p:{actions=%s,suggested=%s,action=%s}\n",
_gdk_win32_drag_protocol_to_string (protocol),
_gdk_win32_drag_action_to_string (suggested_action),
_gdk_win32_drag_action_to_string (possible_actions),
@@ -1521,13 +2022,13 @@ gdk_drag_motion (GdkDragContext *context,
_gdk_win32_drag_action_to_string (context->suggested_action),
_gdk_win32_drag_action_to_string (context->action)));
-
private = PRIVATE_DATA (context);
-
+
+#ifndef OLE2_DND
if (context->dest_window == dest_window)
{
GdkDragContext *dest_context;
-
+
dest_context = gdk_drag_context_find (FALSE,
context->source_window,
dest_window);
@@ -1539,7 +2040,7 @@ gdk_drag_motion (GdkDragContext *context,
}
else
{
- GdkEvent temp_event;
+ GdkEvent tmp_event;
/* Send a leave to the last destination */
gdk_drag_do_leave (context, time);
@@ -1570,27 +2071,27 @@ gdk_drag_motion (GdkDragContext *context,
}
/* Push a status event, to let the client know that
- * the drag changed
+ * the drag changed
*/
-
- temp_event.dnd.type = GDK_DRAG_STATUS;
- temp_event.dnd.window = context->source_window;
+ tmp_event.type = GDK_DRAG_STATUS;
+ tmp_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;
+ tmp_event.dnd.send_event = TRUE;
- temp_event.dnd.context = context;
- temp_event.dnd.time = time;
+ tmp_event.dnd.context = context;
+ tmp_event.dnd.time = time;
- gdk_event_put (&temp_event);
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
+ gdk_event_put (&tmp_event);
}
/* Send a drag-motion event */
- private->last_x = x_root;
- private->last_y = y_root;
-
+ private->last_pt.x = x_root - _gdk_offset_x;
+ private->last_pt.y = y_root - _gdk_offset_y;
+
if (context->dest_window)
{
if (private->drag_status == GDK_DRAG_STATUS_DRAG)
@@ -1600,7 +2101,7 @@ gdk_drag_motion (GdkDragContext *context,
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;
@@ -1612,7 +2113,7 @@ gdk_drag_motion (GdkDragContext *context,
else
{
GDK_NOTE (DND, g_print (" returning TRUE\n"
- " context=%p:actions=%s, suggested_action=%s, action=%s\n",
+ " context=%p:{actions=%s,suggested=%s,action=%s}\n",
context,
_gdk_win32_drag_action_to_string (context->actions),
_gdk_win32_drag_action_to_string (context->suggested_action),
@@ -1621,8 +2122,10 @@ gdk_drag_motion (GdkDragContext *context,
}
}
+#endif
+
GDK_NOTE (DND, g_print (" returning FALSE\n"
- " context=%p:actions=%s, suggested_action=%s, action=%s\n",
+ " context=%p:{actions=%s,suggested=%s,action=%s}\n",
context,
_gdk_win32_drag_action_to_string (context->actions),
_gdk_win32_drag_action_to_string (context->suggested_action),
@@ -1638,22 +2141,13 @@ gdk_drag_drop (GdkDragContext *context,
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;
- }
- }
+#ifndef OLE2_DND
+ if (context->dest_window &&
+ context->protocol == GDK_DRAG_PROTO_LOCAL)
+ local_send_drop (context, time);
+#else
+ _dnd_source_state = GDK_WIN32_DND_DROPPED;
+#endif
}
void
@@ -1664,7 +2158,9 @@ gdk_drag_abort (GdkDragContext *context,
GDK_NOTE (DND, g_print ("gdk_drag_abort\n"));
- gdk_drag_do_leave (context, time);
+#ifdef OLE2_DND
+ _dnd_source_state = GDK_WIN32_DND_NONE;
+#endif
}
/* Destination side */
@@ -1675,25 +2171,27 @@ gdk_drag_status (GdkDragContext *context,
guint32 time)
{
GdkDragContextPrivateWin32 *private;
+#ifndef OLE2_DND
GdkDragContext *src_context;
GdkEvent tmp_event;
+#endif
g_return_if_fail (context != NULL);
- GDK_NOTE (DND, g_print ("gdk_drag_status\n"));
-
private = PRIVATE_DATA (context);
- GDK_NOTE (DND, g_print ("gdk_drag_status: action=%s\n"
- " context=%p:actions=%s, suggested_action=%s, action=%s\n",
+ GDK_NOTE (DND, g_print ("gdk_drag_status: %s\n"
+ " context=%p:{actions=%s,suggested=%s,action=%s}\n",
_gdk_win32_drag_action_to_string (action),
context,
_gdk_win32_drag_action_to_string (context->actions),
_gdk_win32_drag_action_to_string (context->suggested_action),
_gdk_win32_drag_action_to_string (context->action)));
-
+
context->action = action;
+#ifndef OLE2_DND
+
src_context = gdk_drag_context_find (TRUE,
context->source_window,
context->dest_window);
@@ -1701,11 +2199,11 @@ gdk_drag_status (GdkDragContext *context,
if (src_context)
{
GdkDragContextPrivateWin32 *private = 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.type = GDK_DRAG_STATUS;
tmp_event.dnd.window = context->source_window;
tmp_event.dnd.send_event = FALSE;
tmp_event.dnd.context = src_context;
@@ -1713,14 +2211,16 @@ gdk_drag_status (GdkDragContext *context,
if (action == GDK_ACTION_DEFAULT)
action = 0;
-
+
src_context->action = action;
-
+
+ GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
gdk_event_put (&tmp_event);
}
+#endif
}
-void
+void
gdk_drop_reply (GdkDragContext *context,
gboolean ok,
guint32 time)
@@ -1729,18 +2229,14 @@ gdk_drop_reply (GdkDragContext *context,
GDK_NOTE (DND, g_print ("gdk_drop_reply\n"));
+#ifndef OLE2_DND
+
if (context->dest_window)
{
- switch (context->protocol)
- {
- case GDK_DRAG_PROTO_WIN32_DROPFILES:
- _gdk_dropfiles_store (NULL);
- break;
-
- default:
- break;
- }
+ if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES)
+ _gdk_dropfiles_store (NULL);
}
+#endif
}
void
@@ -1749,31 +2245,45 @@ gdk_drop_finish (GdkDragContext *context,
guint32 time)
{
GdkDragContextPrivateWin32 *private;
+#ifndef OLE2_DND
GdkDragContext *src_context;
GdkEvent tmp_event;
-
+#endif
+
g_return_if_fail (context != NULL);
GDK_NOTE (DND, g_print ("gdk_drop_finish\n"));
private = PRIVATE_DATA (context);
+#ifndef OLE2_DND
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.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_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event));
gdk_event_put (&tmp_event);
}
+#else
+ gdk_drag_do_leave (context, time);
+
+ if (success)
+ _dnd_target_state = GDK_WIN32_DND_DROPPED;
+ else
+ _dnd_target_state = GDK_WIN32_DND_FAILED;
+#endif
}
#ifdef OLE2_DND
+#if 0
+
static GdkFilterReturn
gdk_destroy_filter (GdkXEvent *xev,
GdkEvent *event,
@@ -1794,6 +2304,9 @@ gdk_destroy_filter (GdkXEvent *xev,
}
return GDK_FILTER_CONTINUE;
}
+
+#endif
+
#endif
void
@@ -1801,7 +2314,7 @@ gdk_window_register_dnd (GdkWindow *window)
{
#ifdef OLE2_DND
target_drag_context *ctx;
- HRESULT hres;
+ HRESULT hr;
#endif
g_return_if_fail (window != NULL);
@@ -1813,6 +2326,7 @@ gdk_window_register_dnd (GdkWindow *window)
GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %p\n", GDK_WINDOW_HWND (window)));
+#ifndef OLE2_DND
/* 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
* whether the window (widget) in question actually accepts files
@@ -1820,57 +2334,57 @@ gdk_window_register_dnd (GdkWindow *window)
*/
gdk_window_add_filter (window, gdk_dropfiles_filter, NULL);
DragAcceptFiles (GDK_WINDOW_HWND (window), TRUE);
+#else
+ /* Return if window is already setup for DND. */
+ if (g_hash_table_lookup (target_ctx_for_window, GDK_WINDOW_HWND (window)) != NULL)
+ return;
-#ifdef OLE2_DND
- /* Register for OLE2 d&d */
- ctx = target_context_new ();
- ctx->context->protocol = GDK_DRAG_PROTO_OLE2;
- hres = CoLockObjectExternal ((IUnknown *) &ctx->idt, TRUE, FALSE);
- if (!SUCCEEDED (hres))
+ /* Register for OLE2 d&d : similarly, claim to accept all supported
+ * data types because we cannot know from here what the window
+ * actually accepts.
+ */
+ /* FIXME: This of course won't work with user-extensible data types! */
+ ctx = target_context_new (window);
+
+ hr = CoLockObjectExternal ((IUnknown *) &ctx->idt, TRUE, FALSE);
+ if (!SUCCEEDED (hr))
OTHER_API_FAILED ("CoLockObjectExternal");
else
{
- hres = RegisterDragDrop (GDK_WINDOW_HWND (window), &ctx->idt);
- if (hres == DRAGDROP_E_ALREADYREGISTERED)
+ hr = RegisterDragDrop (GDK_WINDOW_HWND (window), &ctx->idt);
+ if (hr == DRAGDROP_E_ALREADYREGISTERED)
{
g_print ("DRAGDROP_E_ALREADYREGISTERED\n");
-#if 0
- ctx->idt.lpVtbl->Release (&ctx->idt);
-#endif
CoLockObjectExternal ((IUnknown *) &ctx->idt, FALSE, FALSE);
}
- else if (!SUCCEEDED (hres))
+ else if (!SUCCEEDED (hr))
OTHER_API_FAILED ("RegisterDragDrop");
else
{
- gdk_window_add_filter (window, gdk_destroy_filter, &ctx->idt);
+ gdk_window_ref (window);
+ g_hash_table_insert (target_ctx_for_window, GDK_WINDOW_HWND (window), ctx);
}
}
#endif
}
-/*************************************************************
- * gdk_drag_get_selection:
- * Returns the selection atom for the current source window
- * arguments:
- *
- * results:
- *************************************************************/
-
GdkAtom
gdk_drag_get_selection (GdkDragContext *context)
{
- 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;
- else
- return GDK_NONE;
+ switch (context->protocol)
+ {
+ case GDK_DRAG_PROTO_LOCAL:
+ return _local_dnd;
+ case GDK_DRAG_PROTO_WIN32_DROPFILES:
+ return _gdk_win32_dropfiles;
+ case GDK_DRAG_PROTO_OLE2:
+ return _gdk_ole2_dnd;
+ default:
+ return GDK_NONE;
+ }
}
-gboolean
+gboolean
gdk_drag_drop_succeeded (GdkDragContext *context)
{
GdkDragContextPrivateWin32 *private;
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 4d9c0e4..3773e4d 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -825,7 +825,7 @@ _gdk_win32_print_event (const GdkEvent *event)
default: g_assert_not_reached ();
}
- g_print (" %p ", GDK_WINDOW_HWND (event->any.window));
+ g_print (" %p ", event->any.window ? GDK_WINDOW_HWND (event->any.window) : NULL);
switch (event->any.type)
{
@@ -889,9 +889,14 @@ _gdk_win32_print_event (const GdkEvent *event)
case GDK_FOCUS_CHANGE:
g_print ("%s", (event->focus_change.in ? "IN" : "OUT"));
break;
+ case GDK_CONFIGURE:
+ g_print ("x:%d y:%d w:%d h:%d",
+ event->configure.x, event->configure.y,
+ event->configure.width, event->configure.height);
+ break;
+ case GDK_SELECTION_CLEAR:
case GDK_SELECTION_REQUEST:
case GDK_SELECTION_NOTIFY:
- case GDK_SELECTION_CLEAR:
selection_name = gdk_atom_name (event->selection.selection);
target_name = gdk_atom_name (event->selection.target);
property_name = gdk_atom_name (event->selection.property);
@@ -901,10 +906,19 @@ _gdk_win32_print_event (const GdkEvent *event)
g_free (target_name);
g_free (property_name);
break;
- case GDK_CONFIGURE:
- g_print ("x:%d y:%d w:%d h:%d",
- event->configure.x, event->configure.y,
- event->configure.width, event->configure.height);
+ case GDK_DRAG_ENTER:
+ case GDK_DRAG_LEAVE:
+ case GDK_DRAG_MOTION:
+ case GDK_DRAG_STATUS:
+ case GDK_DROP_START:
+ case GDK_DROP_FINISHED:
+ if (event->dnd.context != NULL)
+ g_print ("ctx:%p: %s %s src:%p dest:%p",
+ event->dnd.context,
+ _gdk_win32_drag_protocol_to_string (event->dnd.context->protocol),
+ event->dnd.context->is_source ? "SOURCE" : "DEST",
+ event->dnd.context->source_window == NULL ? NULL : GDK_WINDOW_HWND (event->dnd.context->source_window),
+ event->dnd.context->dest_window == NULL ? NULL : GDK_WINDOW_HWND (event->dnd.context->dest_window));
break;
case GDK_CLIENT_EVENT:
g_print ("%s %d %ld %ld %ld %ld %ld",
@@ -1628,22 +1642,44 @@ handle_wm_paint (MSG *msg,
DeleteObject (hrgn);
}
-static void
-handle_stuff_while_moving_or_resizing (void)
+static VOID CALLBACK
+modal_timer_proc (HWND hwnd,
+ UINT msg,
+ UINT_PTR id,
+ DWORD time)
{
int arbitrary_limit = 1;
- while (g_main_context_pending (NULL) && arbitrary_limit--)
+
+ while (_modal_operation_in_progress &&
+ g_main_context_pending (NULL) &&
+ arbitrary_limit--)
g_main_context_iteration (NULL, FALSE);
}
-static VOID CALLBACK
-modal_timer_proc (HWND hwnd,
- UINT msg,
- UINT_PTR id,
- DWORD time)
+void
+_gdk_win32_begin_modal_call (void)
{
- if (_sizemove_in_progress)
- handle_stuff_while_moving_or_resizing ();
+ g_assert (!_modal_operation_in_progress);
+
+ _modal_operation_in_progress = TRUE;
+
+ modal_timer = SetTimer (NULL, 0, 10, modal_timer_proc);
+ if (modal_timer == 0)
+ WIN32_API_FAILED ("SetTimer");
+}
+
+void
+_gdk_win32_end_modal_call (void)
+{
+ g_assert (_modal_operation_in_progress);
+
+ _modal_operation_in_progress = FALSE;
+
+ if (modal_timer != 0)
+ {
+ API_CALL (KillTimer, (NULL, modal_timer));
+ modal_timer = 0;
+ }
}
static VOID CALLBACK
@@ -2702,23 +2738,13 @@ gdk_event_translate (MSG *msg,
break;
case WM_ENTERSIZEMOVE:
- _sizemove_in_progress = TRUE;
- modal_timer = SetTimer (NULL, 0, 20, modal_timer_proc);
- break;
-
- case WM_EXITSIZEMOVE:
- _sizemove_in_progress = FALSE;
- KillTimer (NULL, modal_timer);
- break;
-
case WM_ENTERMENULOOP:
- _sizemove_in_progress = TRUE;
- modal_timer = SetTimer (NULL, 0, 20, modal_timer_proc);
+ _gdk_win32_begin_modal_call ();
break;
+ case WM_EXITSIZEMOVE:
case WM_EXITMENULOOP:
- _sizemove_in_progress = FALSE;
- KillTimer (NULL, modal_timer);
+ _gdk_win32_end_modal_call ();
break;
case WM_WINDOWPOSCHANGING:
@@ -2751,7 +2777,7 @@ gdk_event_translate (MSG *msg,
windowpos->cx, windowpos->cy, windowpos->x, windowpos->y));
/* If position and size haven't changed, don't do anything */
- if (_sizemove_in_progress &&
+ if (_modal_operation_in_progress &&
(windowpos->flags & SWP_NOMOVE) &&
(windowpos->flags & SWP_NOSIZE))
break;
@@ -2759,7 +2785,7 @@ gdk_event_translate (MSG *msg,
/* Once we've entered the moving or sizing modal loop, we won't
* return to the main loop until we're done sizing or moving.
*/
- if (_sizemove_in_progress &&
+ if (_modal_operation_in_progress &&
GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
!GDK_WINDOW_DESTROYED (window))
{
@@ -2768,13 +2794,13 @@ gdk_event_translate (MSG *msg,
GDK_NOTE (EVENTS, g_print (" do magic"));
if (((GdkWindowObject *) window)->resize_count > 1)
((GdkWindowObject *) window)->resize_count -= 1;
-
+
handle_configure_event (msg, window);
g_main_context_iteration (NULL, FALSE);
-
+#if 0
/* Dispatch main loop - to realize resizes... */
- handle_stuff_while_moving_or_resizing ();
-
+ modal_timer_proc (msg->hwnd, msg->message, 0, msg->time);
+#endif
/* Claim as handled, so that WM_SIZE and WM_MOVE are avoided */
return_val = TRUE;
*ret_valp = 1;
@@ -3352,6 +3378,14 @@ gdk_event_dispatch (GSource *source,
(*_gdk_event_func) (event, _gdk_event_data);
gdk_event_free (event);
+
+ /* Do drag & drop if it is still pending */
+ if (_dnd_source_state == GDK_WIN32_DND_PENDING)
+ {
+ _dnd_source_state = GDK_WIN32_DND_DRAGGING;
+ _gdk_win32_dnd_do_dragdrop ();
+ _dnd_source_state = GDK_WIN32_DND_NONE;
+ }
}
GDK_THREADS_LEAVE ();
diff --git a/gdk/win32/gdkglobals-win32.c b/gdk/win32/gdkglobals-win32.c
index ef1dbec..f9b2c02 100644
--- a/gdk/win32/gdkglobals-win32.c
+++ b/gdk/win32/gdkglobals-win32.c
@@ -49,11 +49,13 @@ UINT _gdk_input_codepage;
GdkAtom _gdk_selection;
GdkAtom _wm_transient_for;
GdkAtom _targets;
+GdkAtom _delete;
GdkAtom _save_targets;
GdkAtom _utf8_string;
GdkAtom _text;
GdkAtom _compound_text;
GdkAtom _text_uri_list;
+GdkAtom _text_html;
GdkAtom _image_png;
GdkAtom _image_jpeg;
GdkAtom _image_bmp;
@@ -63,10 +65,20 @@ GdkAtom _local_dnd;
GdkAtom _gdk_win32_dropfiles;
GdkAtom _gdk_ole2_dnd;
+UINT _cf_png;
+UINT _cf_jfif;
+UINT _cf_gif;
+UINT _cf_url;
+UINT _cf_html_format;
+UINT _cf_text_html;
+
+GdkWin32DndState _dnd_target_state = GDK_WIN32_DND_NONE;
+GdkWin32DndState _dnd_source_state = GDK_WIN32_DND_NONE;
+
gint _gdk_input_ignore_wintab = FALSE;
gint _gdk_max_colors = 0;
-gboolean _sizemove_in_progress = FALSE;
+gboolean _modal_operation_in_progress = FALSE;
gboolean _ignore_destroy_clipboard = FALSE;
HGLOBAL _delayed_rendering_data = NULL;
diff --git a/gdk/win32/gdkinput-win32.c b/gdk/win32/gdkinput-win32.c
index 1510c24..d02952d 100644
--- a/gdk/win32/gdkinput-win32.c
+++ b/gdk/win32/gdkinput-win32.c
@@ -898,7 +898,7 @@ _gdk_input_other_event (GdkEvent *event,
/* Don't produce any button or motion events while a window is being
* moved or resized, see bug #151090.
*/
- if (_sizemove_in_progress)
+ if (_modal_operation_in_progress)
{
GDK_NOTE (EVENTS_OR_INPUT, g_print ("... ignored when moving/sizing\n"));
return FALSE;
diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c
index f1afdf2..94b7ac7 100644
--- a/gdk/win32/gdkmain-win32.c
+++ b/gdk/win32/gdkmain-win32.c
@@ -100,22 +100,37 @@ _gdk_windowing_init (void)
CoInitialize (NULL);
- _gdk_selection = gdk_atom_intern ("GDK_SELECTION", FALSE);
- _wm_transient_for = gdk_atom_intern ("WM_TRANSIENT_FOR", FALSE);
- _targets = gdk_atom_intern ("TARGETS", FALSE);
- _save_targets = gdk_atom_intern ("SAVE_TARGETS", FALSE);
- _utf8_string = gdk_atom_intern ("UTF8_STRING", FALSE);
- _text = gdk_atom_intern ("TEXT", FALSE);
- _compound_text = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
- _text_uri_list = gdk_atom_intern ("text/uri-list", FALSE);
- _image_png = gdk_atom_intern ("image/png", FALSE);
- _image_jpeg = gdk_atom_intern ("image/jpeg", FALSE);
- _image_bmp = gdk_atom_intern ("image/bmp", FALSE);
- _image_gif = gdk_atom_intern ("image/gif", FALSE);
-
- _local_dnd = gdk_atom_intern ("LocalDndSelection", FALSE);
- _gdk_win32_dropfiles = gdk_atom_intern ("DROPFILES_DND", FALSE);
- _gdk_ole2_dnd = gdk_atom_intern ("OLE2_DND", FALSE);
+ _gdk_selection = gdk_atom_intern_static_string ("GDK_SELECTION");
+ _wm_transient_for = gdk_atom_intern_static_string ("WM_TRANSIENT_FOR");
+ _targets = gdk_atom_intern_static_string ("TARGETS");
+ _delete = gdk_atom_intern_static_string ("DELETE");
+ _save_targets = gdk_atom_intern_static_string ("SAVE_TARGETS");
+ _utf8_string = gdk_atom_intern_static_string ("UTF8_STRING");
+ _text = gdk_atom_intern_static_string ("TEXT");
+ _compound_text = gdk_atom_intern_static_string ("COMPOUND_TEXT");
+ _text_uri_list = gdk_atom_intern_static_string ("text/uri-list");
+ _text_html = gdk_atom_intern_static_string ("text/html");
+ _image_png = gdk_atom_intern_static_string ("image/png");
+ _image_jpeg = gdk_atom_intern_static_string ("image/jpeg");
+ _image_bmp = gdk_atom_intern_static_string ("image/bmp");
+ _image_gif = gdk_atom_intern_static_string ("image/gif");
+
+ _local_dnd = gdk_atom_intern_static_string ("LocalDndSelection");
+ _gdk_win32_dropfiles = gdk_atom_intern_static_string ("DROPFILES_DND");
+ _gdk_ole2_dnd = gdk_atom_intern_static_string ("OLE2_DND");
+
+ /* MS Office 2007, at least, offers images in common file formats
+ * using clipboard format names like "PNG" and "JFIF". So we follow
+ * the lead and map the GDK target name "image/png" to the clipboard
+ * format name "PNG" etc.
+ */
+ _cf_png = RegisterClipboardFormat ("PNG");
+ _cf_jfif = RegisterClipboardFormat ("JFIF");
+ _cf_gif = RegisterClipboardFormat ("GIF");
+
+ _cf_url = RegisterClipboardFormat ("UniformResourceLocatorW");
+ _cf_html_format = RegisterClipboardFormat ("HTML Format");
+ _cf_text_html = RegisterClipboardFormat ("text/html");
_gdk_win32_selection_init ();
}
diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h
index 3eda1a9..7578800 100644
--- a/gdk/win32/gdkprivate-win32.h
+++ b/gdk/win32/gdkprivate-win32.h
@@ -304,7 +304,7 @@ void _gdk_wchar_text_handle (GdkFont *font,
void _gdk_push_modal_window (GdkWindow *window);
void _gdk_remove_modal_window (GdkWindow *window);
-GdkWindow *_gdk_modal_current ();
+GdkWindow *_gdk_modal_current (void);
#ifdef G_ENABLE_DEBUG
@@ -411,11 +411,13 @@ extern guint _scancode_rshift;
extern GdkAtom _gdk_selection;
extern GdkAtom _wm_transient_for;
extern GdkAtom _targets;
+extern GdkAtom _delete;
extern GdkAtom _save_targets;
extern GdkAtom _utf8_string;
extern GdkAtom _text;
extern GdkAtom _compound_text;
extern GdkAtom _text_uri_list;
+extern GdkAtom _text_html;
extern GdkAtom _image_png;
extern GdkAtom _image_jpeg;
extern GdkAtom _image_bmp;
@@ -426,14 +428,44 @@ extern GdkAtom _local_dnd;
extern GdkAtom _gdk_win32_dropfiles;
extern GdkAtom _gdk_ole2_dnd;
+/* Clipboard formats */
+extern UINT _cf_png;
+extern UINT _cf_jfif;
+extern UINT _cf_gif;
+extern UINT _cf_url;
+extern UINT _cf_html_format;
+extern UINT _cf_text_html;
+
+/* OLE-based DND state */
+typedef enum {
+ GDK_WIN32_DND_NONE,
+ GDK_WIN32_DND_PENDING,
+ GDK_WIN32_DND_DROPPED,
+ GDK_WIN32_DND_FAILED,
+ GDK_WIN32_DND_DRAGGING,
+} GdkWin32DndState;
+
+extern GdkWin32DndState _dnd_target_state;
+extern GdkWin32DndState _dnd_source_state;
+
+void _gdk_win32_dnd_do_dragdrop (void);
+void _gdk_win32_ole2_dnd_property_change (GdkAtom type,
+ gint format,
+ const guchar *data,
+ gint nelements);
+
+void _gdk_win32_begin_modal_call (void);
+void _gdk_win32_end_modal_call (void);
+
+
/* Options */
extern gboolean _gdk_input_ignore_wintab;
extern gint _gdk_max_colors;
#define GDK_WIN32_COLORMAP_DATA(cmap) ((GdkColormapPrivateWin32 *) GDK_COLORMAP (cmap)->windowing_data)
-/* TRUE while a user-initiated window move or resize operation is in progress */
-extern gboolean _sizemove_in_progress;
+/* TRUE while a modal sizing, moving, or dnd operation is in progress */
+extern gboolean _modal_operation_in_progress;
/* TRUE when we are emptying the clipboard ourselves */
extern gboolean _ignore_destroy_clipboard;
diff --git a/gdk/win32/gdkproperty-win32.c b/gdk/win32/gdkproperty-win32.c
index 927fd64..6228ad1 100644
--- a/gdk/win32/gdkproperty-win32.c
+++ b/gdk/win32/gdkproperty-win32.c
@@ -258,6 +258,11 @@ gdk_property_change (GdkWindow *window,
_delayed_rendering_data = hdata;
}
}
+ else if (property == _gdk_ole2_dnd)
+ {
+ /* Will happen only if gdkdnd-win32.c has OLE2 dnd support compiled in */
+ _gdk_win32_ole2_dnd_property_change (type, format, data, nelements);
+ }
else
g_warning ("gdk_property_change: General case not implemented");
}
diff --git a/gdk/win32/gdkselection-win32.c b/gdk/win32/gdkselection-win32.c
index 0f6b165..e3936a9 100644
--- a/gdk/win32/gdkselection-win32.c
+++ b/gdk/win32/gdkselection-win32.c
@@ -55,11 +55,6 @@ static GdkSelProp *dropfiles_prop = NULL;
*/
static GHashTable *sel_owner_table = NULL;
-/* Well-known registered clipboard image formats */
-static UINT cf_png;
-static UINT cf_jfif;
-static UINT cf_gif;
-
/* GdkAtoms for well-known image formats */
static GdkAtom *known_pixbuf_formats;
static int n_known_pixbuf_formats;
@@ -79,15 +74,6 @@ _gdk_win32_selection_init (void)
sel_owner_table = g_hash_table_new (NULL, NULL);
_format_atom_table = g_hash_table_new (NULL, NULL);
- /* MS Office 2007, at least, offers images in common file formats
- * using clipboard format names like "PNG" and "JFIF". So we follow
- * the lead and map the GDK target name "image/png" to the clipboard
- * format name "PNG" etc.
- */
- cf_png = RegisterClipboardFormat ("PNG");
- cf_jfif = RegisterClipboardFormat ("JFIF");
- cf_gif = RegisterClipboardFormat ("GIF");
-
pixbuf_formats = gdk_pixbuf_get_formats ();
n_known_pixbuf_formats = 0;
@@ -123,7 +109,7 @@ _gdk_win32_selection_init (void)
text_plain_charset_CP1252 = gdk_atom_intern ("text/plain;charset=CP1252", FALSE);
g_hash_table_replace (_format_atom_table,
- GINT_TO_POINTER (cf_png),
+ GINT_TO_POINTER (_cf_png),
_image_png);
g_hash_table_replace (_format_atom_table,
@@ -442,7 +428,7 @@ gdk_selection_convert (GdkWindow *requestor,
for (fmt = 0; 0 != (fmt = EnumClipboardFormats (fmt)); )
{
- if (fmt == cf_png)
+ if (fmt == _cf_png)
{
targets[ntargets++] = _image_png;
has_png = TRUE;
@@ -460,7 +446,7 @@ gdk_selection_convert (GdkWindow *requestor,
targets[ntargets++] = _utf8_string;
has_text = TRUE;
}
- else if (fmt == cf_png)
+ else if (fmt == _cf_png)
{
/* Already handled above */
}
@@ -475,13 +461,13 @@ gdk_selection_convert (GdkWindow *requestor,
targets[ntargets++] = _image_bmp;
has_bmp = TRUE;
}
- else if (fmt == cf_jfif)
+ else if (fmt == _cf_jfif)
{
/* Ditto for JPEG */
if (!has_png)
targets[ntargets++] = _image_jpeg;
}
- else if (fmt == cf_gif)
+ else if (fmt == _cf_gif)
{
/* Ditto for GIF.
*/
@@ -1215,7 +1201,7 @@ gdk_win32_selection_add_targets (GdkWindow *owner,
if (!has_image)
{
GDK_NOTE (DND, g_print ("... SetClipboardData(PNG,NULL)\n"));
- SetClipboardData (cf_png, NULL);
+ SetClipboardData (_cf_png, NULL);
GDK_NOTE (DND, g_print ("... SetClipboardData(CF_DIB,NULL)\n"));
SetClipboardData (CF_DIB, NULL);
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index b859efc..598d291 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -1835,7 +1835,7 @@ _gdk_remove_modal_window (GdkWindow *window)
}
GdkWindow *
-_gdk_modal_current ()
+_gdk_modal_current (void)
{
if (modal_window_stack != NULL)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]