diff --git a/gdk/win32/gdkdnd-win32.c b/gdk/win32/gdkdnd-win32.c deleted file mode 100644 index db6f4e833a..0000000000 --- a/gdk/win32/gdkdnd-win32.c +++ /dev/null @@ -1,3231 +0,0 @@ -/* GDK - The GIMP Drawing Kit - * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald - * Copyright (C) 2001 Archaeopteryx Software Inc. - * 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 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ - -/* - * 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 - -#include -#include - -/* - * Support for OLE-2 drag and drop added at Archaeopteryx Software, 2001 - * For more information, contact Stephan R.A. Deibel (sdeibel@archaeopteryx.com) - * - * Notes on the implementation: - * - * Source drag context, IDragSource and IDataObject for it are created - * (almost) simultaneously, whereas target drag context and IDropTarget - * are separated in time - IDropTarget is created when a window is made - * to accept drops, while target drag context is created when a dragging - * cursor enters the window and is destroyed when that cursor leaves - * the window. - * - * There's a mismatch between data types supported by W32 (W32 formats) - * and by GTK+ (GDK targets). - * To account for it the data is transmuted back and forth. There are two - * main points of transmutation: - * * GDK convert selection: transmute W32 data to GTK+ data - * * GDK surface property change: transmute GTK+ data to W32 data - * - * There are also two points where data formats are considered: - * * When source drag context is created, it gets a list of GTK+ targets - * that it supports, these are matched to the W32 formats they - * correspond to (possibly with transmutation). New W32 formats for - * GTK+-specific formats are also created here (see below). - * * When target drag context is created, it queries the IDataObject - * for the list of W32 formats it supports and matches these to - * corresponding GTK+ formats that it will be able to provide - * (possibly with transmutation) later. Missing GDK targets for - * W32-specific formats are also created here (see below). - * - * W32 formats and GTK+ targets are both integers (CLIPFORMAT and GdkAtom - * respectively), but cannot be used interchangeably. - * - * To accommodate advanced GTK+ applications the code allows them to - * register drop targets that accept W32 data formats, and to register - * drag sources that provide W32 data formats. To do that they must - * register either with the string name of the format in question - * (for example, "Shell IDList Array") or, for unnamed pre-defined - * formats, register with the stringified constant name of the format - * in question (for example, "CF_UNICODETEXT"). - * If such target format is accepted/provided, GDK will not try to - * transmute it to/from something else. Otherwise GDK will do the following - * transmutation: - * * If GTK+ application provides image/png, image/gif or image/jpeg, - * GDK will claim to also provide "PNG", "GIF" or "JFIF" respectively, - * and will pass these along verbatim. - * * If GTK+ application provides any GdkPixbuf-compatible target, - * GDK will also offer "PNG" and CF_DIB W32 formats. - * * If GTK+ application provides UTF8_STRING, GDK will also offer - * CF_UNICODETEXT (UTF-16-encoded) and CF_TEXT (encoded with thread- - * and locale-depenant codepage), and will do the conversion when such - * data is requested. - * * If GTK+ application accepts image/png, image/gif or image/jpeg, - * GDK will claim to also accept "PNG", "GIF" or "JFIF" respectively, - * and will pass these along verbatim. - * * If GTK+ application accepts image/bmp, GDK will - * claim to accept CF_DIB W32 format, and will convert - * it, changing the header, when such data is provided. - * * If GTK+ application accepts UTF8_STRING, GDK will - * claim to accept CF_UNICODETEXT and CF_TEXT, and will do - * the conversion when such data is provided. - * * If GTK+ application accepts text/uri-list, GDK will - * claim to accept "Shell IDList Array", and will do the - * conversion when such data is provided. - * - * Currently the conversion from text/uri-list to Shell IDList Array is not - * implemented, so it's not possible to drag & drop files from GTK+ - * applications to non-GTK+ applications the same way one can drag files - * from Windows Explorer. - * - * To accommodate GTK+ application compaibility the code allows - * GTK+ applications to register drop targets that accept GTK+-specific - * data formats, and to register drag sources that provide GTK+-specific - * data formats. This is done by simply registering target atom names - * as clipboard formats. This way two GTK+ applications can exchange - * data in their native formats (both well-known ones, such as UTF8_STRING, - * and special, known only to specific applications). This will work just - * fine as long as both applications agree on what kind of data is stored - * under such format exactly. - * - * Note that clipboard format space is limited, there can only be 16384 - * of them for a particular user session. Therefore it is highly inadvisable - * to create and register such formats out of the whole cloth, dynamically. - * If more flexibility is needed, register one format that has some - * internal indicators of the kind of data it contains, then write the application - * in such a way that it requests the data and inspects its header before deciding - * whether to accept it or not. For details see GTK+ drag & drop documentation - * on the "drag-motion" and "drag-data-received" signals. - */ - -/* The mingw.org compiler does not export GUIDS in it's import library. To work - * around that, define INITGUID to have the GUIDS declared. */ -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -#define INITGUID -#endif - -/* For C-style COM wrapper macros */ -#define COBJMACROS - -#include "gdkdnd.h" -#include "gdkproperty.h" -#include "gdkinternals.h" -#include "gdkprivate-win32.h" -#include "gdkwin32.h" -#include "gdkwin32dnd.h" -#include "gdkdisplayprivate.h" -#include "gdk/gdkdndprivate.h" -#include "gdkwin32dnd-private.h" -#include "gdkdisplay-win32.h" -#include "gdkselection-win32.h" -#include "gdkdeviceprivate.h" - -#include - -#include -#include -#include - -#include -#include - -/* from gdkselection-win32.c */ -extern GdkAtom *known_pixbuf_formats; -extern int n_known_pixbuf_formats; - - -typedef enum { - GDK_DRAG_STATUS_DRAG, - GDK_DRAG_STATUS_MOTION_WAIT, - GDK_DRAG_STATUS_ACTION_WAIT, - GDK_DRAG_STATUS_DROP -} GdkDragStatus; - -static GList *contexts; -static GdkDragContext *current_dest_drag = NULL; -static gboolean use_ole2_dnd = FALSE; - -static gboolean drag_context_grab (GdkDragContext *context); - -G_DEFINE_TYPE (GdkWin32DragContext, gdk_win32_drag_context, GDK_TYPE_DRAG_CONTEXT) - -static void -move_drag_surface (GdkDragContext *context, - guint x_root, - guint y_root) -{ - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - - gdk_surface_move (context_win32->drag_surface, - x_root - context_win32->hot_x, - y_root - context_win32->hot_y); - gdk_surface_raise (context_win32->drag_surface); -} - -static void -gdk_win32_drag_context_init (GdkWin32DragContext *context) -{ - if (!use_ole2_dnd) - { - contexts = g_list_prepend (contexts, context); - } - else - { - } - - GDK_NOTE (DND, g_print ("gdk_drag_context_init %p\n", context)); -} - -static void -gdk_win32_drag_context_finalize (GObject *object) -{ - GdkDragContext *context; - GdkWin32DragContext *context_win32; - GdkSurface *drag_surface; - - GDK_NOTE (DND, g_print ("gdk_drag_context_finalize %p\n", object)); - - g_return_if_fail (GDK_IS_WIN32_DRAG_CONTEXT (object)); - - context = GDK_DRAG_CONTEXT (object); - context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - - if (!use_ole2_dnd) - { - contexts = g_list_remove (contexts, context); - - if (context == current_dest_drag) - current_dest_drag = NULL; - } - - g_set_object (&context_win32->ipc_window, NULL); - drag_surface = context_win32->drag_surface; - - g_array_unref (context_win32->droptarget_format_target_map); - - G_OBJECT_CLASS (gdk_win32_drag_context_parent_class)->finalize (object); - - if (drag_surface) - gdk_surface_destroy (drag_surface); -} - -/* Drag Contexts */ - -static GdkDragContext * -gdk_drag_context_new (GdkDisplay *display, - gboolean is_source, - GdkSurface *source_surface, - GdkSurface *dest_surface, - GdkDragAction actions, - GdkDevice *device, - GdkDragProtocol protocol) -{ - GdkWin32DragContext *context_win32; - GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display); - GdkDragContext *context; - - context_win32 = g_object_new (GDK_TYPE_WIN32_DRAG_CONTEXT, - "device", device ? device : gdk_seat_get_pointer (gdk_display_get_default_seat (display)), - NULL); - context = GDK_DRAG_CONTEXT(context_win32); - - - if (win32_display->has_fixed_scale) - context_win32->scale = win32_display->surface_scale; - else - context_win32->scale = _gdk_win32_display_get_monitor_scale_factor (win32_display, NULL, NULL, NULL); - - context_win32->droptarget_format_target_map = g_array_new (FALSE, FALSE, sizeof (GdkSelTargetFormat)); - - context->is_source = is_source; - g_set_object (&context->source_surface, source_surface); - g_set_object (&context->dest_surface, dest_surface); - context->actions = actions; - context_win32->protocol = protocol; - - return context; -} - -static GdkDragContext * -gdk_drag_context_find (gboolean is_source, - GdkSurface *source, - GdkSurface *dest) -{ - GList *tmp_list = contexts; - GdkDragContext *context; - - while (tmp_list) - { - context = (GdkDragContext *)tmp_list->data; - - if ((!context->is_source == !is_source) && - ((source == NULL) || (context->source_surface && (context->source_surface == source))) && - ((dest == NULL) || (context->dest_surface && (context->dest_surface == dest)))) - return context; - - tmp_list = tmp_list->next; - } - - return NULL; -} - -#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]); - -typedef struct { - IDropTarget idt; - GdkDragContext *context; - - gint ref_count; - GdkSurface *dest_surface; - -} target_drag_context; - -typedef struct { - IDropSource ids; - GdkDragContext *context; - gint ref_count; -} source_drag_context; - -typedef struct { - IDataObject ido; - int ref_count; - GdkDragContext *context; - GArray *formats; -} data_object; - -typedef struct { - IEnumFORMATETC ief; - int ref_count; - int ix; - data_object *dataobj; -} enum_formats; - -static source_drag_context *pending_src_context = NULL; -static source_drag_context *current_src_context = NULL; -static data_object *current_src_object = NULL; - -static enum_formats *enum_formats_new (data_object *dataobj); - -/* map windows -> target drag contexts. The table - * owns a ref to both objects. - */ -static GHashTable* target_ctx_for_surface = NULL; - -static ULONG STDMETHODCALLTYPE -idroptarget_addref (LPDROPTARGET This) -{ - target_drag_context *ctx = (target_drag_context *) This; - - int ref_count = ++ctx->ref_count; - - GDK_NOTE (DND, g_print ("idroptarget_addref %p %d\n", This, ref_count)); - - return ref_count; -} - -static HRESULT STDMETHODCALLTYPE -idroptarget_queryinterface (LPDROPTARGET This, - REFIID riid, - LPVOID *ppvObject) -{ - GDK_NOTE (DND, { - g_print ("idroptarget_queryinterface %p ", This); - PRINT_GUID (riid); - }); - - *ppvObject = NULL; - - if (IsEqualGUID (riid, &IID_IUnknown)) - { - GDK_NOTE (DND, g_print ("...IUnknown S_OK\n")); - idroptarget_addref (This); - *ppvObject = This; - return S_OK; - } - else if (IsEqualGUID (riid, &IID_IDropTarget)) - { - GDK_NOTE (DND, g_print ("...IDropTarget S_OK\n")); - idroptarget_addref (This); - *ppvObject = This; - return S_OK; - } - else - { - GDK_NOTE (DND, g_print ("...E_NOINTERFACE\n")); - return E_NOINTERFACE; - } -} - -static ULONG STDMETHODCALLTYPE -idroptarget_release (LPDROPTARGET This) -{ - target_drag_context *ctx = (target_drag_context *) This; - - int ref_count = --ctx->ref_count; - - GDK_NOTE (DND, g_print ("idroptarget_release %p %d\n", This, ref_count)); - - if (ref_count == 0) - { - g_object_unref (ctx->context); - g_clear_object (&ctx->dest_surface); - g_free (This); - } - - return ref_count; -} - -static GdkDragAction -get_suggested_action (DWORD grfKeyState) -{ - GdkWin32Selection *sel_win32 = _gdk_win32_selection_get (); - /* 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; - else if (sel_win32->dnd_source_state == GDK_WIN32_DND_DRAGGING) - return GDK_ACTION_MOVE; - 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 (GdkDisplay *display) -{ - g_main_context_iteration (NULL, FALSE); - while (_gdk_event_queue_find_first (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 GdkDragAction -action_for_drop_effect (DWORD effect) -{ - switch (effect) - { - case DROPEFFECT_MOVE: - return GDK_ACTION_MOVE; - case DROPEFFECT_LINK: - return GDK_ACTION_LINK; - case DROPEFFECT_COPY: - return GDK_ACTION_COPY; - default: - return 0; - } -} - -static void -_gdk_display_put_event (GdkDisplay *display, - GdkEvent *event) -{ - gdk_event_set_display (event, display); - gdk_display_put_event (display, event); -} - -static void -dnd_event_put (GdkEventType type, - GdkDragContext *context, - gint pt_x, - gint pt_y, - GdkSurface *dnd_surface) -{ - GdkEvent *e; - - e = gdk_event_new (type); - - e->dnd.send_event = FALSE; - g_set_object (&e->dnd.context, context); - g_set_object (&e->dnd.surface, dnd_surface); - e->dnd.time = GDK_CURRENT_TIME; - e->dnd.x_root = pt_x; - e->dnd.y_root = pt_y; - - gdk_event_set_device (e, gdk_drag_context_get_device (context)); - gdk_event_set_seat (e, gdk_device_get_seat (gdk_drag_context_get_device (context))); - - GDK_NOTE (EVENTS, _gdk_win32_print_event (e)); - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (context)), e); - gdk_event_free (e); -} - -static GdkContentFormats * -query_targets (LPDATAOBJECT pDataObj, - GArray *format_target_map) -{ - IEnumFORMATETC *pfmt = NULL; - FORMATETC fmt; - GList *result = NULL; - HRESULT hr; - GdkContentFormatsBuilder *builder; - GdkContentFormats *result_formats; - GList *p; - - if ((LPDATAOBJECT) current_src_object == pDataObj) - return gdk_content_formats_ref (current_src_object->context->formats); - - hr = IDataObject_EnumFormatEtc (pDataObj, DATADIR_GET, &pfmt); - - if (SUCCEEDED (hr)) - hr = IEnumFORMATETC_Next (pfmt, 1, &fmt, NULL); - - while (SUCCEEDED (hr) && hr != S_FALSE) - { - gboolean is_predef; - gchar *registered_name = _gdk_win32_get_clipboard_format_name (fmt.cfFormat, &is_predef); - - if (registered_name && is_predef) - GDK_NOTE (DND, g_print ("supported built-in source format 0x%x %s\n", fmt.cfFormat, registered_name)); - else if (registered_name) - GDK_NOTE (DND, g_print ("supported source format 0x%x %s\n", fmt.cfFormat, registered_name)); - else - GDK_NOTE (DND, g_print ("supported unnamed? source format 0x%x\n", fmt.cfFormat)); - - g_free (registered_name); - - _gdk_win32_add_format_to_targets (fmt.cfFormat, format_target_map, &result); - hr = IEnumFORMATETC_Next (pfmt, 1, &fmt, NULL); - } - - if (pfmt) - IEnumFORMATETC_Release (pfmt); - - builder = gdk_content_formats_builder_new (); - - for (p = g_list_reverse (result); p; p = p->next) - gdk_content_formats_builder_add_mime_type (builder, (const gchar *) p->data); - - result_formats = gdk_content_formats_builder_free_to_formats (builder); - g_list_free (result); - - return result_formats; -} - -static void -set_data_object (LPDATAOBJECT *location, LPDATAOBJECT data_object) -{ - if (*location != NULL) - IDataObject_Release (*location); - - *location = data_object; - - if (*location != NULL) - IDataObject_AddRef (*location); -} - -static HRESULT STDMETHODCALLTYPE -idroptarget_dragenter (LPDROPTARGET This, - LPDATAOBJECT pDataObj, - DWORD grfKeyState, - POINTL pt, - LPDWORD pdwEffect) -{ - target_drag_context *ctx = (target_drag_context *) This; - GdkWin32Selection *sel_win32 = _gdk_win32_selection_get (); - GdkDragContext *context; - GdkWin32DragContext *context_win32; - GdkDisplay *display; - gint pt_x; - gint pt_y; - - GDK_NOTE (DND, g_print ("idroptarget_dragenter %p @ %ld : %ld for dest window 0x%p S_OK\n", This, pt.x, pt.y, ctx->dest_surface)); - - g_clear_object (&ctx->context); - - context = gdk_drag_context_new (gdk_surface_get_display (ctx->dest_surface), - FALSE, - /* OLE2 DnD does not allow us to get the source window, - * but we *can* find it if it's ours. This is needed to - * support DnD within the same widget, for example. - */ - /* FIXME: Root window used to be here instead of NULL. Find a substitute? */ - (current_src_context && current_src_context->context) ? current_src_context->context->source_surface : NULL, - ctx->dest_surface, - GDK_ACTION_DEFAULT | GDK_ACTION_COPY | GDK_ACTION_MOVE, - NULL, - GDK_DRAG_PROTO_OLE2); - context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - context->formats = query_targets (pDataObj, context_win32->droptarget_format_target_map); - - ctx->context = context; - - g_set_object (&sel_win32->target_drag_context, context); - context->suggested_action = GDK_ACTION_MOVE; - context->action = GDK_ACTION_MOVE; - - g_array_set_size (context_win32->droptarget_format_target_map, 0); - - ctx->context->suggested_action = get_suggested_action (grfKeyState); - set_data_object (&sel_win32->dnd_data_object_target, pDataObj); - pt_x = pt.x / context_win32->scale + _gdk_offset_x; - pt_y = pt.y / context_win32->scale + _gdk_offset_y; - dnd_event_put (GDK_DRAG_ENTER, ctx->context, pt_x, pt_y, ctx->context->dest_window); - dnd_event_put (GDK_DRAG_MOTION, ctx->context, pt_x, pt_y, ctx->context->dest_window); - context_win32->last_key_state = grfKeyState; - context_win32->last_x = pt_x; - context_win32->last_y = pt_y; - process_pending_events (gdk_device_get_display (gdk_drag_context_get_device (ctx->context))); - *pdwEffect = drop_effect_for_action (ctx->context->action); - - GDK_NOTE (DND, g_print ("idroptarget_dragenter returns with action %d and drop effect %lu\n", ctx->context->action, *pdwEffect)); - - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -idroptarget_dragover (LPDROPTARGET This, - DWORD grfKeyState, - POINTL pt, - LPDWORD pdwEffect) -{ - target_drag_context *ctx = (target_drag_context *) This; - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (ctx->context); - gint pt_x = pt.x / context_win32->scale + _gdk_offset_x; - gint pt_y = pt.y / context_win32->scale + _gdk_offset_y; - - ctx->context->suggested_action = get_suggested_action (grfKeyState); - - GDK_NOTE (DND, g_print ("idroptarget_dragover %p @ %ld : %ld, suggests %d action S_OK\n", This, pt.x, pt.y, ctx->context->suggested_action)); - - if (pt_x != context_win32->last_x || - pt_y != context_win32->last_y || - grfKeyState != context_win32->last_key_state) - { - dnd_event_put (GDK_DRAG_MOTION, ctx->context, pt_x, pt_y, ctx->context->dest_window); - context_win32->last_key_state = grfKeyState; - context_win32->last_x = pt_x; - context_win32->last_y = pt_y; - } - - process_pending_events (gdk_device_get_display (gdk_drag_context_get_device (ctx->context))); - - *pdwEffect = drop_effect_for_action (ctx->context->action); - - GDK_NOTE (DND, g_print ("idroptarget_dragover returns with action %d and effect %lu\n", ctx->context->action, *pdwEffect)); - - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -idroptarget_dragleave (LPDROPTARGET This) -{ - target_drag_context *ctx = (target_drag_context *) This; - GdkWin32Selection *sel_win32 = _gdk_win32_selection_get (); - - GDK_NOTE (DND, g_print ("idroptarget_dragleave %p S_OK\n", This)); - - dnd_event_put (GDK_DRAG_LEAVE, ctx->context, 0, 0, ctx->context->dest_window); - process_pending_events (gdk_device_get_display (gdk_drag_context_get_device (ctx->context))); - - g_clear_object (&sel_win32->target_drag_context); - g_clear_object (&ctx->context); - set_data_object (&sel_win32->dnd_data_object_target, NULL); - - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -idroptarget_drop (LPDROPTARGET This, - LPDATAOBJECT pDataObj, - DWORD grfKeyState, - POINTL pt, - LPDWORD pdwEffect) -{ - target_drag_context *ctx = (target_drag_context *) This; - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (ctx->context); - gint pt_x = pt.x / context_win32->scale + _gdk_offset_x; - gint pt_y = pt.y / context_win32->scale + _gdk_offset_y; - GdkWin32Selection *sel_win32 = _gdk_win32_selection_get (); - - GDK_NOTE (DND, g_print ("idroptarget_drop %p ", This)); - - if (pDataObj == NULL) - { - GDK_NOTE (DND, g_print ("E_POINTER\n")); - g_clear_object (&ctx->context); - return E_POINTER; - } - - ctx->context->suggested_action = get_suggested_action (grfKeyState); - - dnd_event_put (GDK_DROP_START, ctx->context, pt_x, pt_y, ctx->context->dest_window); - process_pending_events (gdk_device_get_display (gdk_drag_context_get_device (ctx->context))); - - /* Notify OLE of copy or move */ - if (sel_win32->dnd_target_state != GDK_WIN32_DND_DROPPED) - *pdwEffect = DROPEFFECT_NONE; - else - *pdwEffect = drop_effect_for_action (ctx->context->action); - - g_clear_object (&sel_win32->target_drag_context); - g_clear_object (&ctx->context); - set_data_object (&sel_win32->dnd_data_object_target, NULL); - - GDK_NOTE (DND, g_print ("drop S_OK with effect %lx\n", *pdwEffect)); - - return S_OK; -} - -static ULONG STDMETHODCALLTYPE -idropsource_addref (LPDROPSOURCE This) -{ - source_drag_context *ctx = (source_drag_context *) This; - - int ref_count = ++ctx->ref_count; - - GDK_NOTE (DND, g_print ("idropsource_addref %p %d\n", This, ref_count)); - - return ref_count; -} - -static HRESULT STDMETHODCALLTYPE -idropsource_queryinterface (LPDROPSOURCE This, - REFIID riid, - LPVOID *ppvObject) -{ - GDK_NOTE (DND, { - g_print ("idropsource_queryinterface %p ", This); - PRINT_GUID (riid); - }); - - *ppvObject = NULL; - - if (IsEqualGUID (riid, &IID_IUnknown)) - { - GDK_NOTE (DND, g_print ("...IUnknown S_OK\n")); - idropsource_addref (This); - *ppvObject = This; - return S_OK; - } - else if (IsEqualGUID (riid, &IID_IDropSource)) - { - GDK_NOTE (DND, g_print ("...IDropSource S_OK\n")); - idropsource_addref (This); - *ppvObject = This; - return S_OK; - } - else - { - GDK_NOTE (DND, g_print ("...E_NOINTERFACE\n")); - return E_NOINTERFACE; - } -} - -static ULONG STDMETHODCALLTYPE -idropsource_release (LPDROPSOURCE This) -{ - source_drag_context *ctx = (source_drag_context *) This; - - int ref_count = --ctx->ref_count; - - GDK_NOTE (DND, g_print ("idropsource_release %p %d\n", This, ref_count)); - - if (ref_count == 0) - { - g_clear_object (&ctx->context); - if (current_src_context == ctx) - current_src_context = NULL; - g_free (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 *context, - DWORD key_state, - gboolean esc_pressed) -{ - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - POINT pt; - POINT pt_client; - gboolean changed = FALSE; - HWND hwnd = GDK_SURFACE_HWND (context->source_surface); - LPARAM lparam; - WPARAM wparam; - gint pt_x; - gint pt_y; - - if (!API_CALL (GetCursorPos, (&pt))) - return FALSE; - - pt_client = pt; - - if (!API_CALL (ScreenToClient, (hwnd, &pt_client))) - return FALSE; - - pt_x = pt.x / context_win32->scale + _gdk_offset_x; - pt_y = pt.y / context_win32->scale + _gdk_offset_y; - - if (pt_x != context_win32->last_x || pt_y != context_win32->last_y || - key_state != context_win32->last_key_state) - { - lparam = MAKELPARAM (pt_client.x, pt_client.y); - wparam = key_state; - if (pt_x != context_win32->last_x || pt_y != context_win32->last_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) != (context_win32->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) != (context_win32->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) != (context_win32->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) != (context_win32->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) != (context_win32->last_key_state & MK_SHIFT)) - { - if (key_state & MK_SHIFT) - SendMessage (hwnd, WM_KEYDOWN, VK_SHIFT, 0); - else - SendMessage (hwnd, WM_KEYUP, VK_SHIFT, 0); - } - - changed = TRUE; - context_win32->last_key_state = key_state; - context_win32->last_x = pt_x; - context_win32->last_y = pt_y; - } - - 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) -{ - source_drag_context *ctx = (source_drag_context *) This; - GdkWin32Selection *sel_win32 = _gdk_win32_selection_get (); - - GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag %p esc=%d keystate=0x%lx with state %d", This, fEscapePressed, grfKeyState, sel_win32->dnd_source_state)); - - if (send_change_events (ctx->context, grfKeyState, fEscapePressed)) - process_pending_events (gdk_device_get_display (gdk_drag_context_get_device (ctx->context))); - - if (sel_win32->dnd_source_state == GDK_WIN32_DND_DROPPED) - { - GDK_NOTE (DND, g_print ("DRAGDROP_S_DROP\n")); - return DRAGDROP_S_DROP; - } - else if (sel_win32->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) -{ - source_drag_context *ctx = (source_drag_context *) This; - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (ctx->context); - GdkDragAction suggested_action; - GdkEvent *e; - POINT pt; - - GDK_NOTE (DND, g_print ("idropsource_givefeedback %p with drop effect %lu S_OK\n", This, dwEffect)); - - if (!API_CALL (GetCursorPos, (&pt))) - return S_OK; - - suggested_action = action_for_drop_effect (dwEffect); - - ctx->context->action = suggested_action; - - if (dwEffect == DROPEFFECT_NONE) - g_clear_object (&ctx->context->dest_surface); - else if (ctx->context->dest_surface == NULL) - ctx->context->dest_surface = NULL; /* FIXME: Root window was here originally. Find a substitute? */ - - context_win32->last_x = pt.x / context_win32->scale + _gdk_offset_x; - context_win32->last_y = pt.y / context_win32->scale + _gdk_offset_y; - - e = gdk_event_new (GDK_DRAG_STATUS); - - g_set_object (&e->dnd.window, ctx->context->source_surface); - e->dnd.send_event = FALSE; - g_set_object (&e->dnd.context, ctx->context); - e->dnd.time = GDK_CURRENT_TIME; - e->dnd.x_root = context_win32->last_x; - e->dnd.y_root = context_win32->last_y; - - gdk_event_set_device (e, gdk_drag_context_get_device (ctx->context)); - gdk_event_set_seat (e, gdk_device_get_seat (gdk_drag_context_get_device (ctx->context))); - - GDK_NOTE (EVENTS, _gdk_win32_print_event (e)); - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (ctx->context)), e); - gdk_event_free (e); - process_pending_events (gdk_device_get_display (gdk_drag_context_get_device (ctx->context))); - - GDK_NOTE (DND, g_print ("idropsource_givefeedback %p returns\n", This)); - - return S_OK; -} - -static ULONG STDMETHODCALLTYPE -idataobject_addref (LPDATAOBJECT This) -{ - data_object *dobj = (data_object *) This; - int ref_count = ++dobj->ref_count; - - GDK_NOTE (DND, g_print ("idataobject_addref %p %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 %p ", This); - PRINT_GUID (riid); - }); - - *ppvObject = NULL; - - if (IsEqualGUID (riid, &IID_IUnknown)) - { - GDK_NOTE (DND, g_print ("...IUnknown S_OK\n")); - idataobject_addref (This); - *ppvObject = This; - return S_OK; - } - else if (IsEqualGUID (riid, &IID_IDataObject)) - { - GDK_NOTE (DND, g_print ("...IDataObject S_OK\n")); - idataobject_addref (This); - *ppvObject = This; - return S_OK; - } - else - { - GDK_NOTE (DND, g_print ("...E_NOINTERFACE\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 %p %d\n", This, ref_count)); - - if (ref_count == 0) - { - g_array_free (dobj->formats, TRUE); - g_free (This); - } - - return ref_count; -} - -static HRESULT -query (LPDATAOBJECT This, - LPFORMATETC pFormatEtc) -{ - data_object *ctx = (data_object *) This; - gint 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 < ctx->formats->len; i++) - if (pFormatEtc->cfFormat == g_array_index (ctx->formats, GdkSelTargetFormat, i).format) - return S_OK; - - return DV_E_FORMATETC; -} - -static HRESULT STDMETHODCALLTYPE -idataobject_getdata (LPDATAOBJECT This, - LPFORMATETC pFormatEtc, - LPSTGMEDIUM pMedium) -{ - data_object *ctx = (data_object *) This; - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - HRESULT hr; - GdkEvent e; - gint i; - GdkAtom target; - gint64 loopend; - - 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) - { - GDK_NOTE (DND, g_print ("Unsupported format, returning 0x%lx\n", hr)); - return hr; - } - - /* Append a GDK_SELECTION_REQUEST event and then hope the app sets the - * property associated with the _gdk_ole2_dnd atom - */ - win32_sel->property_change_format = pFormatEtc->cfFormat; - win32_sel->property_change_data = pMedium; - - for (i = 0, target = NULL; i < ctx->formats->len; i++) - { - GdkSelTargetFormat *frec = &g_array_index (ctx->formats, GdkSelTargetFormat, i); - - if (frec->format == pFormatEtc->cfFormat) - { - target = frec->target; - win32_sel->property_change_transmute = frec->transmute; - win32_sel->property_change_target_atom = frec->target; - } - } - - if (target == NULL) - { - GDK_NOTE (EVENTS, g_print ("(target not found)")); - return E_UNEXPECTED; - } - - GDK_NOTE (DND, { - const char *target_name = (const char *)target; - g_print ("idataobject_getdata will request target 0x%p (%s) ", - target, target_name); - }); - - - memset (&e, 0, sizeof (GdkEvent)); - e.type = GDK_SELECTION_REQUEST; - g_set_object (&e.selection.window, ctx->context->source_surface); - e.selection.send_event = FALSE; /* ??? */ - /* Both selection and property are OLE2_DND, because change_property() - * will only get the property and not the selection. Theoretically we - * could use two different atoms (SELECTION_OLE2_DND and PROPERTY_OLE2_DND), - * but there's little reason to do so. - */ - e.selection.selection = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_OLE2_DND); - e.selection.target = target; - /* Requestor here is fake, just to allow the event to be processed */ - g_set_object (&e.selection.requestor, ctx->context->source_surface); - e.selection.property = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_OLE2_DND); - e.selection.time = GDK_CURRENT_TIME; - - GDK_NOTE (EVENTS, _gdk_win32_print_event (&e)); - - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (ctx->context)), &e); - - /* Don't hold up longer than one second */ - loopend = g_get_monotonic_time () + 1000000000; - - while (win32_sel->property_change_data != 0 && - g_get_monotonic_time () < loopend) - process_pending_events (gdk_device_get_display (gdk_drag_context_get_device (ctx->context))); - - if (pMedium->hGlobal == NULL) { - GDK_NOTE (DND, g_print (" E_UNEXPECTED\n")); - return E_UNEXPECTED; - } - - GDK_NOTE (DND, g_print (" S_OK\n")); - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -idataobject_getdatahere (LPDATAOBJECT This, - LPFORMATETC pFormatEtc, - LPSTGMEDIUM pMedium) -{ - GDK_NOTE (DND, g_print ("idataobject_getdatahere %p %s E_UNEXPECTED\n", - This, _gdk_win32_cf_to_string (pFormatEtc->cfFormat))); - - return E_UNEXPECTED; -} - -static HRESULT STDMETHODCALLTYPE -idataobject_querygetdata (LPDATAOBJECT This, - LPFORMATETC pFormatEtc) -{ - HRESULT hr; - - hr = query (This, pFormatEtc); - -#define CASE(x) case x: g_print (#x "\n"); break - GDK_NOTE (DND, { - g_print ("idataobject_querygetdata %p %s ", - 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); - } - }); - - return hr; -} - -static HRESULT STDMETHODCALLTYPE -idataobject_getcanonicalformatetc (LPDATAOBJECT This, - LPFORMATETC pFormatEtcIn, - LPFORMATETC pFormatEtcOut) -{ - GDK_NOTE (DND, g_print ("idataobject_getcanonicalformatetc %p E_UNEXPECTED\n", This)); - - return E_UNEXPECTED; -} - -static HRESULT STDMETHODCALLTYPE -idataobject_setdata (LPDATAOBJECT This, - LPFORMATETC pFormatEtc, - LPSTGMEDIUM pMedium, - BOOL fRelease) -{ - GDK_NOTE (DND, g_print ("idataobject_setdata %p %s E_UNEXPECTED\n", - This, _gdk_win32_cf_to_string (pFormatEtc->cfFormat))); - - return E_UNEXPECTED; -} - -static HRESULT STDMETHODCALLTYPE -idataobject_enumformatetc (LPDATAOBJECT This, - DWORD dwDirection, - LPENUMFORMATETC *ppEnumFormatEtc) -{ - GDK_NOTE (DND, g_print ("idataobject_enumformatetc %p ", This)); - - if (dwDirection != DATADIR_GET) - { - GDK_NOTE (DND, g_print ("E_NOTIMPL\n")); - return E_NOTIMPL; - } - - *ppEnumFormatEtc = &enum_formats_new ((data_object *) This)->ief; - - GDK_NOTE (DND, g_print (" %p S_OK\n", *ppEnumFormatEtc)); - - 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 %p E_NOTIMPL\n", This)); - - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -idataobject_dunadvise (LPDATAOBJECT This, - DWORD dwConnection) -{ - GDK_NOTE (DND, g_print ("idataobject_dunadvise %p E_NOTIMPL\n", This)); - - return E_NOTIMPL; -} - -static HRESULT STDMETHODCALLTYPE -idataobject_enumdadvise (LPDATAOBJECT This, - LPENUMSTATDATA *ppenumAdvise) -{ - GDK_NOTE (DND, g_print ("idataobject_enumdadvise %p OLE_E_ADVISENOTSUPPORTED\n", This)); - - return OLE_E_ADVISENOTSUPPORTED; -} - -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 %p %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 %p", This); - PRINT_GUID (riid); - }); - - *ppvObject = NULL; - - if (IsEqualGUID (riid, &IID_IUnknown)) - { - GDK_NOTE (DND, g_print ("...IUnknown S_OK\n")); - ienumformatetc_addref (This); - *ppvObject = This; - return S_OK; - } - else if (IsEqualGUID (riid, &IID_IEnumFORMATETC)) - { - GDK_NOTE (DND, g_print ("...IEnumFORMATETC S_OK\n")); - ienumformatetc_addref (This); - *ppvObject = This; - return S_OK; - } - else - { - GDK_NOTE (DND, g_print ("...E_NOINTERFACE\n")); - return E_NOINTERFACE; - } -} - -static ULONG STDMETHODCALLTYPE -ienumformatetc_release (LPENUMFORMATETC This) -{ - enum_formats *en = (enum_formats *) This; - int ref_count = --en->ref_count; - - GDK_NOTE (DND, g_print ("ienumformatetc_release %p %d\n", This, ref_count)); - - if (ref_count == 0) - { - idataobject_release ((LPDATAOBJECT) en->dataobj); - g_free (This); - } - - return ref_count; -} - -static HRESULT STDMETHODCALLTYPE -ienumformatetc_next (LPENUMFORMATETC This, - ULONG celt, - LPFORMATETC elts, - ULONG *nelt) -{ - enum_formats *en = (enum_formats *) This; - ULONG i, n; - ULONG formats_to_get = celt; - - GDK_NOTE (DND, g_print ("ienumformatetc_next %p %d %ld ", This, en->ix, celt)); - - n = 0; - for (i = 0; i < formats_to_get; i++) - { - UINT fmt; - if (en->ix >= en->dataobj->formats->len) - break; - fmt = g_array_index (en->dataobj->formats, GdkSelTargetFormat, en->ix++).format; - /* skip internals */ - if (fmt == 0 || fmt > 0xFFFF) - { - formats_to_get += 1; - continue; - } - elts[n].cfFormat = fmt; - elts[n].ptd = NULL; - elts[n].dwAspect = DVASPECT_CONTENT; - elts[n].lindex = -1; - elts[n].tymed = TYMED_HGLOBAL; - - n++; - } - - 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 - return S_FALSE; -} - -static HRESULT STDMETHODCALLTYPE -ienumformatetc_skip (LPENUMFORMATETC This, - ULONG celt) -{ - enum_formats *en = (enum_formats *) This; - - GDK_NOTE (DND, g_print ("ienumformatetc_skip %p %d %ld S_OK\n", This, en->ix, celt)); - - en->ix += celt; - - return S_OK; -} - -static HRESULT STDMETHODCALLTYPE -ienumformatetc_reset (LPENUMFORMATETC This) -{ - enum_formats *en = (enum_formats *) This; - - GDK_NOTE (DND, g_print ("ienumformatetc_reset %p S_OK\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 %p S_OK\n", This)); - - new = enum_formats_new (en->dataobj); - - new->ix = en->ix; - - *ppEnumFormatEtc = &new->ief; - - return S_OK; -} - -static IDropTargetVtbl idt_vtbl = { - idroptarget_queryinterface, - idroptarget_addref, - idroptarget_release, - idroptarget_dragenter, - idroptarget_dragover, - idroptarget_dragleave, - idroptarget_drop -}; - -static IDropSourceVtbl ids_vtbl = { - 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 -}; - - -static target_drag_context * -target_context_new (GdkSurface *window) -{ - target_drag_context *result; - - result = g_new0 (target_drag_context, 1); - result->idt.lpVtbl = &idt_vtbl; - result->ref_count = 0; - - result->dest_surface = g_object_ref (window); - - idroptarget_addref (&result->idt); - - GDK_NOTE (DND, g_print ("target_context_new: %p (window %p)\n", result, result->dest_surface)); - - return result; -} - -static source_drag_context * -source_context_new (GdkDragContext *context, - GdkSurface *window, - GdkContentFormats *formats) -{ - GdkWin32DragContext *context_win32; - source_drag_context *result; - - context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - - result = g_new0 (source_drag_context, 1); - result->context = g_object_ref (context); - result->ids.lpVtbl = &ids_vtbl; - result->ref_count = 0; - - idropsource_addref (&result->ids); - - GDK_NOTE (DND, g_print ("source_context_new: %p (drag context %p)\n", result, result->context)); - - if (current_src_context == NULL) - current_src_context = result; - - return result; -} - -static data_object * -data_object_new (GdkDragContext *context) -{ - data_object *result; - GList *p; - const char * const *mime_types; - gsize n_mime_types, i; - - result = g_new0 (data_object, 1); - - result->ido.lpVtbl = &ido_vtbl; - result->ref_count = 1; - result->context = context; - result->formats = g_array_new (FALSE, FALSE, sizeof (GdkSelTargetFormat)); - - mime_types = gdk_content_formats_get_mime_types (context->formats, &n_mime_types); - - for (i = 0; i < n_mime_types; i++) - { - gint added_count = 0; - gint j; - - GDK_NOTE (DND, g_print ("DataObject supports target 0x%p\n", mime_types[i])); - - added_count = _gdk_win32_add_target_to_selformats (mime_types[i], result->formats); - - for (j = 0; j < added_count && result->formats->len - 1 - j >= 0; j++) - GDK_NOTE (DND, g_print ("DataObject will support format 0x%x\n", g_array_index (result->formats, GdkSelTargetFormat, j).format)); - } - - GDK_NOTE (DND, g_print ("data_object_new: %p\n", result)); - - return result; -} - -static enum_formats * -enum_formats_new (data_object *dataobj) -{ - enum_formats *result; - - result = g_new0 (enum_formats, 1); - - result->ief.lpVtbl = &ief_vtbl; - result->ref_count = 1; - result->ix = 0; - result->dataobj = dataobj; - idataobject_addref ((LPDATAOBJECT) dataobj); - - return result; -} - -/* From MS Knowledge Base article Q130698 */ - -static gboolean -resolve_link (HWND hWnd, - wchar_t *link, - gchar **lpszPath) -{ - WIN32_FILE_ATTRIBUTE_DATA wfad; - HRESULT hr; - IShellLinkW *pslW = NULL; - IPersistFile *ppf = NULL; - - /* Check if the file is empty first because IShellLink::Resolve for - * some reason succeeds with an empty file and returns an empty - * "link target". (#524151) - */ - if (!GetFileAttributesExW (link, GetFileExInfoStandard, &wfad) || - (wfad.nFileSizeHigh == 0 && wfad.nFileSizeLow == 0)) - return FALSE; - - /* Assume failure to start with: */ - *lpszPath = 0; - - /* Call CoCreateInstance to obtain the IShellLink interface - * pointer. This call fails if CoInitialize is not called, so it is - * assumed that CoInitialize has been called. - */ - - hr = CoCreateInstance (&CLSID_ShellLink, - NULL, - CLSCTX_INPROC_SERVER, - &IID_IShellLinkW, - (LPVOID *)&pslW); - - if (SUCCEEDED (hr)) - { - /* The IShellLink interface supports the IPersistFile - * interface. Get an interface pointer to it. - */ - hr = pslW->lpVtbl->QueryInterface (pslW, - &IID_IPersistFile, - (LPVOID *) &ppf); - } - - if (SUCCEEDED (hr)) - { - /* Load the file. */ - hr = ppf->lpVtbl->Load (ppf, link, STGM_READ); - } - - if (SUCCEEDED (hr)) - { - /* Resolve the link by calling the Resolve() - * interface function. - */ - hr = pslW->lpVtbl->Resolve (pslW, hWnd, SLR_ANY_MATCH | SLR_NO_UI); - } - - if (SUCCEEDED (hr)) - { - wchar_t wtarget[MAX_PATH]; - - 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 (hr); -} - -#if 0 - -/* Check for filenames like C:\Users\tml\AppData\Local\Temp\d5qtkvvs.bmp */ -static gboolean -filename_looks_tempish (const char *filename) -{ - char *dirname; - char *p; - const char *q; - gboolean retval = FALSE; - - dirname = g_path_get_dirname (filename); - - p = dirname; - q = g_get_tmp_dir (); - - while (*p && *q && - ((G_IS_DIR_SEPARATOR (*p) && G_IS_DIR_SEPARATOR (*q)) || - g_ascii_tolower (*p) == g_ascii_tolower (*q))) - p++, q++; - - if (!*p && !*q) - retval = TRUE; - - g_free (dirname); - - return retval; -} - -static gboolean -close_it (gpointer data) -{ - close (GPOINTER_TO_INT (data)); - - return FALSE; -} - -#endif - -static GdkFilterReturn -gdk_dropfiles_filter (GdkXEvent *xev, - GdkEvent *event, - gpointer data) -{ - GdkDragContext *context; - GdkWin32DragContext *context_win32; - GString *result; - MSG *msg = (MSG *) xev; - HANDLE hdrop; - POINT pt; - gint nfiles, i; - gchar *fileName, *linkedFile; - GPtrArray *formats; - - formats = g_ptr_array_new (); - - if (msg->message == WM_DROPFILES) - { - GDK_NOTE (DND, g_print ("WM_DROPFILES: %p\n", msg->hwnd)); - - context = gdk_drag_context_new (gdk_surface_get_display (event->any.surface), - FALSE, - NULL, - event->any.surface, - GDK_ACTION_COPY, - NULL, - GDK_DRAG_PROTO_WIN32_DROPFILES); - context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - /* WM_DROPFILES drops are always file names */ - context->formats = gdk_content_formats_new ((const char *[2]) { - "text/uri-list", - NULL - }, 1); - - - context->suggested_action = GDK_ACTION_COPY; - current_dest_drag = context; - - event->dnd.type = GDK_DROP_START; - event->dnd.context = current_dest_drag; - gdk_event_set_device (event, gdk_drag_context_get_device (current_dest_drag)); - gdk_event_set_seat (event, gdk_device_get_seat (gdk_drag_context_get_device (current_dest_drag))); - - hdrop = (HANDLE) msg->wParam; - DragQueryPoint (hdrop, &pt); - ClientToScreen (msg->hwnd, &pt); - - event->dnd.x_root = pt.x / context_win32->scale + _gdk_offset_x; - event->dnd.y_root = pt.y / context_win32->scale + _gdk_offset_y; - 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++) - { - gchar *uri; - wchar_t wfn[MAX_PATH]; - - DragQueryFileW (hdrop, i, wfn, MAX_PATH); - fileName = g_utf16_to_utf8 (wfn, -1, NULL, NULL, NULL); - - /* Resolve shortcuts */ - if (resolve_link (msg->hwnd, wfn, &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); - } - g_free (fileName); - fileName = linkedFile; - } - else - { - 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); - } - } - -#if 0 - /* Awful hack to recognize temp files corresponding to - * images dragged from Firefox... Open the file right here - * so that it is less likely that Firefox manages to delete - * it before the GTK+-using app (typically GIMP) has opened - * it. - * - * Not compiled in for now, because it means images dragged - * from Firefox would stay around in the temp folder which - * is not what Firefox intended. I don't feel comfortable - * with that, both from a geenral sanity point of view, and - * from a privacy point of view. It's better to wait for - * Firefox to fix the problem, for instance by deleting the - * temp file after a longer delay, or to wait until we - * implement the OLE2_DND... - */ - if (filename_looks_tempish (fileName)) - { - int fd = g_open (fileName, _O_RDONLY|_O_BINARY, 0); - if (fd == -1) - { - GDK_NOTE (DND, g_print ("Could not open %s, maybe an image dragged from Firefox that it already deleted\n", fileName)); - } - else - { - GDK_NOTE (DND, g_print ("Opened %s as %d so that Firefox won't delete it\n", fileName, fd)); - g_timeout_add_seconds (1, close_it, GINT_TO_POINTER (fd)); - } - } -#endif - - g_free (fileName); - g_string_append (result, "\015\012"); - } - _gdk_dropfiles_store (result->str); - g_string_free (result, FALSE); - - DragFinish (hdrop); - - return GDK_FILTER_TRANSLATE; - } - else - return GDK_FILTER_CONTINUE; -} - - - -void -_gdk_dnd_init (void) -{ - CoInitializeEx (NULL, COINIT_APARTMENTTHREADED); - - if (getenv ("GDK_WIN32_USE_EXPERIMENTAL_OLE2_DND")) - use_ole2_dnd = TRUE; - - if (use_ole2_dnd) - { - HRESULT hr; - - hr = OleInitialize (NULL); - - if (! SUCCEEDED (hr)) - g_error ("OleInitialize failed"); - - target_ctx_for_surface = g_hash_table_new (g_direct_hash, g_direct_equal); - } -} - -void -_gdk_win32_dnd_exit (void) -{ - if (use_ole2_dnd) - { - OleUninitialize (); - } - - CoUninitialize (); -} - -/* Source side */ - -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)); - - if ((current_dest_drag != NULL) && - (GDK_WIN32_DRAG_CONTEXT (current_dest_drag)->protocol == GDK_DRAG_PROTO_LOCAL) && - (current_dest_drag->source_surface == context->source_surface)) - { - tmp_event = gdk_event_new (GDK_DRAG_LEAVE); - - g_set_object (&tmp_event->dnd.window, context->dest_surface); - /* Pass ownership of context to the event */ - tmp_event->dnd.send_event = FALSE; - g_set_object (&tmp_event->dnd.context, current_dest_drag); - tmp_event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */ - gdk_event_set_device (tmp_event, gdk_drag_context_get_device (context)); - gdk_event_set_seat (tmp_event, gdk_device_get_seat (gdk_drag_context_get_device (context))); - - current_dest_drag = NULL; - - GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event)); - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (context)), tmp_event); - gdk_event_free (tmp_event); - } -} - -static void -local_send_enter (GdkDragContext *context, - guint32 time) -{ - GdkEvent *tmp_event; - GdkDragContext *new_context; - - GDK_NOTE (DND, g_print ("local_send_enter: context=%p current_dest_drag=%p\n", - context, - current_dest_drag)); - - if (current_dest_drag != NULL) - { - g_object_unref (G_OBJECT (current_dest_drag)); - current_dest_drag = NULL; - } - - new_context = gdk_drag_context_new (gdk_surface_get_display (context->source_surface), - FALSE, - context->source_surface, - context->dest_surface, - context->actions, - NULL, - GDK_DRAG_PROTO_LOCAL); - new_context->formats = gdk_content_formats_ref (context->formats); - - gdk_surface_set_events (new_context->source_surface, - gdk_surface_get_events (new_context->source_surface) | - GDK_PROPERTY_CHANGE_MASK); - - tmp_event = gdk_event_new (GDK_DRAG_ENTER); - g_set_object (&tmp_event->dnd.window, context->dest_surface); - tmp_event->dnd.send_event = FALSE; - g_set_object (&tmp_event->dnd.context, new_context); - tmp_event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */ - gdk_event_set_device (tmp_event, gdk_drag_context_get_device (context)); - gdk_event_set_seat (tmp_event, gdk_device_get_seat (gdk_drag_context_get_device (context))); - - current_dest_drag = new_context; - - GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event)); - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (context)), tmp_event); - gdk_event_free (tmp_event); -} - -static void -local_send_motion (GdkDragContext *context, - gint x_root, - gint y_root, - GdkDragAction action, - guint32 time) -{ - GdkEvent *tmp_event; - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (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) && - (GDK_WIN32_DRAG_CONTEXT (current_dest_drag)->protocol == GDK_DRAG_PROTO_LOCAL) && - (current_dest_drag->source_surface == context->source_surface)) - { - GdkWin32DragContext *current_dest_drag_win32; - - tmp_event = gdk_event_new (GDK_DRAG_MOTION); - g_set_object (&tmp_event->dnd.window, current_dest_drag->dest_surface); - tmp_event->dnd.send_event = FALSE; - g_set_object (&tmp_event->dnd.context, current_dest_drag); - tmp_event->dnd.time = time; - gdk_event_set_device (tmp_event, gdk_drag_context_get_device (current_dest_drag)); - gdk_event_set_seat (tmp_event, gdk_device_get_seat (gdk_drag_context_get_device (current_dest_drag))); - - current_dest_drag->suggested_action = action; - - tmp_event->dnd.x_root = x_root; - tmp_event->dnd.y_root = y_root; - - current_dest_drag_win32 = GDK_WIN32_DRAG_CONTEXT (current_dest_drag); - current_dest_drag_win32->last_x = x_root; - current_dest_drag_win32->last_y = y_root; - - context_win32->drag_status = GDK_DRAG_STATUS_MOTION_WAIT; - - GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event)); - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (context)), tmp_event); - gdk_event_free (tmp_event); - } -} - -static void -local_send_drop (GdkDragContext *context, - guint32 time) -{ - GdkEvent *tmp_event; - - GDK_NOTE (DND, g_print ("local_send_drop: context=%p current_dest_drag=%p\n", - context, - current_dest_drag)); - - if ((current_dest_drag != NULL) && - (GDK_WIN32_DRAG_CONTEXT (current_dest_drag)->protocol == GDK_DRAG_PROTO_LOCAL) && - (current_dest_drag->source_surface == context->source_surface)) - { - GdkWin32DragContext *context_win32; - - /* Pass ownership of context to the event */ - tmp_event = gdk_event_new (GDK_DROP_START); - g_set_object (&tmp_event->dnd.window, current_dest_drag->dest_surface); - tmp_event->dnd.send_event = FALSE; - g_set_object (&tmp_event->dnd.context, current_dest_drag); - tmp_event->dnd.time = GDK_CURRENT_TIME; - gdk_event_set_device (tmp_event, gdk_drag_context_get_device (current_dest_drag)); - gdk_event_set_seat (tmp_event, gdk_device_get_seat (gdk_drag_context_get_device (current_dest_drag))); - - context_win32 = GDK_WIN32_DRAG_CONTEXT (current_dest_drag); - tmp_event->dnd.x_root = context_win32->last_x; - tmp_event->dnd.y_root = context_win32->last_y; - - current_dest_drag = NULL; - - GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event)); - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (context)), tmp_event); - gdk_event_free (tmp_event); - } - -} - -static void -gdk_drag_do_leave (GdkDragContext *context, - guint32 time) -{ - if (context->dest_surface) - { - GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n")); - - if (!use_ole2_dnd) - { - if (GDK_WIN32_DRAG_CONTEXT (context)->protocol == GDK_DRAG_PROTO_LOCAL) - local_send_leave (context, time); - } - - g_clear_object (&context->dest_surface); - } -} - -static GdkSurface * -create_drag_surface (GdkDisplay *display) -{ - GdkSurface *window; - - window = gdk_surface_new_popup (display, &(GdkRectangle) { 0, 0, 100, 100 }); - - gdk_surface_set_type_hint (window, GDK_SURFACE_TYPE_HINT_DND); - - return window; -} - -GdkDragContext * -_gdk_win32_surface_drag_begin (GdkSurface *window, - GdkDevice *device, - GdkContentFormats *formats, - GdkDragAction actions, - gint dx, - gint dy) -{ - GdkDragContext *context; - GdkWin32DragContext *context_win32; - BYTE kbd_state[256]; - GdkWin32Selection *sel_win32 = _gdk_win32_selection_get (); - int x_root, y_root; - - g_return_val_if_fail (window != NULL, NULL); - - if (use_ole2_dnd) - g_assert (pending_src_context == NULL); - - context = gdk_drag_context_new (gdk_surface_get_display (window), - TRUE, - window, - NULL, - actions, - device, - use_ole2_dnd ? GDK_DRAG_PROTO_OLE2 : GDK_DRAG_PROTO_LOCAL); - context->formats = gdk_content_formats_ref (formats); - - context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - - GDK_NOTE (DND, g_print ("gdk_drag_begin\n")); - - gdk_device_get_position (device, &x_root, &y_root); - x_root += dx; - y_root += dy; - - context_win32->start_x = x_root; - context_win32->start_y = y_root; - context_win32->last_x = context_win32->start_x; - context_win32->last_y = context_win32->start_y; - - g_set_object (&context_win32->ipc_window, window); - - context_win32->last_key_state = 0; - API_CALL (GetKeyboardState, (kbd_state)); - - if (kbd_state[VK_CONTROL] & 0x80) - context_win32->last_key_state |= MK_CONTROL; - if (kbd_state[VK_SHIFT] & 0x80) - context_win32->last_key_state |= MK_SHIFT; - if (kbd_state[VK_LBUTTON] & 0x80) - context_win32->last_key_state |= MK_LBUTTON; - if (kbd_state[VK_MBUTTON] & 0x80) - context_win32->last_key_state |= MK_MBUTTON; - if (kbd_state[VK_RBUTTON] & 0x80) - context_win32->last_key_state |= MK_RBUTTON; - - context_win32->drag_surface = create_drag_surface (gdk_surface_get_display (window)); - - if (!drag_context_grab (context)) - { - g_object_unref (context); - return FALSE; - } - - if (use_ole2_dnd) - { - pending_src_context = source_context_new (context, window, formats); - - sel_win32->dnd_source_state = GDK_WIN32_DND_PENDING; - } - - move_drag_surface (context, x_root, y_root); - - return context; -} - -void -_gdk_win32_dnd_do_dragdrop (void) -{ - GdkDragContext* drag_ctx; - data_object *dobj; - HRESULT hr; - DWORD dwEffect; - - if (!use_ole2_dnd) - return; - - if (pending_src_context == NULL) - return; - - drag_ctx = pending_src_context->context; - - dobj = data_object_new (drag_ctx); - current_src_object = dobj; - - /* Start dragging with mainloop inside the OLE2 API. Exits only when done */ - - GDK_NOTE (DND, g_print ("Calling DoDragDrop\n")); - - _gdk_win32_begin_modal_call (GDK_WIN32_MODAL_OP_DND); - hr = DoDragDrop (&dobj->ido, &pending_src_context->ids, - DROPEFFECT_COPY | DROPEFFECT_MOVE, - &dwEffect); - _gdk_win32_end_modal_call (GDK_WIN32_MODAL_OP_DND); - - 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)))))); - - /* Delete dnd selection after successful move */ - if (hr == DRAGDROP_S_DROP && dwEffect == DROPEFFECT_MOVE) - { - GdkWin32Selection *win32_sel = _gdk_win32_selection_get (); - GdkEvent tmp_event; - - memset (&tmp_event, 0, sizeof (tmp_event)); - tmp_event.type = GDK_SELECTION_REQUEST; - g_set_object (&tmp_event.selection.window, drag_ctx->source_surface); - tmp_event.selection.send_event = FALSE; - tmp_event.selection.selection = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_OLE2_DND); - tmp_event.selection.target = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_DELETE); - win32_sel->property_change_target_atom = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_DELETE); - tmp_event.selection.property = _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_OLE2_DND); - g_set_object (&tmp_event.selection.requestor, drag_ctx->source_surface); - tmp_event.selection.time = GDK_CURRENT_TIME; /* ??? */ - - GDK_NOTE (EVENTS, _gdk_win32_print_event (&tmp_event)); - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (drag_ctx)), &tmp_event); - } - - { - GdkEvent *tmp_event; - tmp_event = gdk_event_new (GDK_DROP_FINISHED); - g_set_object (&tmp_event->dnd.window, drag_ctx->source_surface); - tmp_event->dnd.send_event = FALSE; - g_set_object (&tmp_event->dnd.context, drag_ctx); - gdk_event_set_device (tmp_event, gdk_drag_context_get_device (drag_ctx)); - gdk_event_set_seat (tmp_event, gdk_device_get_seat (gdk_drag_context_get_device (drag_ctx))); - - GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event)); - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (drag_ctx)), tmp_event); - gdk_event_free (tmp_event); - } - - current_src_object = NULL; - 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; - } -} - -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; -} - -static GdkSurface * -gdk_win32_drag_context_find_window (GdkDragContext *context, - GdkSurface *drag_surface, - gint x_root, - gint y_root, - GdkDragProtocol *protocol) -{ - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - GdkSurface *dest_surface, *dw; - find_window_enum_arg a; - - a.x = x_root * context_win32->scale - _gdk_offset_x; - a.y = y_root * context_win32->scale - _gdk_offset_y; - a.ignore = drag_surface ? GDK_SURFACE_HWND (drag_surface) : NULL; - a.result = NULL; - - GDK_NOTE (DND, - g_print ("gdk_drag_find_window_real: %p %+d%+d\n", - (drag_surface ? GDK_SURFACE_HWND (drag_surface) : NULL), - a.x, a.y)); - - EnumWindows (find_window_enum_proc, (LPARAM) &a); - - if (a.result == NULL) - dest_surface = NULL; - else - { - dw = gdk_win32_handle_table_lookup (a.result); - if (dw) - { - dest_surface = gdk_surface_get_toplevel (dw); - g_object_ref (dest_surface); - } - else - dest_surface = gdk_win32_surface_foreign_new_for_display (gdk_drag_context_get_display (context), a.result); - - if (use_ole2_dnd) - *protocol = GDK_DRAG_PROTO_OLE2; - else if (context->source_surface) - *protocol = GDK_DRAG_PROTO_LOCAL; - else - *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES; - } - - GDK_NOTE (DND, - g_print ("gdk_drag_find_window: %p %+d%+d: %p: %p %s\n", - (drag_surface ? GDK_SURFACE_HWND (drag_surface) : NULL), - x_root, y_root, - a.result, - (dest_surface ? GDK_SURFACE_HWND (dest_surface) : NULL), - _gdk_win32_drag_protocol_to_string (*protocol))); - - return dest_surface; -} - -static gboolean -gdk_win32_drag_context_drag_motion (GdkDragContext *context, - GdkSurface *dest_surface, - GdkDragProtocol protocol, - gint x_root, - gint y_root, - GdkDragAction suggested_action, - GdkDragAction possible_actions, - guint32 time) -{ - GdkWin32DragContext *context_win32; - - g_return_val_if_fail (context != NULL, FALSE); - - context->actions = possible_actions; - - GDK_NOTE (DND, g_print ("gdk_drag_motion: @ %+d:%+d %s suggested=%s, possible=%s\n" - " context=%p:{actions=%s,suggested=%s,action=%s}\n", - x_root, y_root, - _gdk_win32_drag_protocol_to_string (protocol), - _gdk_win32_drag_action_to_string (suggested_action), - _gdk_win32_drag_action_to_string (possible_actions), - 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_win32 = GDK_WIN32_DRAG_CONTEXT (context); - - if (context_win32->drag_surface) - move_drag_surface (context, x_root, y_root); - - if (!use_ole2_dnd) - { - if (context->dest_surface == dest_surface) - { - GdkDragContext *dest_context; - - dest_context = gdk_drag_context_find (FALSE, - context->source_surface, - dest_surface); - - if (dest_context) - dest_context->actions = context->actions; - - context->suggested_action = suggested_action; - } - else - { - GdkEvent *tmp_event; - - /* Send a leave to the last destination */ - gdk_drag_do_leave (context, time); - context_win32->drag_status = GDK_DRAG_STATUS_DRAG; - - /* Check if new destination accepts drags, and which protocol */ - if (dest_surface) - { - g_set_object (&context->dest_surface, dest_surface); - context_win32->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_surface = NULL; - context->action = 0; - } - - /* Push a status event, to let the client know that - * the drag changed - */ - tmp_event = gdk_event_new (GDK_DRAG_STATUS); - g_set_object (&tmp_event->dnd.window, context->source_surface); - /* We use this to signal a synthetic status. Perhaps - * we should use an extra field... - */ - tmp_event->dnd.send_event = TRUE; - - g_set_object (&tmp_event->dnd.context, context); - tmp_event->dnd.time = time; - gdk_event_set_device (tmp_event, gdk_drag_context_get_device (context)); - gdk_event_set_seat (tmp_event, gdk_device_get_seat (gdk_drag_context_get_device (context))); - - GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event)); - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (context)), tmp_event); - gdk_event_free (tmp_event); - } - - /* Send a drag-motion event */ - - context_win32->last_x = x_root; - context_win32->last_y = y_root; - - if (context->dest_surface) - { - if (context_win32->drag_status == GDK_DRAG_STATUS_DRAG) - { - switch (context_win32->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 - { - GDK_NOTE (DND, g_print (" returning TRUE\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), - _gdk_win32_drag_action_to_string (context->action))); - return TRUE; - } - } - } - - GDK_NOTE (DND, g_print (" returning FALSE\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), - _gdk_win32_drag_action_to_string (context->action))); - return FALSE; -} - -static void -gdk_win32_drag_context_drag_drop (GdkDragContext *context, - guint32 time) -{ - GdkWin32Selection *sel_win32 = _gdk_win32_selection_get (); - - g_return_if_fail (context != NULL); - - GDK_NOTE (DND, g_print ("gdk_drag_drop\n")); - - if (!use_ole2_dnd) - { - if (context->dest_surface && - GDK_WIN32_DRAG_CONTEXT (context)->protocol == GDK_DRAG_PROTO_LOCAL) - local_send_drop (context, time); - } - else - { - sel_win32->dnd_source_state = GDK_WIN32_DND_DROPPED; - } -} - -static void -gdk_win32_drag_context_drag_abort (GdkDragContext *context, - guint32 time) -{ - GdkWin32Selection *sel_win32 = _gdk_win32_selection_get (); - - g_return_if_fail (context != NULL); - - GDK_NOTE (DND, g_print ("gdk_drag_abort\n")); - - if (use_ole2_dnd) - sel_win32->dnd_source_state = GDK_WIN32_DND_NONE; -} - -/* Destination side */ - -static void -gdk_win32_drag_context_drag_status (GdkDragContext *context, - GdkDragAction action, - guint32 time) -{ - GdkDragContext *src_context; - GdkEvent *tmp_event; - - g_return_if_fail (context != NULL); - - 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; - - if (!use_ole2_dnd) - { - src_context = gdk_drag_context_find (TRUE, - context->source_surface, - context->dest_surface); - - if (src_context) - { - GdkWin32DragContext *src_context_win32 = GDK_WIN32_DRAG_CONTEXT (src_context); - - if (src_context_win32->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) - src_context_win32->drag_status = GDK_DRAG_STATUS_DRAG; - - tmp_event = gdk_event_new (GDK_DRAG_STATUS); - g_set_object (&tmp_event->dnd.window, context->source_surface); - tmp_event->dnd.send_event = FALSE; - g_set_object (&tmp_event->dnd.context, src_context); - tmp_event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */ - gdk_event_set_device (tmp_event, gdk_drag_context_get_device (src_context)); - gdk_event_set_seat (tmp_event, gdk_device_get_seat (gdk_drag_context_get_device (src_context))); - - if (action == GDK_ACTION_DEFAULT) - action = 0; - - src_context->action = action; - - GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event)); - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (src_context)), tmp_event); - gdk_event_free (tmp_event); - } - } -} - -static void -gdk_win32_drag_context_drop_finish (GdkDragContext *context, - gboolean success, - guint32 time) -{ - GdkDragContext *src_context; - GdkEvent *tmp_event; - GdkWin32Selection *sel_win32 = _gdk_win32_selection_get (); - - g_return_if_fail (context != NULL); - - GDK_NOTE (DND, g_print ("gdk_drop_finish\n")); - - if (!use_ole2_dnd) - { - src_context = gdk_drag_context_find (TRUE, - context->source_surface, - context->dest_surface); - if (src_context) - { - tmp_event = gdk_event_new (GDK_DROP_FINISHED); - g_set_object (&tmp_event->dnd.window, src_context->source_surface); - tmp_event->dnd.send_event = FALSE; - g_set_object (&tmp_event->dnd.context, src_context); - gdk_event_set_device (tmp_event, gdk_drag_context_get_device (src_context)); - gdk_event_set_seat (tmp_event, gdk_device_get_seat (gdk_drag_context_get_device (src_context))); - - GDK_NOTE (EVENTS, _gdk_win32_print_event (tmp_event)); - _gdk_display_put_event (gdk_device_get_display (gdk_drag_context_get_device (src_context)), tmp_event); - gdk_event_free (tmp_event); - } - } - else - { - gdk_drag_do_leave (context, time); - - if (success) - sel_win32->dnd_target_state = GDK_WIN32_DND_DROPPED; - else - sel_win32->dnd_target_state = GDK_WIN32_DND_FAILED; - } -} - -#if 0 - -static GdkFilterReturn -gdk_destroy_filter (GdkXEvent *xev, - GdkEvent *event, - gpointer data) -{ - MSG *msg = (MSG *) xev; - - if (msg->message == WM_DESTROY) - { - IDropTarget *idtp = (IDropTarget *) data; - - GDK_NOTE (DND, g_print ("gdk_destroy_filter: WM_DESTROY: %p\n", msg->hwnd)); -#if 0 - idtp->lpVtbl->Release (idtp); -#endif - RevokeDragDrop (msg->hwnd); - CoLockObjectExternal ((IUnknown*) idtp, FALSE, TRUE); - } - return GDK_FILTER_CONTINUE; -} - -#endif - -void -_gdk_win32_surface_register_dnd (GdkSurface *window) -{ - target_drag_context *ctx; - HRESULT hr; - - g_return_if_fail (window != NULL); - - if (g_object_get_data (G_OBJECT (window), "gdk-dnd-registered") != NULL) - return; - else - g_object_set_data (G_OBJECT (window), "gdk-dnd-registered", GINT_TO_POINTER (TRUE)); - - GDK_NOTE (DND, g_print ("gdk_surface_register_dnd: %p\n", GDK_SURFACE_HWND (window))); - - if (!use_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 - * (in gtk, data of type text/uri-list) or not. - */ - gdk_surface_add_filter (window, gdk_dropfiles_filter, NULL); - DragAcceptFiles (GDK_SURFACE_HWND (window), TRUE); - } - else - { - /* Return if window is already setup for DND. */ - if (g_hash_table_lookup (target_ctx_for_surface, GDK_SURFACE_HWND (window)) != NULL) - return; - - ctx = target_context_new (window); - - hr = CoLockObjectExternal ((IUnknown *) &ctx->idt, TRUE, FALSE); - if (!SUCCEEDED (hr)) - OTHER_API_FAILED ("CoLockObjectExternal"); - else - { - hr = RegisterDragDrop (GDK_SURFACE_HWND (window), &ctx->idt); - if (hr == DRAGDROP_E_ALREADYREGISTERED) - { - g_print ("DRAGDROP_E_ALREADYREGISTERED\n"); - CoLockObjectExternal ((IUnknown *) &ctx->idt, FALSE, FALSE); - } - else if (!SUCCEEDED (hr)) - OTHER_API_FAILED ("RegisterDragDrop"); - else - { - g_object_ref (window); - g_hash_table_insert (target_ctx_for_surface, GDK_SURFACE_HWND (window), ctx); - } - } - } -} - -static GdkAtom -gdk_win32_drag_context_get_selection (GdkDragContext *context) -{ - switch (GDK_WIN32_DRAG_CONTEXT (context)->protocol) - { - case GDK_DRAG_PROTO_LOCAL: - return _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_LOCAL_DND_SELECTION); - case GDK_DRAG_PROTO_WIN32_DROPFILES: - return _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_DROPFILES_DND); - case GDK_DRAG_PROTO_OLE2: - return _gdk_win32_selection_atom (GDK_WIN32_ATOM_INDEX_OLE2_DND); - default: - return NULL; - } -} - -static void -gdk_win32_drag_context_set_cursor (GdkDragContext *context, - GdkCursor *cursor) -{ - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - - GDK_NOTE (DND, g_print ("gdk_drag_context_set_cursor: 0x%p 0x%p\n", context, cursor)); - - if (!g_set_object (&context_win32->cursor, cursor)) - return; - - if (context_win32->grab_seat) - { - G_GNUC_BEGIN_IGNORE_DEPRECATIONS; - gdk_device_grab (gdk_seat_get_pointer (context_win32->grab_seat), - context_win32->ipc_window, - GDK_OWNERSHIP_APPLICATION, FALSE, - GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, - cursor, GDK_CURRENT_TIME); - G_GNUC_END_IGNORE_DEPRECATIONS; - } -} - -static double -ease_out_cubic (double t) -{ - double p = t - 1; - return p * p * p + 1; -} - -#define ANIM_TIME 500000 /* half a second */ - -typedef struct _GdkDragAnim GdkDragAnim; -struct _GdkDragAnim { - GdkWin32DragContext *context; - GdkFrameClock *frame_clock; - gint64 start_time; -}; - -static void -gdk_drag_anim_destroy (GdkDragAnim *anim) -{ - g_object_unref (anim->context); - g_slice_free (GdkDragAnim, anim); -} - -static gboolean -gdk_drag_anim_timeout (gpointer data) -{ - GdkDragAnim *anim = data; - GdkWin32DragContext *context = anim->context; - GdkFrameClock *frame_clock = anim->frame_clock; - gint64 current_time; - double f; - double t; - - if (!frame_clock) - return G_SOURCE_REMOVE; - - current_time = gdk_frame_clock_get_frame_time (frame_clock); - - f = (current_time - anim->start_time) / (double) ANIM_TIME; - - if (f >= 1.0) - return G_SOURCE_REMOVE; - - t = ease_out_cubic (f); - - gdk_surface_show (context->drag_surface); - gdk_surface_move (context->drag_surface, - context->last_x + (context->start_x - context->last_x) * t - context->hot_x, - context->last_y + (context->start_y - context->last_y) * t - context->hot_y); - gdk_surface_set_opacity (context->drag_surface, 1.0 - f); - - return G_SOURCE_CONTINUE; -} - -static void -gdk_win32_drag_context_drop_done (GdkDragContext *context, - gboolean success) -{ - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); - GdkDragAnim *anim; - cairo_surface_t *win_surface; - cairo_surface_t *surface; - cairo_t *cr; - guint id; - - GDK_NOTE (DND, g_print ("gdk_drag_context_drop_done: 0x%p %s\n", - context, - success ? "dropped successfully" : "dropped unsuccessfully")); - - /* FIXME: This is temporary, until the code is fixed to ensure that - * gdk_drop_finish () is called by GTK. - */ - if (use_ole2_dnd) - { - GdkWin32Selection *sel_win32 = _gdk_win32_selection_get (); - - if (success) - sel_win32->dnd_source_state = GDK_WIN32_DND_DROPPED; - else - sel_win32->dnd_source_state = GDK_WIN32_DND_NONE; - } - - if (success) - { - gdk_surface_hide (win32_context->drag_surface); - return; - } - - win_surface = _gdk_surface_ref_cairo_surface (win32_context->drag_surface); - surface = gdk_surface_create_similar_surface (win32_context->drag_surface, - cairo_surface_get_content (win_surface), - gdk_surface_get_width (win32_context->drag_surface), - gdk_surface_get_height (win32_context->drag_surface)); - cr = cairo_create (surface); - cairo_set_source_surface (cr, win_surface, 0, 0); - cairo_paint (cr); - cairo_destroy (cr); - cairo_surface_destroy (win_surface); - -/* - pattern = cairo_pattern_create_for_surface (surface); - - gdk_surface_set_background_pattern (win32_context->drag_surface, pattern); - - cairo_pattern_destroy (pattern); -*/ - cairo_surface_destroy (surface); - - anim = g_slice_new0 (GdkDragAnim); - g_set_object (&anim->context, win32_context); - anim->frame_clock = gdk_surface_get_frame_clock (win32_context->drag_surface); - anim->start_time = gdk_frame_clock_get_frame_time (anim->frame_clock); - - id = g_timeout_add_full (G_PRIORITY_DEFAULT, 17, - gdk_drag_anim_timeout, anim, - (GDestroyNotify) gdk_drag_anim_destroy); - g_source_set_name_by_id (id, "[gtk+] gdk_drag_anim_timeout"); -} - -static gboolean -drag_context_grab (GdkDragContext *context) -{ - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - GdkSeatCapabilities capabilities; - GdkSeat *seat; - GdkCursor *cursor; - - if (!context_win32->ipc_window) - return FALSE; - - seat = gdk_device_get_seat (gdk_drag_context_get_device (context)); - - capabilities = GDK_SEAT_CAPABILITY_ALL; - - cursor = gdk_drag_get_cursor (context, gdk_drag_context_get_selected_action (context)); - g_set_object (&context_win32->cursor, cursor); - - if (gdk_seat_grab (seat, context_win32->ipc_window, - capabilities, FALSE, - context_win32->cursor, NULL, NULL, NULL) != GDK_GRAB_SUCCESS) - return FALSE; - - g_set_object (&context_win32->grab_seat, seat); - - /* TODO: Should be grabbing keys here, to support keynav. SetWindowsHookEx()? */ - - return TRUE; -} - -static void -drag_context_ungrab (GdkDragContext *context) -{ - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - - if (!context_win32->grab_seat) - return; - - gdk_seat_ungrab (context_win32->grab_seat); - - g_clear_object (&context_win32->grab_seat); - - /* TODO: Should be ungrabbing keys here */ -} - -static void -gdk_win32_drag_context_cancel (GdkDragContext *context, - GdkDragCancelReason reason) -{ - const gchar *reason_str = NULL; - switch (reason) - { - case GDK_DRAG_CANCEL_NO_TARGET: - reason_str = "no target"; - break; - case GDK_DRAG_CANCEL_USER_CANCELLED: - reason_str = "user cancelled"; - break; - case GDK_DRAG_CANCEL_ERROR: - reason_str = "error"; - break; - default: - reason_str = ""; - break; - } - - GDK_NOTE (DND, g_print ("gdk_drag_context_cancel: 0x%p %s\n", - context, - reason_str)); - drag_context_ungrab (context); - gdk_drag_drop_done (context, FALSE); -} - -static void -gdk_win32_drag_context_drop_performed (GdkDragContext *context, - guint32 time_) -{ - GDK_NOTE (DND, g_print ("gdk_drag_context_drop_performed: 0x%p %u\n", - context, - time_)); - gdk_drag_drop (context, time_); - drag_context_ungrab (context); -} - -#define BIG_STEP 20 -#define SMALL_STEP 1 - -static void -gdk_drag_get_current_actions (GdkModifierType state, - gint button, - GdkDragAction actions, - GdkDragAction *suggested_action, - GdkDragAction *possible_actions) -{ - *suggested_action = 0; - *possible_actions = 0; - - if ((button == GDK_BUTTON_MIDDLE || button == GDK_BUTTON_SECONDARY) && (actions & GDK_ACTION_ASK)) - { - *suggested_action = GDK_ACTION_ASK; - *possible_actions = actions; - } - else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) - { - if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK)) - { - if (actions & GDK_ACTION_LINK) - { - *suggested_action = GDK_ACTION_LINK; - *possible_actions = GDK_ACTION_LINK; - } - } - else if (state & GDK_CONTROL_MASK) - { - if (actions & GDK_ACTION_COPY) - { - *suggested_action = GDK_ACTION_COPY; - *possible_actions = GDK_ACTION_COPY; - } - } - else - { - if (actions & GDK_ACTION_MOVE) - { - *suggested_action = GDK_ACTION_MOVE; - *possible_actions = GDK_ACTION_MOVE; - } - } - } - else - { - *possible_actions = actions; - - if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK)) - *suggested_action = GDK_ACTION_ASK; - else if (actions & GDK_ACTION_COPY) - *suggested_action = GDK_ACTION_COPY; - else if (actions & GDK_ACTION_MOVE) - *suggested_action = GDK_ACTION_MOVE; - else if (actions & GDK_ACTION_LINK) - *suggested_action = GDK_ACTION_LINK; - } -} - -static void -gdk_drag_update (GdkDragContext *context, - gdouble x_root, - gdouble y_root, - GdkModifierType mods, - guint32 evtime) -{ - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); - GdkDragAction action, possible_actions; - GdkSurface *dest_surface; - GdkDragProtocol protocol; - - gdk_drag_get_current_actions (mods, GDK_BUTTON_PRIMARY, win32_context->actions, - &action, &possible_actions); - - gdk_drag_find_window (context, - win32_context->drag_surface, - x_root, y_root, &dest_surface, &protocol); - - gdk_drag_motion (context, dest_surface, protocol, x_root, y_root, - action, possible_actions, evtime); -} - -static gboolean -gdk_dnd_handle_motion_event (GdkDragContext *context, - const GdkEventMotion *event) -{ - GdkModifierType state; - - if (!gdk_event_get_state ((GdkEvent *) event, &state)) - return FALSE; - - GDK_NOTE (DND, g_print ("gdk_dnd_handle_motion_event: 0x%p\n", - context)); - - gdk_drag_update (context, event->x_root, event->y_root, state, - gdk_event_get_time ((GdkEvent *) event)); - return TRUE; -} - -static gboolean -gdk_dnd_handle_key_event (GdkDragContext *context, - const GdkEventKey *event) -{ - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); - GdkModifierType state; - GdkSurface *root_window; - GdkDevice *pointer; - gint dx, dy; - - GDK_NOTE (DND, g_print ("gdk_dnd_handle_key_event: 0x%p\n", - context)); - - dx = dy = 0; - state = event->state; - pointer = gdk_device_get_associated_device (gdk_event_get_device ((GdkEvent *) event)); - - if (event->type == GDK_KEY_PRESS) - { - switch (event->keyval) - { - case GDK_KEY_Escape: - gdk_drag_context_cancel (context, GDK_DRAG_CANCEL_USER_CANCELLED); - return TRUE; - - case GDK_KEY_space: - case GDK_KEY_Return: - case GDK_KEY_ISO_Enter: - case GDK_KEY_KP_Enter: - case GDK_KEY_KP_Space: - if ((gdk_drag_context_get_selected_action (context) != 0) && - (gdk_drag_context_get_dest_surface (context) != NULL)) - { - g_signal_emit_by_name (context, "drop-performed", - gdk_event_get_time ((GdkEvent *) event)); - } - else - gdk_drag_context_cancel (context, GDK_DRAG_CANCEL_NO_TARGET); - - return TRUE; - - case GDK_KEY_Up: - case GDK_KEY_KP_Up: - dy = (state & GDK_MOD1_MASK) ? -BIG_STEP : -SMALL_STEP; - break; - - case GDK_KEY_Down: - case GDK_KEY_KP_Down: - dy = (state & GDK_MOD1_MASK) ? BIG_STEP : SMALL_STEP; - break; - - case GDK_KEY_Left: - case GDK_KEY_KP_Left: - dx = (state & GDK_MOD1_MASK) ? -BIG_STEP : -SMALL_STEP; - break; - - case GDK_KEY_Right: - case GDK_KEY_KP_Right: - dx = (state & GDK_MOD1_MASK) ? BIG_STEP : SMALL_STEP; - break; - } - } - - /* The state is not yet updated in the event, so we need - * to query it here. - */ - _gdk_device_query_state (pointer, NULL, NULL, NULL, NULL, NULL, NULL, &state); - - if (dx != 0 || dy != 0) - { - win32_context->last_x += dx; - win32_context->last_y += dy; - gdk_device_warp (pointer, win32_context->last_x, win32_context->last_y); - } - - gdk_drag_update (context, win32_context->last_x, win32_context->last_y, state, - gdk_event_get_time ((GdkEvent *) event)); - - return TRUE; -} - -static gboolean -gdk_dnd_handle_grab_broken_event (GdkDragContext *context, - const GdkEventGrabBroken *event) -{ - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); - - GDK_NOTE (DND, g_print ("gdk_dnd_handle_grab_broken_event: 0x%p\n", - context)); - - /* Don't cancel if we break the implicit grab from the initial button_press. - * Also, don't cancel if we re-grab on the widget or on our IPC window, for - * example, when changing the drag cursor. - */ - if (event->implicit || - event->grab_window == win32_context->drag_surface || - event->grab_window == win32_context->ipc_window) - return FALSE; - - if (gdk_event_get_device ((GdkEvent *) event) != - gdk_drag_context_get_device (context)) - return FALSE; - - gdk_drag_context_cancel (context, GDK_DRAG_CANCEL_ERROR); - return TRUE; -} - -static gboolean -gdk_dnd_handle_button_event (GdkDragContext *context, - const GdkEventButton *event) -{ - GDK_NOTE (DND, g_print ("gdk_dnd_handle_button_event: 0x%p\n", - context)); - -#if 0 - /* FIXME: Check the button matches */ - if (event->button != win32_context->button) - return FALSE; -#endif - - if ((gdk_drag_context_get_selected_action (context) != 0)) - { - g_signal_emit_by_name (context, "drop-performed", - gdk_event_get_time ((GdkEvent *) event)); - } - else - gdk_drag_context_cancel (context, GDK_DRAG_CANCEL_NO_TARGET); - - return TRUE; -} - -gboolean -gdk_dnd_handle_drag_status (GdkDragContext *context, - const GdkEventDND *event) -{ - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - GdkDragAction action; - - GDK_NOTE (DND, g_print ("gdk_dnd_handle_drag_status: 0x%p\n", - context)); - - if (context != event->context) - return FALSE; - - action = gdk_drag_context_get_selected_action (context); - - if (action != context_win32->current_action) - { - context_win32->current_action = action; - g_signal_emit_by_name (context, "action-changed", action); - } - - return TRUE; -} - -static gboolean -gdk_dnd_handle_drop_finished (GdkDragContext *context, - const GdkEventDND *event) -{ - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); - - GDK_NOTE (DND, g_print ("gdk_dnd_handle_drop_finihsed: 0x%p\n", - context)); - - if (context != event->context) - return FALSE; - - g_signal_emit_by_name (context, "dnd-finished"); - gdk_drag_drop_done (context, !win32_context->drop_failed); - gdk_win32_selection_clear_targets (gdk_display_get_default (), - gdk_win32_drag_context_get_selection (context)); - - return TRUE; -} - -gboolean -gdk_win32_drag_context_handle_event (GdkDragContext *context, - const GdkEvent *event) -{ - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); - - if (!context->is_source) - return FALSE; - if (!win32_context->grab_seat && event->type != GDK_DROP_FINISHED) - return FALSE; - - switch (event->type) - { - case GDK_MOTION_NOTIFY: - return gdk_dnd_handle_motion_event (context, &event->motion); - case GDK_BUTTON_RELEASE: - return gdk_dnd_handle_button_event (context, &event->button); - case GDK_KEY_PRESS: - case GDK_KEY_RELEASE: - return gdk_dnd_handle_key_event (context, &event->key); - case GDK_GRAB_BROKEN: - return gdk_dnd_handle_grab_broken_event (context, &event->grab_broken); - case GDK_DRAG_STATUS: - return gdk_dnd_handle_drag_status (context, &event->dnd); - case GDK_DROP_FINISHED: - return gdk_dnd_handle_drop_finished (context, &event->dnd); - default: - break; - } - - return FALSE; -} - -void -gdk_win32_drag_context_action_changed (GdkDragContext *context, - GdkDragAction action) -{ - GdkCursor *cursor; - - cursor = gdk_drag_get_cursor (context, action); - gdk_drag_context_set_cursor (context, cursor); -} - -static GdkSurface * -gdk_win32_drag_context_get_drag_surface (GdkDragContext *context) -{ - return GDK_WIN32_DRAG_CONTEXT (context)->drag_surface; -} - -static void -gdk_win32_drag_context_set_hotspot (GdkDragContext *context, - gint hot_x, - gint hot_y) -{ - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); - - GDK_NOTE (DND, g_print ("gdk_drag_context_set_hotspot: 0x%p %d:%d\n", - context, - hot_x, hot_y)); - - win32_context->hot_x = hot_x; - win32_context->hot_y = hot_y; - - if (win32_context->grab_seat) - { - /* DnD is managed, update current position */ - move_drag_surface (context, win32_context->last_x, win32_context->last_y); - } -} - -static void -gdk_win32_drag_context_class_init (GdkWin32DragContextClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GdkDragContextClass *context_class = GDK_DRAG_CONTEXT_CLASS (klass); - - object_class->finalize = gdk_win32_drag_context_finalize; - - context_class->find_window = gdk_win32_drag_context_find_window; - context_class->drag_status = gdk_win32_drag_context_drag_status; - context_class->drag_motion = gdk_win32_drag_context_drag_motion; - context_class->drag_abort = gdk_win32_drag_context_drag_abort; - context_class->drag_drop = gdk_win32_drag_context_drag_drop; - context_class->drop_finish = gdk_win32_drag_context_drop_finish; - - context_class->get_drag_surface = gdk_win32_drag_context_get_drag_surface; - context_class->set_hotspot = gdk_win32_drag_context_set_hotspot; - context_class->drop_done = gdk_win32_drag_context_drop_done; - context_class->set_cursor = gdk_win32_drag_context_set_cursor; - context_class->cancel = gdk_win32_drag_context_cancel; - context_class->drop_performed = gdk_win32_drag_context_drop_performed; - context_class->handle_event = gdk_win32_drag_context_handle_event; - context_class->action_changed = gdk_win32_drag_context_action_changed; - -}