From 8ee4de804c94cbf5a29b114f855ec3bab65add6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Tue, 5 Jun 2018 23:03:51 +0000 Subject: [PATCH] GDK W32: Adapt to GdkDrop and GdkDragContext changes * Remove clipdrop->dnd_target_state, it's not used anymore * Remove non-functioning _gdk_dropfiles_store(), store dropfiles list in GdkWin32Drop instead * Fix multiple comment typos * Fix _gdk_win32_get_clipboard_format_name_as_interned_mimetype() to leave names that look like mime/types alone * Refactor _gdk_win32_add_w32format_to_pairs() to populate GdkContentFormatsBuilder directly, instead of making a GList * Rename context -> drag (still using GdkDragContext type, but [almost?] all variables and comments say "drag" now) * Rename GdkDropContext -> GdkDrop * Rename some parameter names for clarity * Rewrite local protocol to look more like OLE2 protocol instead of mirroring the structure of the X11 API. * Add handle_events field to GdkWin32DragContext, to shut off event handling (temporary fix until GTK is patched up) * Remove _gdk_win32_drag_context_find() - the drag object is stored in GdkDrop instead. Use _gdk_win32_find_drag_for_dest_surface() to get it initially. * Remove target_ctx_for_window, droptarget context is stored in the surface instead. * Call gdk_drag_context_set_cursor() just like wayland backend does (slightly broken for now) * Clean up the action choosing code (filter source actions by using keyboard state, pass that to GTK, get all actions supported by GTK in response, match them up with filtered source actions, return the result, falling back to COPY in case of multiple actions) * Check drag_win32->protocol instead of the use_ole2_dnd variable where possible * Remove protocol checks from functions that are only used by the local protocol * Use event state to manufacture the keyboard state for WM_MOUSEMOVE * Change function names printed by GDK_NOTE to name the actual functions, not their theoretical generic GDK stack ancestors * Consistently use drag_win32 and drop_win32 variables instead of a mix of that and win32_drag/win32_drop * Return FALSE from button handler to ensure that GTK gets the button event to break implicit grab * Emit leave event on failed idroptarget_drop() calls --- gdk/win32/gdkclipdrop-win32.c | 83 +-- gdk/win32/gdkclipdrop-win32.h | 58 +- gdk/win32/gdkdrag-win32.c | 1133 +++++++++++++------------------ gdk/win32/gdkdrop-win32.c | 1110 ++++++++++++++++++------------ gdk/win32/gdkprivate-win32.h | 4 +- gdk/win32/gdksurface-win32.c | 3 + gdk/win32/gdksurface-win32.h | 12 + gdk/win32/gdkwin32dnd-private.h | 81 +-- gdk/win32/gdkwin32dnd.h | 17 - 9 files changed, 1256 insertions(+), 1245 deletions(-) diff --git a/gdk/win32/gdkclipdrop-win32.c b/gdk/win32/gdkclipdrop-win32.c index 2cefb583ea..f3d4925fb5 100644 --- a/gdk/win32/gdkclipdrop-win32.c +++ b/gdk/win32/gdkclipdrop-win32.c @@ -1540,8 +1540,6 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop) win32_clipdrop->GetUpdatedClipboardFormats = GetProcAddress (user32, "GetUpdatedClipboardFormats"); FreeLibrary (user32); - win32_clipdrop->dnd_target_state = GDK_WIN32_DND_NONE; - atoms = g_array_sized_new (FALSE, TRUE, sizeof (GdkAtom), GDK_WIN32_ATOM_INDEX_LAST); g_array_set_size (atoms, GDK_WIN32_ATOM_INDEX_LAST); cfs = g_array_sized_new (FALSE, TRUE, sizeof (UINT), GDK_WIN32_CF_INDEX_LAST); @@ -1875,32 +1873,6 @@ gdk_win32_clipdrop_init (GdkWin32Clipdrop *win32_clipdrop) win32_clipdrop->dnd_thread_id = GPOINTER_TO_UINT (g_async_queue_pop (win32_clipdrop->dnd_queue)); } -void -_gdk_dropfiles_store (gchar *data) -{ -/* FIXME: REMOVE ALL THAT STUFF - if (data != NULL) - { - g_assert (clipdrop->dropfiles_prop == NULL); - - clipdrop->dropfiles_prop = g_new (GdkSelProp, 1); - clipdrop->dropfiles_prop->data = (guchar *) data; - clipdrop->dropfiles_prop->length = strlen (data) + 1; - clipdrop->dropfiles_prop->bitness = 8; - clipdrop->dropfiles_prop->target = _gdk_win32_clipdrop_atom (GDK_WIN32_ATOM_INDEX_TEXT_URI_LIST); - } - else - { - if (clipdrop->dropfiles_prop != NULL) - { - g_free (clipdrop->dropfiles_prop->data); - g_free (clipdrop->dropfiles_prop); - } - clipdrop->dropfiles_prop = NULL; - } -*/ -} - #define CLIPBOARD_IDLE_ABORT_TIME 30 static const gchar * @@ -1967,7 +1939,7 @@ _gdk_win32_get_clipboard_format_name (UINT fmt, } /* If GetClipboardFormatNameW() used up all the space, it means that - * we probably need a bigger buffer, but cap this at 1 kilobyte. + * we probably need a bigger buffer, but cap this at 1 megabyte. */ if (gcfn_result == 0 || registered_name_w_len > 1024 * 1024) { @@ -1994,12 +1966,22 @@ _gdk_win32_get_clipboard_format_name (UINT fmt, /* This turns an arbitrary string into a string that * *looks* like a mime/type, such as: * "application/x.windows.FOO_BAR" from "FOO_BAR". + * Does nothing for strings that already look like a mime/type + * (no spaces, one slash, with at least one char on each side of the slash). */ const gchar * _gdk_win32_get_clipboard_format_name_as_interned_mimetype (gchar *w32format_name) { gchar *mime_type; const gchar *result; + gchar *space = strchr (w32format_name, ' '); + gchar *slash = strchr (w32format_name, '/'); + + if (space == NULL && + slash > w32format_name && + slash[1] != '\0' && + strchr (&slash[1], '/') == NULL) + return g_intern_string (w32format_name); mime_type = g_strdup_printf ("application/x.windows.%s", w32format_name); result = g_intern_string (mime_type); @@ -2058,15 +2040,16 @@ _gdk_win32_get_compatibility_contentformats_for_w32format (UINT w32format) /* Turn W32 format into a GDK content format and add it * to the array of W32 format <-> GDK content format pairs - * and/or to a list of GDK content formats. + * and/or to a GDK contentformat builder. * Also add compatibility GDK content formats for that W32 format. * The added content format string is always interned. - * Ensures that duplicates are not added. + * Ensures that duplicates are not added to the pairs array + * (builder already takes care of that for itself). */ void -_gdk_win32_add_w32format_to_pairs (UINT w32format, - GArray *array, - GList **list) +_gdk_win32_add_w32format_to_pairs (UINT w32format, + GArray *pairs, + GdkContentFormatsBuilder *builder) { gboolean predef; gchar *w32format_name = _gdk_win32_get_clipboard_format_name (w32format, &predef); @@ -2081,47 +2064,45 @@ _gdk_win32_add_w32format_to_pairs (UINT w32format, GDK_NOTE (DND, g_print ("Maybe add as-is format %s (%s) (0x%p)\n", w32format_name, interned_w32format_name, interned_w32format_name)); g_free (w32format_name); - if (array && interned_w32format_name != 0) + if (pairs && interned_w32format_name != 0) { - for (j = 0; j < array->len; j++) - if (g_array_index (array, GdkWin32ContentFormatPair, j).contentformat == interned_w32format_name) + for (j = 0; j < pairs->len; j++) + if (g_array_index (pairs, GdkWin32ContentFormatPair, j).contentformat == interned_w32format_name) break; - if (j == array->len) + if (j == pairs->len) { pair.w32format = w32format; pair.contentformat = interned_w32format_name; pair.transmute = FALSE; - g_array_append_val (array, pair); + g_array_append_val (pairs, pair); } } - - if (list && interned_w32format_name != 0 && g_list_find (*list, interned_w32format_name) == NULL) - *list = g_list_prepend (*list, (gpointer) interned_w32format_name); + if (builder != NULL && interned_w32format_name != 0) + gdk_content_formats_builder_add_mime_type (builder, interned_w32format_name); } comp_pairs = _gdk_win32_get_compatibility_contentformats_for_w32format (w32format); - if (array && comp_pairs != NULL) + if (pairs != NULL && comp_pairs != NULL) for (i = 0; i < comp_pairs->len; i++) { pair = g_array_index (comp_pairs, GdkWin32ContentFormatPair, i); - for (j = 0; j < array->len; j++) - if (g_array_index (array, GdkWin32ContentFormatPair, j).contentformat == pair.contentformat && - g_array_index (array, GdkWin32ContentFormatPair, j).w32format == pair.w32format) + for (j = 0; j < pairs->len; j++) + if (g_array_index (pairs, GdkWin32ContentFormatPair, j).contentformat == pair.contentformat && + g_array_index (pairs, GdkWin32ContentFormatPair, j).w32format == pair.w32format) break; - if (j == array->len) - g_array_append_val (array, pair); + if (j == pairs->len) + g_array_append_val (pairs, pair); } - if (list && comp_pairs != NULL) + if (builder != NULL && comp_pairs != NULL) for (i = 0; i < comp_pairs->len; i++) { pair = g_array_index (comp_pairs, GdkWin32ContentFormatPair, i); - if (g_list_find (*list, pair.contentformat) == NULL) - *list = g_list_prepend (*list, (gpointer) pair.contentformat); + gdk_content_formats_builder_add_mime_type (builder, pair.contentformat); } } diff --git a/gdk/win32/gdkclipdrop-win32.h b/gdk/win32/gdkclipdrop-win32.h index c281c8d486..d7b88c6061 100644 --- a/gdk/win32/gdkclipdrop-win32.h +++ b/gdk/win32/gdkclipdrop-win32.h @@ -236,42 +236,42 @@ GType gdk_win32_clipdrop_get_type (void) G_GNUC void _gdk_win32_clipdrop_init (void); -gboolean _gdk_win32_format_uses_hdata (UINT w32format); +gboolean _gdk_win32_format_uses_hdata (UINT w32format); -gchar * _gdk_win32_get_clipboard_format_name (UINT fmt, - gboolean *is_predefined); -void _gdk_win32_add_w32format_to_pairs (UINT format, - GArray *array, - GList **list); -gint _gdk_win32_add_contentformat_to_pairs (GdkAtom target, - GArray *array); +gchar * _gdk_win32_get_clipboard_format_name (UINT fmt, + gboolean *is_predefined); +void _gdk_win32_add_w32format_to_pairs (UINT format, + GArray *array, + GdkContentFormatsBuilder *builder); +gint _gdk_win32_add_contentformat_to_pairs (GdkAtom target, + GArray *array); -void _gdk_win32_clipboard_default_output_done (GObject *clipboard, - GAsyncResult *result, - gpointer user_data); -gboolean _gdk_win32_transmute_contentformat (const gchar *from_contentformat, - UINT to_w32format, - const guchar *data, - gint length, - guchar **set_data, - gsize *set_data_length); +void _gdk_win32_clipboard_default_output_done (GObject *clipboard, + GAsyncResult *result, + gpointer user_data); +gboolean _gdk_win32_transmute_contentformat (const gchar *from_contentformat, + UINT to_w32format, + const guchar *data, + gint length, + guchar **set_data, + gsize *set_data_length); -gboolean _gdk_win32_transmute_windows_data (UINT from_w32format, - const gchar *to_contentformat, - HANDLE hdata, - guchar **set_data, - gsize *set_data_length); +gboolean _gdk_win32_transmute_windows_data (UINT from_w32format, + const gchar *to_contentformat, + HANDLE hdata, + guchar **set_data, + gsize *set_data_length); -gboolean _gdk_win32_store_clipboard_contentformats (GdkClipboard *cb, - GTask *task, - GdkContentFormats *contentformats); +gboolean _gdk_win32_store_clipboard_contentformats (GdkClipboard *cb, + GTask *task, + GdkContentFormats *contentformats); -void _gdk_win32_retrieve_clipboard_contentformats (GTask *task, - GdkContentFormats *contentformats); +void _gdk_win32_retrieve_clipboard_contentformats (GTask *task, + GdkContentFormats *contentformats); -void _gdk_win32_advertise_clipboard_contentformats (GTask *task, - GdkContentFormats *contentformats); +void _gdk_win32_advertise_clipboard_contentformats (GTask *task, + GdkContentFormats *contentformats); diff --git a/gdk/win32/gdkdrag-win32.c b/gdk/win32/gdkdrag-win32.c index 2da9700306..8ad7322f86 100644 --- a/gdk/win32/gdkdrag-win32.c +++ b/gdk/win32/gdkdrag-win32.c @@ -37,7 +37,7 @@ * * Notes on the implementation: * - * Source drag context, IDragSource and IDataObject for it are created + * Source drag context, IDropSource 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 @@ -49,7 +49,7 @@ * To account for it the data is transmuted back and forth. There are two * main points of transmutation: * * GdkWin32HDATAOutputStream: transmutes GTK+ data to W32 data - * * GdkWin32DropContext: transmutes W32 data to GTK+ data + * * GdkWin32Drop: transmutes W32 data to GTK+ data * * There are also two points where data formats are considered: * * When source drag context is created, it gets a list of GDK contentformats @@ -226,7 +226,7 @@ typedef struct IDropSource ids; IDropSourceNotify idsn; gint ref_count; - GdkDragContext *context; + GdkDragContext *drag; /* These are thread-local * copies of the similar fields from GdkWin32DragContext @@ -248,7 +248,7 @@ typedef struct typedef struct { IDataObject ido; int ref_count; - GdkDragContext *context; + GdkDragContext *drag; GArray *formats; } data_object; @@ -400,6 +400,7 @@ free_queue_item (GdkWin32DnDThreadQueueItem *item) case GDK_WIN32_DND_THREAD_QUEUE_ITEM_UPDATE_DRAG_STATE: case GDK_WIN32_DND_THREAD_QUEUE_ITEM_GIVE_FEEDBACK: case GDK_WIN32_DND_THREAD_QUEUE_ITEM_DRAG_INFO: + /* These have no data to clean up */ break; case GDK_WIN32_DND_THREAD_QUEUE_ITEM_GET_DATA: getdata = (GdkWin32DnDThreadGetData *) item; @@ -482,18 +483,27 @@ process_dnd_queue (gboolean timed, return FALSE; } +void +_gdk_win32_local_drag_context_drop_response (GdkDragContext *drag, + GdkDragAction action) +{ + GDK_NOTE (DND, g_print ("_gdk_win32_local_drag_context_drop_response: 0x%p\n", + drag)); + + g_signal_emit_by_name (drag, "dnd-finished"); + gdk_drag_drop_done (drag, action != 0); +} + static gboolean do_drag_drop_response (gpointer user_data) { GdkWin32DnDThreadDoDragDrop *ddd = (GdkWin32DnDThreadDoDragDrop *) user_data; HRESULT hr = ddd->received_result; - GdkDragContext *context = GDK_DRAG_CONTEXT (ddd->base.opaque_context); + GdkDragContext *drag = GDK_DRAG_CONTEXT (ddd->base.opaque_context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get (); - gpointer table_value = g_hash_table_lookup (clipdrop->active_source_drags, context); + gpointer table_value = g_hash_table_lookup (clipdrop->active_source_drags, drag); - /* This just verifies that we got the right context, - * we don't need the ddd struct itself. - */ if (ddd == table_value) { GDK_NOTE (DND, g_print ("DoDragDrop returned %s with effect %lu\n", @@ -502,46 +512,46 @@ do_drag_drop_response (gpointer user_data) (hr == E_UNEXPECTED ? "E_UNEXPECTED" : g_strdup_printf ("%#.8lx", hr)))), ddd->received_drop_effect)); - GDK_WIN32_DRAG_CONTEXT (context)->drop_failed = !(SUCCEEDED (hr) || hr == DRAGDROP_S_DROP); + drag_win32->drop_failed = !(SUCCEEDED (hr) || hr == DRAGDROP_S_DROP); /* We used to delete the selection here, * now GTK does that automatically in response to * the "dnd-finished" signal, * if the operation was successful and was a move. */ - GDK_NOTE (DND, g_print ("gdk_dnd_handle_drop_finihsed: 0x%p\n", - context)); + GDK_NOTE (DND, g_print ("gdk_dnd_handle_drop_finished: 0x%p\n", + drag)); - g_signal_emit_by_name (context, "dnd-finished"); - gdk_drag_drop_done (context, !(GDK_WIN32_DRAG_CONTEXT (context))->drop_failed); + g_signal_emit_by_name (drag, "dnd-finished"); + gdk_drag_drop_done (drag, !drag_win32->drop_failed); } else { if (!table_value) - g_critical ("Did not find context 0x%p in the active contexts table", context); + g_critical ("Did not find drag 0x%p in the active drags table", drag); else - g_critical ("Found context 0x%p in the active contexts table, but the record doesn't match (0x%p != 0x%p)", context, ddd, table_value); + g_critical ("Found drag 0x%p in the active drags table, but the record doesn't match (0x%p != 0x%p)", drag, ddd, table_value); } /* 3rd parties could keep a reference to this object, - * but we won't keep the context alive that long. + * but we won't keep the drag alive that long. * Neutralize it (attempts to get its data will fail) - * by nullifying the context pointer (it doesn't hold + * by nullifying the drag pointer (it doesn't hold * a reference, so no unreffing). */ - ddd->src_object->context = NULL; + g_clear_object (&ddd->src_object->drag); IDropSource_Release (&ddd->src_context->ids); IDataObject_Release (&ddd->src_object->ido); - g_hash_table_remove (clipdrop->active_source_drags, context); + g_hash_table_remove (clipdrop->active_source_drags, drag); free_queue_item (&ddd->base); return G_SOURCE_REMOVE; } static void -received_drag_context_data (GObject *context, +received_drag_context_data (GObject *drag, GAsyncResult *result, gpointer user_data) { @@ -549,12 +559,12 @@ received_drag_context_data (GObject *context, GdkWin32DnDThreadGetData *getdata = (GdkWin32DnDThreadGetData *) user_data; GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get (); - if (!gdk_drag_context_write_finish (GDK_DRAG_CONTEXT (context), result, &error)) + if (!gdk_drag_context_write_finish (GDK_DRAG_CONTEXT (drag), result, &error)) { HANDLE handle; gboolean is_hdata; - GDK_NOTE (DND, g_printerr ("%p: failed to write HData-backed stream: %s\n", context, error->message)); + GDK_NOTE (DND, g_printerr ("%p: failed to write HData-backed stream: %s\n", drag, error->message)); g_error_free (error); g_output_stream_close (G_OUTPUT_STREAM (getdata->stream), NULL, NULL); handle = gdk_win32_hdata_output_stream_get_handle (getdata->stream, &is_hdata); @@ -582,13 +592,13 @@ get_data_response (gpointer user_data) { GdkWin32DnDThreadGetData *getdata = (GdkWin32DnDThreadGetData *) user_data; GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get (); - GdkDragContext *context = GDK_DRAG_CONTEXT (getdata->base.opaque_context); - gpointer ddd = g_hash_table_lookup (clipdrop->active_source_drags, context); + GdkDragContext *drag = GDK_DRAG_CONTEXT (getdata->base.opaque_context); + gpointer ddd = g_hash_table_lookup (clipdrop->active_source_drags, drag); GDK_NOTE (DND, g_print ("idataobject_getdata will request target 0x%p (%s)", getdata->pair.contentformat, getdata->pair.contentformat)); - /* This just verifies that we got the right context, + /* This just verifies that we got the right drag, * we don't need the ddd struct itself. */ if (ddd) @@ -599,7 +609,7 @@ get_data_response (gpointer user_data) if (stream) { getdata->stream = GDK_WIN32_HDATA_OUTPUT_STREAM (stream); - gdk_drag_context_write_async (context, + gdk_drag_context_write_async (drag, getdata->pair.contentformat, stream, G_PRIORITY_DEFAULT, @@ -708,75 +718,60 @@ typedef enum { GDK_DRAG_STATUS_DROP } GdkDragStatus; -static GList *local_source_contexts; -static GdkDragContext *current_dest_drag = NULL; - static gboolean use_ole2_dnd = TRUE; -static gboolean drag_context_grab (GdkDragContext *context); +static gboolean drag_context_grab (GdkDragContext *drag); G_DEFINE_TYPE (GdkWin32DragContext, gdk_win32_drag_context, GDK_TYPE_DRAG_CONTEXT) static void -move_drag_surface (GdkDragContext *context, +move_drag_surface (GdkDragContext *drag, guint x_root, guint y_root) { - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); g_assert (_win32_main_thread == NULL || _win32_main_thread == g_thread_self ()); - 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); + gdk_surface_move (drag_win32->drag_surface, + x_root - drag_win32->hot_x, + y_root - drag_win32->hot_y); + gdk_surface_raise (drag_win32->drag_surface); } static void -gdk_win32_drag_context_init (GdkWin32DragContext *context) +gdk_win32_drag_context_init (GdkWin32DragContext *drag) { g_assert (_win32_main_thread == NULL || _win32_main_thread == g_thread_self ()); - if (!use_ole2_dnd) - { - local_source_contexts = g_list_prepend (local_source_contexts, context); - } - else - { - } + drag->handle_events = TRUE; - GDK_NOTE (DND, g_print ("gdk_drag_context_init %p\n", context)); + GDK_NOTE (DND, g_print ("gdk_win32_drag_context_init %p\n", drag)); } static void gdk_win32_drag_context_finalize (GObject *object) { - GdkDragContext *context; - GdkWin32DragContext *context_win32; + GdkDragContext *drag; + GdkWin32DragContext *drag_win32; GdkSurface *drag_surface; g_assert (_win32_main_thread == NULL || _win32_main_thread == g_thread_self ()); - GDK_NOTE (DND, g_print ("gdk_drag_context_finalize %p\n", object)); + GDK_NOTE (DND, g_print ("gdk_win32_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); + drag = GDK_DRAG_CONTEXT (object); + drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); - if (!use_ole2_dnd) - { - local_source_contexts = g_list_remove (local_source_contexts, context); + gdk_drag_context_set_cursor (drag, NULL); - if (context == current_dest_drag) - current_dest_drag = NULL; - } - - g_set_object (&context_win32->ipc_window, NULL); - drag_surface = context_win32->drag_surface; + g_set_object (&drag_win32->ipc_window, NULL); + drag_surface = drag_win32->drag_surface; G_OBJECT_CLASS (gdk_win32_drag_context_parent_class)->finalize (object); @@ -789,62 +784,30 @@ gdk_win32_drag_context_finalize (GObject *object) static GdkDragContext * gdk_drag_context_new (GdkDisplay *display, GdkContentProvider *content, - GdkSurface *source_surface, - GdkContentFormats *formats, GdkDragAction actions, GdkDevice *device, GdkDragProtocol protocol) { - GdkWin32DragContext *context_win32; + GdkWin32DragContext *drag_win32; GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display); - GdkDragContext *context; + GdkDragContext *drag; - context_win32 = g_object_new (GDK_TYPE_WIN32_DRAG_CONTEXT, - "device", device ? device : gdk_seat_get_pointer (gdk_display_get_default_seat (display)), + drag_win32 = g_object_new (GDK_TYPE_WIN32_DRAG_CONTEXT, + "device", device, "content", content, - "formats", formats, NULL); - context = GDK_DRAG_CONTEXT (context_win32); + drag = GDK_DRAG_CONTEXT (drag_win32); if (win32_display->has_fixed_scale) - context_win32->scale = win32_display->surface_scale; + drag_win32->scale = win32_display->surface_scale; else - context_win32->scale = _gdk_win32_display_get_monitor_scale_factor (win32_display, NULL, NULL, NULL); + drag_win32->scale = _gdk_win32_display_get_monitor_scale_factor (win32_display, NULL, NULL, NULL); - context->is_source = TRUE; - g_set_object (&context->source_surface, source_surface); - gdk_drag_context_set_actions (context, actions, actions); - context_win32->protocol = protocol; + gdk_drag_context_set_actions (drag, actions, actions); + drag_win32->protocol = protocol; - gdk_content_formats_unref (formats); - - return context; -} - -GdkDragContext * -_gdk_win32_drag_context_find (GdkSurface *source, - GdkSurface *dest) -{ - GList *tmp_list = local_source_contexts; - GdkDragContext *context; - - g_assert (_win32_main_thread == NULL || - _win32_main_thread == g_thread_self ()); - - while (tmp_list) - { - context = (GdkDragContext *)tmp_list->data; - - if (context->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; + return drag; } #define PRINT_GUID(guid) \ @@ -863,19 +826,23 @@ _gdk_win32_drag_context_find (GdkSurface *source, static enum_formats *enum_formats_new (GArray *formats); +/* Finds a GdkDragContext object that corresponds to a DnD operation + * which is currently targetting the dest_surface + * Does not give a reference. + */ GdkDragContext * -_gdk_win32_find_source_context_for_dest_surface (GdkSurface *dest_surface) +_gdk_win32_find_drag_for_dest_surface (GdkSurface *dest_surface) { GHashTableIter iter; - GdkWin32DragContext *win32_context; + GdkWin32DragContext *drag_win32; GdkWin32DnDThreadDoDragDrop *ddd; GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get (); g_hash_table_iter_init (&iter, clipdrop->active_source_drags); - while (g_hash_table_iter_next (&iter, (gpointer *) &win32_context, (gpointer *) &ddd)) + while (g_hash_table_iter_next (&iter, (gpointer *) &drag_win32, (gpointer *) &ddd)) if (ddd->src_context->dest_window_handle == GDK_SURFACE_HWND (dest_surface)) - return GDK_DRAG_CONTEXT (win32_context); + return GDK_DRAG_CONTEXT (drag_win32); return NULL; } @@ -919,7 +886,7 @@ static gboolean notify_dnd_enter (gpointer user_data) { GdkWin32DnDEnterLeaveNotify *notify = (GdkWin32DnDEnterLeaveNotify *) user_data; - GdkDragContext *context = GDK_DRAG_CONTEXT (notify->opaque_context); + GdkDragContext *drag = GDK_DRAG_CONTEXT (notify->opaque_context); GdkSurface *dest_surface, *dw; dw = gdk_win32_handle_table_lookup (notify->target_window_handle); @@ -927,10 +894,10 @@ notify_dnd_enter (gpointer user_data) if (dw) dest_surface = g_object_ref (dw); else - dest_surface = gdk_win32_surface_foreign_new_for_display (gdk_drag_context_get_display (context), notify->target_window_handle); + dest_surface = gdk_win32_surface_foreign_new_for_display (gdk_drag_context_get_display (drag), notify->target_window_handle); - g_clear_object (&context->dest_surface); - context->dest_surface = dest_surface; + g_clear_object (&drag->dest_surface); + drag->dest_surface = dest_surface; g_free (notify); @@ -941,7 +908,7 @@ static gboolean notify_dnd_leave (gpointer user_data) { GdkWin32DnDEnterLeaveNotify *notify = (GdkWin32DnDEnterLeaveNotify *) user_data; - GdkDragContext *context = GDK_DRAG_CONTEXT (notify->opaque_context); + GdkDragContext *drag = GDK_DRAG_CONTEXT (notify->opaque_context); GdkSurface *dest_surface, *dw; dw = gdk_win32_handle_table_lookup (notify->target_window_handle); @@ -950,10 +917,10 @@ notify_dnd_leave (gpointer user_data) { dest_surface = gdk_surface_get_toplevel (dw); - if (dest_surface == context->dest_surface) - g_clear_object (&context->dest_surface); + if (dest_surface == drag->dest_surface) + g_clear_object (&drag->dest_surface); else - g_warning ("Destination window for handle 0x%p is 0x%p, but context has 0x%p", notify->target_window_handle, dest_surface, context->dest_surface); + g_warning ("Destination window for handle 0x%p is 0x%p, but drag has 0x%p", notify->target_window_handle, dest_surface, drag->dest_surface); } else g_warning ("Failed to find destination window for handle 0x%p", notify->target_window_handle); @@ -979,7 +946,7 @@ idropsourcenotify_dragentertarget (IDropSourceNotify *This, notify = g_new0 (GdkWin32DnDEnterLeaveNotify, 1); notify->target_window_handle = hwndTarget; - notify->opaque_context = ctx->context; + notify->opaque_context = ctx->drag; g_idle_add_full (G_PRIORITY_DEFAULT, notify_dnd_enter, notify, NULL); return S_OK; @@ -999,7 +966,7 @@ idropsourcenotify_dragleavetarget (IDropSourceNotify *This) notify = g_new0 (GdkWin32DnDEnterLeaveNotify, 1); notify->target_window_handle = ctx->dest_window_handle; ctx->dest_window_handle = NULL; - notify->opaque_context = ctx->context; + notify->opaque_context = ctx->drag; g_idle_add_full (G_PRIORITY_DEFAULT, notify_dnd_leave, notify, NULL); return S_OK; @@ -1048,9 +1015,9 @@ idropsource_queryinterface (LPDROPSOURCE This, static gboolean unref_context_in_main_thread (gpointer opaque_context) { - GdkDragContext *context = GDK_DRAG_CONTEXT (opaque_context); + GdkDragContext *drag = GDK_DRAG_CONTEXT (opaque_context); - g_clear_object (&context); + g_clear_object (&drag); return G_SOURCE_REMOVE; } @@ -1066,7 +1033,7 @@ idropsource_release (LPDROPSOURCE This) if (ref_count == 0) { - g_idle_add (unref_context_in_main_thread, ctx->context); + g_idle_add (unref_context_in_main_thread, ctx->drag); g_free (This); } @@ -1091,11 +1058,13 @@ idropsource_querycontinuedrag (LPDROPSOURCE This, { source_drag_context *ctx = (source_drag_context *) This; - GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag %p esc=%d keystate=0x%lx with state %d", This, fEscapePressed, grfKeyState, ctx->util_data.state)); + GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag %p esc=%d keystate=0x%lx with state %d\n", This, fEscapePressed, grfKeyState, ctx->util_data.state)); if (!dnd_queue_is_empty ()) process_dnd_queue (FALSE, 0, NULL); + GDK_NOTE (DND, g_print ("idropsource_querycontinuedrag state %d\n", ctx->util_data.state)); + if (ctx->util_data.state == GDK_WIN32_DND_DROPPED) { GDK_NOTE (DND, g_print ("DRAGDROP_S_DROP\n")); @@ -1113,6 +1082,33 @@ idropsource_querycontinuedrag (LPDROPSOURCE This, } } +static void +maybe_emit_action_changed (GdkWin32DragContext *drag_win32, + GdkDragAction actions) +{ + if (actions != drag_win32->current_action) + { + drag_win32->current_action = actions; + g_signal_emit_by_name (GDK_DRAG_CONTEXT (drag_win32), "action-changed", actions); + } +} + +void +_gdk_win32_local_drag_give_feedback (GdkDragContext *drag, + GdkDragAction actions) +{ + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); + + if (drag_win32->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) + drag_win32->drag_status = GDK_DRAG_STATUS_DRAG; + + GDK_NOTE (DND, g_print ("_gdk_win32_local_drag_give_feedback: 0x%p\n", + drag)); + + drag->action = actions; + maybe_emit_action_changed (drag_win32, actions); +} + static gboolean give_feedback (gpointer user_data) { @@ -1122,19 +1118,14 @@ give_feedback (gpointer user_data) if (ddd) { - GdkDragContext *context = GDK_DRAG_CONTEXT (feedback->base.opaque_context); - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); + GdkDragContext *drag = GDK_DRAG_CONTEXT (feedback->base.opaque_context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); GDK_NOTE (DND, g_print ("gdk_dnd_handle_drag_status: 0x%p\n", - context)); + drag)); - context->action = action_for_drop_effect (feedback->received_drop_effect); - - if (context->action != win32_context->current_action) - { - win32_context->current_action = context->action; - g_signal_emit_by_name (context, "action-changed", context->action); - } + drag->action = action_for_drop_effect (feedback->received_drop_effect); + maybe_emit_action_changed (drag_win32, drag->action); } free_queue_item (&feedback->base); @@ -1155,7 +1146,8 @@ idropsource_givefeedback (LPDROPSOURCE This, process_dnd_queue (FALSE, 0, NULL); feedback = g_new0 (GdkWin32DnDThreadGiveFeedback, 1); - feedback->base.opaque_context = ctx->context; + feedback->base.item_type = GDK_WIN32_DND_THREAD_QUEUE_ITEM_GIVE_FEEDBACK; + feedback->base.opaque_context = ctx->drag; feedback->received_drop_effect = dwEffect; g_idle_add_full (G_PRIORITY_DEFAULT, give_feedback, feedback, NULL); @@ -1274,7 +1266,7 @@ idataobject_getdata (LPDATAOBJECT This, GdkWin32DnDThreadGetData *getdata; GdkWin32ContentFormatPair *pair; - if (ctx->context == NULL) + if (ctx->drag == NULL) return E_FAIL; GDK_NOTE (DND, g_print ("idataobject_getdata %p %s ", @@ -1294,7 +1286,7 @@ idataobject_getdata (LPDATAOBJECT This, getdata = g_new0 (GdkWin32DnDThreadGetData, 1); getdata->base.item_type = GDK_WIN32_DND_THREAD_QUEUE_ITEM_GET_DATA; - getdata->base.opaque_context = (gpointer) ctx->context; + getdata->base.opaque_context = (gpointer) ctx->drag; getdata->pair = *pair; g_idle_add_full (G_PRIORITY_DEFAULT, get_data_response, getdata, NULL); @@ -1612,31 +1604,31 @@ static IEnumFORMATETCVtbl ief_vtbl = { }; static source_drag_context * -source_context_new (GdkDragContext *context, +source_context_new (GdkDragContext *drag, GdkSurface *window, GdkContentFormats *formats) { - GdkWin32DragContext *context_win32; + GdkWin32DragContext *drag_win32; source_drag_context *result; - context_win32 = GDK_WIN32_DRAG_CONTEXT (context); + drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); result = g_new0 (source_drag_context, 1); - result->context = g_object_ref (context); + result->drag = g_object_ref (drag); result->ids.lpVtbl = &ids_vtbl; result->idsn.lpVtbl = &idsn_vtbl; result->ref_count = 1; - result->source_window_handle = GDK_SURFACE_HWND (context->source_surface); - result->scale = context_win32->scale; + result->source_window_handle = GDK_SURFACE_HWND (drag->source_surface); + result->scale = drag_win32->scale; result->util_data.state = GDK_WIN32_DND_PENDING; /* Implicit */ - GDK_NOTE (DND, g_print ("source_context_new: %p (drag context %p)\n", result, result->context)); + GDK_NOTE (DND, g_print ("source_context_new: %p (drag %p)\n", result, result->drag)); return result; } static data_object * -data_object_new (GdkDragContext *context) +data_object_new (GdkDragContext *drag) { data_object *result; const char * const *mime_types; @@ -1646,10 +1638,10 @@ data_object_new (GdkDragContext *context) result->ido.lpVtbl = &ido_vtbl; result->ref_count = 1; - result->context = context; + result->drag = drag; result->formats = g_array_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair)); - mime_types = gdk_content_formats_get_mime_types (gdk_drag_context_get_formats (context), &n_mime_types); + mime_types = gdk_content_formats_get_mime_types (gdk_drag_context_get_formats (drag), &n_mime_types); for (i = 0; i < n_mime_types; i++) { @@ -1689,8 +1681,8 @@ _gdk_drag_init (void) { CoInitializeEx (NULL, COINIT_APARTMENTTHREADED); - if (g_strcmp0 (getenv ("GDK_WIN32_OLE2_DND"), "0") != 0) - use_ole2_dnd = TRUE; + if (g_strcmp0 (getenv ("GDK_WIN32_OLE2_DND"), "0") == 0) + use_ole2_dnd = FALSE; if (use_ole2_dnd) { @@ -1714,123 +1706,6 @@ _gdk_win32_dnd_exit (void) CoUninitialize (); } -/* Source side */ - -void -_gdk_win32_drag_context_send_local_status_event (GdkDragContext *src_context, - GdkDragAction action) -{ - 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; - - src_context->action = action; - - GDK_NOTE (DND, g_print ("gdk_dnd_handle_drag_status: 0x%p\n", - src_context)); - - if (action != src_context_win32->current_action) - { - src_context_win32->current_action = action; - g_signal_emit_by_name (src_context, "action-changed", action); - } -} - -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)) - { - gdk_drop_emit_leave_event (GDK_DROP (current_dest_drag), FALSE, GDK_CURRENT_TIME); - - current_dest_drag = NULL; - } -} - -static void -local_send_motion (GdkDragContext *context, - gint x_root, - gint y_root, - GdkDragAction action, - guint32 time) -{ - 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; - - gdk_drag_context_set_actions (current_dest_drag, action, action); - - current_dest_drag_win32 = GDK_WIN32_DRAG_CONTEXT (current_dest_drag); - current_dest_drag_win32->util_data.last_x = x_root; - current_dest_drag_win32->util_data.last_y = y_root; - - context_win32->drag_status = GDK_DRAG_STATUS_MOTION_WAIT; - - gdk_drop_emit_motion_event (GDK_DROP (current_dest_drag), FALSE, x_root, y_root, time); - } -} - -static void -local_send_drop (GdkDragContext *context, - guint32 time) -{ - 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; - - context_win32 = GDK_WIN32_DRAG_CONTEXT (current_dest_drag); - - gdk_drop_emit_motion_event (GDK_DROP (current_dest_drag), - FALSE, - context_win32->util_data.last_x, context_win32->util_data.last_y, - GDK_CURRENT_TIME); - - current_dest_drag = NULL; - } -} - -void -_gdk_win32_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) { @@ -1844,64 +1719,64 @@ create_drag_surface (GdkDisplay *display) } GdkDragContext * -_gdk_win32_surface_drag_begin (GdkSurface *window, - GdkDevice *device, - GdkContentProvider *content, - GdkDragAction actions, - gint dx, - gint dy) +_gdk_win32_surface_drag_begin (GdkSurface *window, + GdkDevice *device, + GdkContentProvider *content, + GdkDragAction actions, + gint dx, + gint dy) { - GdkDragContext *context; - GdkWin32DragContext *context_win32; + GdkDragContext *drag; + GdkWin32DragContext *drag_win32; GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get (); int x_root, y_root; g_return_val_if_fail (window != NULL, NULL); - context = gdk_drag_context_new (gdk_surface_get_display (window), - content, - window, - gdk_content_formats_union_serialize_mime_types (gdk_content_provider_ref_storable_formats (content)), - actions, - device, - use_ole2_dnd ? GDK_DRAG_PROTO_OLE2 : GDK_DRAG_PROTO_LOCAL); + drag = gdk_drag_context_new (gdk_surface_get_display (window), + content, + actions, + device, + use_ole2_dnd ? GDK_DRAG_PROTO_OLE2 : GDK_DRAG_PROTO_LOCAL); + drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); - context_win32 = GDK_WIN32_DRAG_CONTEXT (context); + g_set_object (&drag->source_surface, window); + drag->is_source = TRUE; - GDK_NOTE (DND, g_print ("gdk_drag_begin\n")); + GDK_NOTE (DND, g_print ("_gdk_win32_surface_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->util_data.last_x = context_win32->start_x; - context_win32->util_data.last_y = context_win32->start_y; + drag_win32->start_x = x_root; + drag_win32->start_y = y_root; + drag_win32->util_data.last_x = drag_win32->start_x; + drag_win32->util_data.last_y = drag_win32->start_y; - g_set_object (&context_win32->ipc_window, window); + g_set_object (&drag_win32->ipc_window, window); - context_win32->drag_surface = create_drag_surface (gdk_surface_get_display (window)); + drag_win32->drag_surface = create_drag_surface (gdk_surface_get_display (window)); - if (!drag_context_grab (context)) + if (!drag_context_grab (drag)) { - g_object_unref (context); + g_object_unref (drag); return FALSE; } - if (use_ole2_dnd) + if (drag_win32->protocol == GDK_DRAG_PROTO_OLE2) { GdkWin32DnDThreadDoDragDrop *ddd = g_new0 (GdkWin32DnDThreadDoDragDrop, 1); source_drag_context *source_ctx; data_object *data_obj; - source_ctx = source_context_new (context, + source_ctx = source_context_new (drag, window, - gdk_drag_context_get_formats (context)); - data_obj = data_object_new (context); + gdk_drag_context_get_formats (drag)); + data_obj = data_object_new (drag); ddd->base.item_type = GDK_WIN32_DND_THREAD_QUEUE_ITEM_DO_DRAG_DROP; - ddd->base.opaque_context = context_win32; + ddd->base.opaque_context = drag_win32; ddd->src_context = source_ctx; ddd->src_object = data_obj; ddd->allowed_drop_effects = 0; @@ -1912,17 +1787,17 @@ _gdk_win32_surface_drag_begin (GdkSurface *window, if (actions & GDK_ACTION_LINK) ddd->allowed_drop_effects |= DROPEFFECT_LINK; - g_hash_table_replace (clipdrop->active_source_drags, g_object_ref (context), ddd); + g_hash_table_replace (clipdrop->active_source_drags, g_object_ref (drag), ddd); increment_dnd_queue_counter (); g_async_queue_push (clipdrop->dnd_queue, ddd); API_CALL (PostThreadMessage, (clipdrop->dnd_thread_id, thread_wakeup_message, 0, 0)); - context_win32->util_data.state = GDK_WIN32_DND_PENDING; + drag_win32->util_data.state = GDK_WIN32_DND_PENDING; } - move_drag_surface (context, x_root, y_root); + move_drag_surface (drag, x_root, y_root); - return context; + return drag; } /* TODO: remove this? @@ -1968,22 +1843,26 @@ find_window_enum_proc (HWND hwnd, return TRUE; } +/* Finds the GdkSurface under cursor. Local DnD protcol + * uses this function, since local protocol is implemented + * entirely in GDK and cannot rely on the OS to notify + * drop targets about drags that move over them. + */ static GdkSurface * -gdk_win32_drag_context_find_surface (GdkDragContext *context, +gdk_win32_drag_context_find_surface (GdkDragContext *drag, GdkSurface *drag_surface, gint x_root, - gint y_root, - GdkDragProtocol *protocol) + gint y_root) { - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); GdkSurface *dest_surface, *dw; find_window_enum_arg a; g_assert (_win32_main_thread == NULL || _win32_main_thread == g_thread_self ()); - a.x = x_root * context_win32->scale - _gdk_offset_x; - a.y = y_root * context_win32->scale - _gdk_offset_y; + a.x = x_root * drag_win32->scale - _gdk_offset_x; + a.y = y_root * drag_win32->scale - _gdk_offset_y; a.ignore = drag_surface ? GDK_SURFACE_HWND (drag_surface) : NULL; a.result = NULL; @@ -2007,157 +1886,114 @@ gdk_win32_drag_context_find_surface (GdkDragContext *context, 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; + dest_surface = gdk_win32_surface_foreign_new_for_display (gdk_drag_context_get_display (drag), a.result); } GDK_NOTE (DND, - g_print ("gdk_win32_drag_context_find_surface: %p %+d%+d: %p: %p %s\n", + g_print ("gdk_win32_drag_context_find_surface: %p %+d%+d: %p: %p\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))); + (dest_surface ? GDK_SURFACE_HWND (dest_surface) : NULL))); 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) +static DWORD +manufacture_keystate_from_GMT (GdkModifierType state) { - GdkWin32DragContext *context_win32; + DWORD key_state = 0; + + if (state & GDK_MOD1_MASK) + key_state |= MK_ALT; + if (state & GDK_CONTROL_MASK) + key_state |= MK_CONTROL; + if (state & GDK_SHIFT_MASK) + key_state |= MK_SHIFT; + if (state & GDK_BUTTON1_MASK) + key_state |= MK_LBUTTON; + if (state & GDK_BUTTON2_MASK) + key_state |= MK_MBUTTON; + if (state & GDK_BUTTON3_MASK) + key_state |= MK_RBUTTON; + + return key_state; +} + +static gboolean +gdk_win32_local_drag_motion (GdkDragContext *drag, + GdkSurface *dest_surface, + gint x_root, + gint y_root, + GdkDragAction possible_actions, + DWORD key_state, + guint32 time_) +{ + GdkWin32DragContext *drag_win32; + GdkDrop *drop; + GdkDragAction actions; g_assert (_win32_main_thread == NULL || _win32_main_thread == g_thread_self ()); - g_return_val_if_fail (context != NULL, FALSE); + g_return_val_if_fail (drag != NULL, FALSE); - GDK_NOTE (DND, g_print ("gdk_win32_drag_context_drag_motion: @ %+d:%+d %s suggested=%s, possible=%s\n" - " context=%p:{actions=%s,suggested=%s,action=%s}\n", + drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); + + drop = _gdk_win32_get_drop_for_dest_surface (drag->dest_surface); + + actions = gdk_drag_context_get_actions (drag); + + GDK_NOTE (DND, g_print ("gdk_win32_local_drag_motion: @ %+d:%+d possible=%s\n" + " dest=%p (current %p) drop=%p drag=%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 (gdk_drag_context_get_actions (context)), - _gdk_win32_drag_action_to_string (gdk_drag_context_get_suggested_action (context)), - _gdk_win32_drag_action_to_string (context->action))); + dest_surface, drag->dest_surface, drop, drag, + _gdk_win32_drag_action_to_string (actions), + _gdk_win32_drag_action_to_string (gdk_drag_context_get_suggested_action (drag)), + _gdk_win32_drag_action_to_string (drag->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 (drag->dest_surface != dest_surface) { - if (context->dest_surface == dest_surface) - { - GdkDragContext *dest_context; + /* Send a leave to the last destination */ + if (drop) + _gdk_win32_local_drop_target_dragleave (drop, time_); - dest_context = _gdk_win32_drop_context_find (context->source_surface, - dest_surface); + g_set_object (&drag->dest_surface, dest_surface); - if (dest_context) - gdk_drag_context_set_actions (dest_context, possible_actions, suggested_action); + drag_win32->drag_status = GDK_DRAG_STATUS_DRAG; - gdk_drag_context_set_actions (context, possible_actions, suggested_action); - } - else - { - /* Send a leave to the last destination */ - _gdk_win32_drag_do_leave (context, time); + _gdk_win32_local_drop_target_dragenter (drag, dest_surface, x_root, y_root, key_state, time_, &actions); - 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: - _gdk_win32_local_send_enter (context, time); - break; - - default: - break; - } - gdk_drag_context_set_actions (context, possible_actions, suggested_action); - } - else - { - context->dest_surface = NULL; - gdk_drag_context_set_actions (context, 0, 0); - } - - GDK_NOTE (DND, g_print ("gdk_dnd_handle_drag_status: 0x%p\n", - context)); - - if (context->action != context_win32->current_action) - { - context_win32->current_action = context->action; - g_signal_emit_by_name (context, "action-changed", context->action); - } - } - - /* Send a drag-motion event */ - - context_win32->util_data.last_x = x_root; - context_win32->util_data.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_win32_drag_context_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 (gdk_drag_context_get_actions (context)), - _gdk_win32_drag_action_to_string (gdk_drag_context_get_suggested_action (context)), - _gdk_win32_drag_action_to_string (context->action))); - return TRUE; - } - } + drop = _gdk_win32_get_drop_for_dest_surface (drag->dest_surface); + maybe_emit_action_changed (drag_win32, actions); } - GDK_NOTE (DND, g_print (" returning FALSE\n" - " context=%p:{actions=%s,suggested=%s,action=%s}\n", - context, - _gdk_win32_drag_action_to_string (gdk_drag_context_get_actions (context)), - _gdk_win32_drag_action_to_string (gdk_drag_context_get_suggested_action (context)), - _gdk_win32_drag_action_to_string (context->action))); - return FALSE; + /* Send a drag-motion event */ + + drag_win32->util_data.last_x = x_root; + drag_win32->util_data.last_y = y_root; + + if (drop != NULL && + drag_win32->drag_status == GDK_DRAG_STATUS_DRAG && + _gdk_win32_local_drop_target_will_emit_motion (drop, x_root, y_root, key_state)) + { + actions = gdk_drag_context_get_actions (drag); + drag_win32->drag_status = GDK_DRAG_STATUS_MOTION_WAIT; + + _gdk_win32_local_drop_target_dragover (drop, drag, x_root, y_root, key_state, time_, &actions); + + maybe_emit_action_changed (drag_win32, actions); + } + + GDK_NOTE (DND, g_print (" returning %s\n" + " drag=%p:{actions=%s,suggested=%s,action=%s}\n", + (drop != NULL && drag_win32->drag_status == GDK_DRAG_STATUS_DRAG) ? "TRUE" : "FALSE", + drag, + _gdk_win32_drag_action_to_string (gdk_drag_context_get_actions (drag)), + _gdk_win32_drag_action_to_string (gdk_drag_context_get_suggested_action (drag)), + _gdk_win32_drag_action_to_string (drag->action))); + return (drop != NULL && drag_win32->drag_status == GDK_DRAG_STATUS_DRAG); } static void @@ -2175,75 +2011,86 @@ send_source_state_update (GdkWin32Clipdrop *clipdrop, } static void -gdk_win32_drag_context_drag_drop (GdkDragContext *context, - guint32 time) +gdk_win32_drag_context_drag_drop (GdkDragContext *drag, + guint32 time_) { + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get (); g_assert (_win32_main_thread == NULL || _win32_main_thread == g_thread_self ()); - g_return_if_fail (context != NULL); + g_return_if_fail (drag != NULL); - GDK_NOTE (DND, g_print ("gdk_drag_drop\n")); + GDK_NOTE (DND, g_print ("gdk_win32_drag_context_drag_drop\n")); - if (!use_ole2_dnd) + if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL) { - if (context->dest_surface && - GDK_WIN32_DRAG_CONTEXT (context)->protocol == GDK_DRAG_PROTO_LOCAL) - local_send_drop (context, time); + GdkDrop *drop; + drop = _gdk_win32_get_drop_for_dest_surface (drag->dest_surface); + + if (drop) + { + GdkDragAction actions; + + actions = gdk_drag_context_get_actions (drag); + _gdk_win32_local_drop_target_drop (drop, drag, time_, &actions); + maybe_emit_action_changed (drag_win32, actions); + _gdk_win32_local_drag_context_drop_response (drag, actions); + } } - else + else if (drag_win32->protocol == GDK_DRAG_PROTO_OLE2) { - gpointer ddd = g_hash_table_lookup (clipdrop->active_source_drags, context); + gpointer ddd = g_hash_table_lookup (clipdrop->active_source_drags, drag); - GDK_WIN32_DRAG_CONTEXT (context)->util_data.state = GDK_WIN32_DND_DROPPED; + drag_win32->util_data.state = GDK_WIN32_DND_DROPPED; if (ddd) - send_source_state_update (clipdrop, GDK_WIN32_DRAG_CONTEXT (context), ddd); + send_source_state_update (clipdrop, drag_win32, ddd); } } static void -gdk_win32_drag_context_drag_abort (GdkDragContext *context, - guint32 time) +gdk_win32_drag_context_drag_abort (GdkDragContext *drag, + guint32 time_) { + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get (); g_assert (_win32_main_thread == NULL || _win32_main_thread == g_thread_self ()); - g_return_if_fail (context != NULL); + g_return_if_fail (drag != NULL); - GDK_NOTE (DND, g_print ("gdk_drag_abort\n")); + GDK_NOTE (DND, g_print ("gdk_win32_drag_context_drag_abort\n")); - if (use_ole2_dnd) + if (drag_win32->protocol == GDK_DRAG_PROTO_OLE2) { - gpointer ddd = g_hash_table_lookup (clipdrop->active_source_drags, context); + gpointer ddd = g_hash_table_lookup (clipdrop->active_source_drags, drag); - GDK_WIN32_DRAG_CONTEXT (context)->util_data.state = GDK_WIN32_DND_NONE; + drag_win32->util_data.state = GDK_WIN32_DND_NONE; if (ddd) - send_source_state_update (clipdrop, GDK_WIN32_DRAG_CONTEXT (context), ddd); + send_source_state_update (clipdrop, drag_win32, ddd); } } static void -gdk_win32_drag_context_set_cursor (GdkDragContext *context, +gdk_win32_drag_context_set_cursor (GdkDragContext *drag, GdkCursor *cursor) { - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); - GDK_NOTE (DND, g_print ("gdk_drag_context_set_cursor: 0x%p 0x%p\n", context, cursor)); + GDK_NOTE (DND, g_print ("gdk_win32_drag_context_set_cursor: 0x%p 0x%p\n", drag, cursor)); - if (!g_set_object (&context_win32->cursor, cursor)) + if (!g_set_object (&drag_win32->cursor, cursor)) return; - if (context_win32->grab_seat) + if (drag_win32->grab_seat) { G_GNUC_BEGIN_IGNORE_DEPRECATIONS; - gdk_device_grab (gdk_seat_get_pointer (context_win32->grab_seat), - context_win32->ipc_window, + gdk_device_grab (gdk_seat_get_pointer (drag_win32->grab_seat), + drag_win32->ipc_window, GDK_OWNERSHIP_APPLICATION, FALSE, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, GDK_CURRENT_TIME); @@ -2262,7 +2109,7 @@ ease_out_cubic (double t) typedef struct _GdkDragAnim GdkDragAnim; struct _GdkDragAnim { - GdkWin32DragContext *context; + GdkWin32DragContext *drag; GdkFrameClock *frame_clock; gint64 start_time; }; @@ -2270,7 +2117,7 @@ struct _GdkDragAnim { static void gdk_drag_anim_destroy (GdkDragAnim *anim) { - g_object_unref (anim->context); + g_object_unref (anim->drag); g_slice_free (GdkDragAnim, anim); } @@ -2278,7 +2125,7 @@ static gboolean gdk_drag_anim_timeout (gpointer data) { GdkDragAnim *anim = data; - GdkWin32DragContext *context = anim->context; + GdkWin32DragContext *drag = anim->drag; GdkFrameClock *frame_clock = anim->frame_clock; gint64 current_time; double f; @@ -2296,20 +2143,20 @@ gdk_drag_anim_timeout (gpointer data) t = ease_out_cubic (f); - gdk_surface_show (context->drag_surface); - gdk_surface_move (context->drag_surface, - context->util_data.last_x + (context->start_x - context->util_data.last_x) * t - context->hot_x, - context->util_data.last_y + (context->start_y - context->util_data.last_y) * t - context->hot_y); - gdk_surface_set_opacity (context->drag_surface, 1.0 - f); + gdk_surface_show (drag->drag_surface); + gdk_surface_move (drag->drag_surface, + drag->util_data.last_x + (drag->start_x - drag->util_data.last_x) * t - drag->hot_x, + drag->util_data.last_y + (drag->start_y - drag->util_data.last_y) * t - drag->hot_y); + gdk_surface_set_opacity (drag->drag_surface, 1.0 - f); return G_SOURCE_CONTINUE; } static void -gdk_win32_drag_context_drop_done (GdkDragContext *context, +gdk_win32_drag_context_drop_done (GdkDragContext *drag, gboolean success) { - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); GdkDragAnim *anim; /* cairo_surface_t *win_surface; @@ -2318,40 +2165,46 @@ gdk_win32_drag_context_drop_done (GdkDragContext *context, */ guint id; - GDK_NOTE (DND, g_print ("gdk_drag_context_drop_done: 0x%p %s\n", - context, + GDK_NOTE (DND, g_print ("gdk_win32_drag_context_drop_done: 0x%p %s\n", + drag, success ? "dropped successfully" : "dropped unsuccessfully")); /* FIXME: This is temporary, until the code is fixed to ensure that * gdk_drag_finish () is called by GTK. */ - if (use_ole2_dnd) + if (drag_win32->protocol == GDK_DRAG_PROTO_OLE2) { GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get (); - gpointer ddd = g_hash_table_lookup (clipdrop->active_source_drags, context); + gpointer ddd = g_hash_table_lookup (clipdrop->active_source_drags, drag); if (success) - win32_context->util_data.state = GDK_WIN32_DND_DROPPED; + drag_win32->util_data.state = GDK_WIN32_DND_DROPPED; else - win32_context->util_data.state = GDK_WIN32_DND_NONE; + drag_win32->util_data.state = GDK_WIN32_DND_NONE; if (ddd) - send_source_state_update (clipdrop, win32_context, ddd); + send_source_state_update (clipdrop, drag_win32, ddd); } + else if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL) + { + + } + + drag_win32->handle_events = FALSE; if (success) { - gdk_surface_hide (win32_context->drag_surface); + gdk_surface_hide (drag_win32->drag_surface); return; } /* - win_surface = _gdk_surface_ref_cairo_surface (win32_context->drag_surface); - surface = gdk_surface_create_similar_surface (win32_context->drag_surface, + win_surface = _gdk_surface_ref_cairo_surface (drag_win32->drag_surface); + surface = gdk_surface_create_similar_surface (drag_win32->drag_surface, cairo_surface_get_content (win_surface), - gdk_surface_get_width (win32_context->drag_surface), - gdk_surface_get_height (win32_context->drag_surface)); + gdk_surface_get_width (drag_win32->drag_surface), + gdk_surface_get_height (drag_win32->drag_surface)); cr = cairo_create (surface); cairo_set_source_surface (cr, win_surface, 0, 0); cairo_paint (cr); @@ -2360,20 +2213,20 @@ gdk_win32_drag_context_drop_done (GdkDragContext *context, pattern = cairo_pattern_create_for_surface (surface); - gdk_surface_set_background_pattern (win32_context->drag_surface, pattern); + gdk_surface_set_background_pattern (drag_win32->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); + g_set_object (&anim->drag, drag_win32); + anim->frame_clock = gdk_surface_get_frame_clock (drag_win32->drag_surface); anim->start_time = gdk_frame_clock_get_frame_time (anim->frame_clock); - GDK_NOTE (DND, g_print ("gdk_drag_context_drop_done: animate the drag window from %d : %d to %d : %d\n", - win32_context->util_data.last_x, win32_context->util_data.last_y, - win32_context->start_x, win32_context->start_y)); + GDK_NOTE (DND, g_print ("gdk_win32_drag_context_drop_done: animate the drag window from %d : %d to %d : %d\n", + drag_win32->util_data.last_x, drag_win32->util_data.last_y, + drag_win32->start_x, drag_win32->start_y)); id = g_timeout_add_full (G_PRIORITY_DEFAULT, 17, gdk_drag_anim_timeout, anim, @@ -2382,29 +2235,33 @@ gdk_win32_drag_context_drop_done (GdkDragContext *context, } static gboolean -drag_context_grab (GdkDragContext *context) +drag_context_grab (GdkDragContext *drag) { - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); GdkSeatCapabilities capabilities; GdkSeat *seat; GdkCursor *cursor; - if (!context_win32->ipc_window) + GDK_NOTE (DND, g_print ("drag_context_grab: 0x%p with ipc window 0x%p\n", + drag, + drag_win32->ipc_window)); + + if (!drag_win32->ipc_window) return FALSE; - seat = gdk_device_get_seat (gdk_drag_context_get_device (context)); + seat = gdk_device_get_seat (gdk_drag_context_get_device (drag)); 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); + cursor = gdk_drag_get_cursor (drag, gdk_drag_context_get_selected_action (drag)); + g_set_object (&drag_win32->cursor, cursor); - if (gdk_seat_grab (seat, context_win32->ipc_window, + if (gdk_seat_grab (seat, drag_win32->ipc_window, capabilities, FALSE, - context_win32->cursor, NULL, NULL, NULL) != GDK_GRAB_SUCCESS) + drag_win32->cursor, NULL, NULL, NULL) != GDK_GRAB_SUCCESS) return FALSE; - g_set_object (&context_win32->grab_seat, seat); + g_set_object (&drag_win32->grab_seat, seat); /* TODO: Should be grabbing keys here, to support keynav. SetWindowsHookEx()? */ @@ -2412,24 +2269,30 @@ drag_context_grab (GdkDragContext *context) } static void -drag_context_ungrab (GdkDragContext *context) +drag_context_ungrab (GdkDragContext *drag) { - GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); - if (!context_win32->grab_seat) + GDK_NOTE (DND, g_print ("drag_context_ungrab: 0x%p 0x%p\n", + drag, + drag_win32->grab_seat)); + + if (!drag_win32->grab_seat) return; - gdk_seat_ungrab (context_win32->grab_seat); + gdk_seat_ungrab (drag_win32->grab_seat); - g_clear_object (&context_win32->grab_seat); + g_clear_object (&drag_win32->grab_seat); /* TODO: Should be ungrabbing keys here */ } static void -gdk_win32_drag_context_cancel (GdkDragContext *context, +gdk_win32_drag_context_cancel (GdkDragContext *drag, GdkDragCancelReason reason) { + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); + const gchar *reason_str = NULL; switch (reason) { @@ -2447,185 +2310,119 @@ gdk_win32_drag_context_cancel (GdkDragContext *context, break; } - GDK_NOTE (DND, g_print ("gdk_drag_context_cancel: 0x%p %s\n", - context, + GDK_NOTE (DND, g_print ("gdk_win32_drag_context_cancel: 0x%p %s\n", + drag, reason_str)); - drag_context_ungrab (context); - gdk_drag_drop_done (context, FALSE); + + if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL) + { + GdkDrop *drop = _gdk_win32_get_drop_for_dest_surface (drag->dest_surface); + if (drop) + _gdk_win32_local_drop_target_dragleave (drop, GDK_CURRENT_TIME); + drop = NULL; + } + + gdk_drag_context_set_cursor (drag, NULL); + drag_context_ungrab (drag); + gdk_drag_drop_done (drag, FALSE); } static void -gdk_win32_drag_context_drop_performed (GdkDragContext *context, +gdk_win32_drag_context_drop_performed (GdkDragContext *drag, guint32 time_) { - GDK_NOTE (DND, g_print ("gdk_drag_context_drop_performed: 0x%p %u\n", - context, + GDK_NOTE (DND, g_print ("gdk_win32_drag_context_drop_performed: 0x%p %u\n", + drag, time_)); - gdk_drag_drop (context, time_); - drag_context_ungrab (context); + gdk_drag_drop (drag, time_); + gdk_drag_context_set_cursor (drag, NULL); + drag_context_ungrab (drag); } #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) +gdk_local_drag_update (GdkDragContext *drag, + gdouble x_root, + gdouble y_root, + DWORD grfKeyState, + guint32 evtime) { - *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; + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); GdkSurface *dest_surface; - GdkDragProtocol protocol; g_assert (_win32_main_thread == NULL || _win32_main_thread == g_thread_self ()); - gdk_drag_get_current_actions (mods, GDK_BUTTON_PRIMARY, win32_context->actions, - &action, &possible_actions); + dest_surface = gdk_win32_drag_context_find_surface (drag, + drag_win32->drag_surface, + x_root, y_root); - dest_surface = gdk_win32_drag_context_find_surface (context, - win32_context->drag_surface, - x_root, y_root, &protocol); - - gdk_win32_drag_context_drag_motion (context, dest_surface, protocol, x_root, y_root, - action, possible_actions, evtime); + gdk_win32_local_drag_motion (drag, dest_surface, x_root, y_root, + gdk_drag_context_get_actions (drag), + grfKeyState, evtime); } static gboolean -gdk_dnd_handle_motion_event (GdkDragContext *context, +gdk_dnd_handle_motion_event (GdkDragContext *drag, const GdkEventMotion *event) { GdkModifierType state; + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); + DWORD key_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)); + drag)); - gdk_drag_update (context, event->x_root, event->y_root, state, - gdk_event_get_time ((GdkEvent *) event)); + if (drag_win32->drag_surface) + move_drag_surface (drag, event->x_root, event->y_root); + key_state = manufacture_keystate_from_GMT (state); - if (use_ole2_dnd) + if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL) + { + gdk_local_drag_update (drag, event->x_root, event->y_root, key_state, + gdk_event_get_time ((GdkEvent *) event)); + } + else if (drag_win32->protocol == GDK_DRAG_PROTO_OLE2) { GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get (); - GdkWin32DragContext *context_win32; - DWORD key_state = 0; - BYTE kbd_state[256]; - - /* TODO: is this correct? We get the state at current moment, - * not at the moment when the event was emitted. - * I don't think that it ultimately serves any purpose, - * as our IDropSource does not react to the keyboard - * state changes (rather, it reacts to our status updates), - * but there's no way to tell what goes inside DoDragDrop(), - * so we should send at least *something* that looks right. - */ - API_CALL (GetKeyboardState, (kbd_state)); - - if (kbd_state[VK_CONTROL] & 0x80) - key_state |= MK_CONTROL; - if (kbd_state[VK_SHIFT] & 0x80) - key_state |= MK_SHIFT; - if (kbd_state[VK_LBUTTON] & 0x80) - key_state |= MK_LBUTTON; - if (kbd_state[VK_MBUTTON] & 0x80) - key_state |= MK_MBUTTON; - if (kbd_state[VK_RBUTTON] & 0x80) - key_state |= MK_RBUTTON; GDK_NOTE (DND, g_print ("Post WM_MOUSEMOVE keystate=%lu\n", key_state)); - context_win32 = GDK_WIN32_DRAG_CONTEXT (context); - - context_win32->util_data.last_x = event->x_root; - context_win32->util_data.last_y = event->y_root; + drag_win32->util_data.last_x = event->x_root; + drag_win32->util_data.last_y = event->y_root; API_CALL (PostThreadMessage, (clipdrop->dnd_thread_id, WM_MOUSEMOVE, key_state, - MAKELPARAM ((event->x_root - _gdk_offset_x) * context_win32->scale, - (event->y_root - _gdk_offset_y) * context_win32->scale))); + MAKELPARAM ((event->x_root - _gdk_offset_x) * drag_win32->scale, + (event->y_root - _gdk_offset_y) * drag_win32->scale))); } return TRUE; } static gboolean -gdk_dnd_handle_key_event (GdkDragContext *context, +gdk_dnd_handle_key_event (GdkDragContext *drag, const GdkEventKey *event) { - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); GdkModifierType state; GdkDevice *pointer; gint dx, dy; + if (!gdk_event_get_state ((GdkEvent *) event, &state)) + return FALSE; + GDK_NOTE (DND, g_print ("gdk_dnd_handle_key_event: 0x%p\n", - context)); + drag)); dx = dy = 0; - state = event->state; pointer = gdk_device_get_associated_device (gdk_event_get_device ((GdkEvent *) event)); if (event->any.type == GDK_KEY_PRESS) @@ -2633,7 +2430,7 @@ gdk_dnd_handle_key_event (GdkDragContext *context, switch (event->keyval) { case GDK_KEY_Escape: - gdk_drag_context_cancel (context, GDK_DRAG_CANCEL_USER_CANCELLED); + gdk_drag_context_cancel (drag, GDK_DRAG_CANCEL_USER_CANCELLED); return TRUE; case GDK_KEY_space: @@ -2641,14 +2438,14 @@ gdk_dnd_handle_key_event (GdkDragContext *context, 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)) + if ((gdk_drag_context_get_selected_action (drag) != 0) && + (gdk_drag_context_get_dest_surface (drag) != NULL)) { - g_signal_emit_by_name (context, "drop-performed", + g_signal_emit_by_name (drag, "drop-performed", gdk_event_get_time ((GdkEvent *) event)); } else - gdk_drag_context_cancel (context, GDK_DRAG_CANCEL_NO_TARGET); + gdk_drag_context_cancel (drag, GDK_DRAG_CANCEL_NO_TARGET); return TRUE; @@ -2681,89 +2478,101 @@ gdk_dnd_handle_key_event (GdkDragContext *context, if (dx != 0 || dy != 0) { - win32_context->util_data.last_x += dx; - win32_context->util_data.last_y += dy; - gdk_device_warp (pointer, win32_context->util_data.last_x, win32_context->util_data.last_y); + drag_win32->util_data.last_x += dx; + drag_win32->util_data.last_y += dy; + gdk_device_warp (pointer, drag_win32->util_data.last_x, drag_win32->util_data.last_y); } - gdk_drag_update (context, win32_context->util_data.last_x, win32_context->util_data.last_y, state, - gdk_event_get_time ((GdkEvent *) event)); + if (drag_win32->drag_surface) + move_drag_surface (drag, drag_win32->util_data.last_x, drag_win32->util_data.last_y); + + if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL) + gdk_local_drag_update (drag, drag_win32->util_data.last_x, drag_win32->util_data.last_y, + manufacture_keystate_from_GMT (state), + gdk_event_get_time ((GdkEvent *) event)); return TRUE; } static gboolean -gdk_dnd_handle_grab_broken_event (GdkDragContext *context, +gdk_dnd_handle_grab_broken_event (GdkDragContext *drag, const GdkEventGrabBroken *event) { - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); GDK_NOTE (DND, g_print ("gdk_dnd_handle_grab_broken_event: 0x%p\n", - context)); + drag)); /* 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_surface == win32_context->drag_surface || - event->grab_surface == win32_context->ipc_window) + event->grab_surface == drag_win32->drag_surface || + event->grab_surface == drag_win32->ipc_window) return FALSE; if (gdk_event_get_device ((GdkEvent *) event) != - gdk_drag_context_get_device (context)) + gdk_drag_context_get_device (drag)) return FALSE; - gdk_drag_context_cancel (context, GDK_DRAG_CANCEL_ERROR); + gdk_drag_context_cancel (drag, GDK_DRAG_CANCEL_ERROR); return TRUE; } static gboolean -gdk_dnd_handle_button_event (GdkDragContext *context, +gdk_dnd_handle_button_event (GdkDragContext *drag, const GdkEventButton *event) { GDK_NOTE (DND, g_print ("gdk_dnd_handle_button_event: 0x%p\n", - context)); + drag)); #if 0 /* FIXME: Check the button matches */ - if (event->button != win32_context->button) + if (event->button != drag_win32->button) return FALSE; #endif - if ((gdk_drag_context_get_selected_action (context) != 0)) + if ((gdk_drag_context_get_selected_action (drag) != 0)) { - g_signal_emit_by_name (context, "drop-performed", + g_signal_emit_by_name (drag, "drop-performed", gdk_event_get_time ((GdkEvent *) event)); } else - gdk_drag_context_cancel (context, GDK_DRAG_CANCEL_NO_TARGET); + gdk_drag_context_cancel (drag, GDK_DRAG_CANCEL_NO_TARGET); - return TRUE; + /* Make sure GTK gets mouse release button event */ + return FALSE; } gboolean -gdk_win32_drag_context_handle_event (GdkDragContext *context, +gdk_win32_drag_context_handle_event (GdkDragContext *drag, const GdkEvent *event) { - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); - if (!context->is_source) + if (!drag->is_source) return FALSE; - if (!win32_context->grab_seat) + if (!drag_win32->grab_seat) return FALSE; + if (!drag_win32->handle_events) + { + /* FIXME: remove this functionality once gtk no longer calls DnD after drag_done() */ + g_warning ("Got an event %d for drag context %p, even though it's done!", event->any.type, drag); + return FALSE; + } switch (event->any.type) { case GDK_MOTION_NOTIFY: - return gdk_dnd_handle_motion_event (context, &event->motion); + return gdk_dnd_handle_motion_event (drag, &event->motion); case GDK_BUTTON_RELEASE: - return gdk_dnd_handle_button_event (context, &event->button); + return gdk_dnd_handle_button_event (drag, &event->button); case GDK_KEY_PRESS: case GDK_KEY_RELEASE: - return gdk_dnd_handle_key_event (context, &event->key); + return gdk_dnd_handle_key_event (drag, &event->key); case GDK_GRAB_BROKEN: - return gdk_dnd_handle_grab_broken_event (context, &event->grab_broken); + return gdk_dnd_handle_grab_broken_event (drag, &event->grab_broken); default: break; } @@ -2772,39 +2581,39 @@ gdk_win32_drag_context_handle_event (GdkDragContext *context, } void -gdk_win32_drag_context_action_changed (GdkDragContext *context, +gdk_win32_drag_context_action_changed (GdkDragContext *drag, GdkDragAction action) { GdkCursor *cursor; - cursor = gdk_drag_get_cursor (context, action); - gdk_drag_context_set_cursor (context, cursor); + cursor = gdk_drag_get_cursor (drag, action); + gdk_drag_context_set_cursor (drag, cursor); } static GdkSurface * -gdk_win32_drag_context_get_drag_surface (GdkDragContext *context) +gdk_win32_drag_context_get_drag_surface (GdkDragContext *drag) { - return GDK_WIN32_DRAG_CONTEXT (context)->drag_surface; + return GDK_WIN32_DRAG_CONTEXT (drag)->drag_surface; } static void -gdk_win32_drag_context_set_hotspot (GdkDragContext *context, +gdk_win32_drag_context_set_hotspot (GdkDragContext *drag, gint hot_x, gint hot_y) { - GdkWin32DragContext *win32_context = GDK_WIN32_DRAG_CONTEXT (context); + GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag); GDK_NOTE (DND, g_print ("gdk_drag_context_set_hotspot: 0x%p %d:%d\n", - context, + drag, hot_x, hot_y)); - win32_context->hot_x = hot_x; - win32_context->hot_y = hot_y; + drag_win32->hot_x = hot_x; + drag_win32->hot_y = hot_y; - if (win32_context->grab_seat) + if (drag_win32->grab_seat) { /* DnD is managed, update current position */ - move_drag_surface (context, win32_context->util_data.last_x, win32_context->util_data.last_y); + move_drag_surface (drag, drag_win32->util_data.last_x, drag_win32->util_data.last_y); } } diff --git a/gdk/win32/gdkdrop-win32.c b/gdk/win32/gdkdrop-win32.c index 17f0738d88..6d7ff78e7a 100644 --- a/gdk/win32/gdkdrop-win32.c +++ b/gdk/win32/gdkdrop-win32.c @@ -62,133 +62,161 @@ #include #include -typedef struct +#define GDK_TYPE_WIN32_DROP (gdk_win32_drop_get_type ()) +#define GDK_WIN32_DROP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WIN32_DROP, GdkWin32Drop)) +#define GDK_WIN32_DROP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WIN32_DROP, GdkWin32DropClass)) +#define GDK_IS_WIN32_DROP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WIN32_DROP)) +#define GDK_IS_WIN32_DROP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WIN32_DROP)) +#define GDK_WIN32_DROP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WIN32_DROP, GdkWin32DropClass)) + +typedef struct _GdkWin32Drop GdkWin32Drop; +typedef struct _GdkWin32DropClass GdkWin32DropClass; + +struct _GdkWin32Drop +{ + GdkDrop drop; + + /* The drag protocol being in use */ + GdkDragProtocol protocol; + + /* The actions supported at GTK level. Set in gdk_win32_drop_status(). */ + GdkDragAction actions; + + guint scale; /* Temporarily caches the HiDPI scale */ + gint last_x; /* Coordinates from last event, in GDK space */ + gint last_y; + DWORD last_key_state; /* Key state from last event */ + + /* Just like GdkDrop->formats, but an array, and with format IDs + * stored inside. + */ + GArray *droptarget_w32format_contentformat_map; + + /* The list from WM_DROPFILES is store here temporarily, + * until the next gdk_win32_drop_read_async () + */ + gchar *dropfiles_list; + + guint drop_finished : 1; /* FALSE until gdk_drop_finish() is called */ + guint drop_failed : 1; /* Whether the drop was unsuccessful */ +}; + +struct _GdkWin32DropClass +{ + GdkDropClass parent_class; +}; + +GType gdk_win32_drop_get_type (void); + +G_DEFINE_TYPE (GdkWin32Drop, gdk_win32_drop, GDK_TYPE_DROP) + +/* This structure is presented to COM as an object that + * implements IDropTarget interface. Every surface that + * can be a droptarget has one of these. + */ +struct _drop_target_context { IDropTarget idt; gint ref_count; - GdkDragContext *context; - /* We get this at the object creation time and keep - * it indefinitely. Contexts come and go, but this window - * remains the same. + + /* The drop object we create when a drag enters our surface. + * The drop objóct is destroyed when the drag leaves. */ - GdkSurface *dest_surface; + GdkDrop *drop; + /* We get this at the object at creation time and keep + * it indefinitely. Drops (see above) come and go, but + * this surface remains the same. + * This is not a reference, as drop_target_context must not + * outlive the surface it's attached to. + * drop_target_context is not folded into GdkSurfaceImplWin32 + * only because it's easier to present it to COM as a separate + * object when it's allocated separately. + */ + GdkSurface *surface; /* This is given to us by the OS, we store it here - * until the drag leaves our window. + * until the drag leaves our window. It is referenced + * (using COM reference counting). */ IDataObject *data_object; -} target_drag_context; - -static GList *dnd_target_contexts; -static GdkDragContext *current_dest_drag = NULL; +}; +/* TRUE to use OLE2 protocol, FALSE to use local protocol */ static gboolean use_ole2_dnd = TRUE; -G_DEFINE_TYPE (GdkWin32DropContext, gdk_win32_drop_context, GDK_TYPE_DRAG_CONTEXT) - static void -gdk_win32_drop_context_init (GdkWin32DropContext *context) +gdk_win32_drop_init (GdkWin32Drop *drop) { - if (!use_ole2_dnd) - { - dnd_target_contexts = g_list_prepend (dnd_target_contexts, context); - } - else - { - } + drop->droptarget_w32format_contentformat_map = g_array_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair)); - GDK_NOTE (DND, g_print ("gdk_drop_context_init %p\n", context)); + GDK_NOTE (DND, g_print ("gdk_win32_drop_init %p\n", drop)); } static void -gdk_win32_drop_context_finalize (GObject *object) +gdk_win32_drop_finalize (GObject *object) { - GdkDragContext *context; - GdkWin32DropContext *context_win32; + GdkDrop *drop; + GdkWin32Drop *drop_win32; - GDK_NOTE (DND, g_print ("gdk_drop_context_finalize %p\n", object)); + GDK_NOTE (DND, g_print ("gdk_win32_drop_finalize %p\n", object)); - g_return_if_fail (GDK_IS_WIN32_DROP_CONTEXT (object)); + drop = GDK_DROP (object); - context = GDK_DRAG_CONTEXT (object); - context_win32 = GDK_WIN32_DROP_CONTEXT (context); + drop_win32 = GDK_WIN32_DROP (drop); - if (!use_ole2_dnd) - { - dnd_target_contexts = g_list_remove (dnd_target_contexts, context); + g_array_unref (drop_win32->droptarget_w32format_contentformat_map); - if (context == current_dest_drag) - current_dest_drag = NULL; - } - - g_clear_object (&context_win32->local_source_context); - - g_array_unref (context_win32->droptarget_w32format_contentformat_map); - - G_OBJECT_CLASS (gdk_win32_drop_context_parent_class)->finalize (object); + G_OBJECT_CLASS (gdk_win32_drop_parent_class)->finalize (object); } -/* Drag Contexts */ - -static GdkDragContext * -gdk_drop_context_new (GdkDisplay *display, - GdkSurface *source_surface, - GdkSurface *dest_surface, - GdkContentFormats *formats, - GdkDragAction actions, - GdkDragProtocol protocol) +static GdkDrop * +gdk_drop_new (GdkDisplay *display, + GdkDevice *device, + GdkDragContext *drag, + GdkContentFormats *formats, + GdkSurface *surface, + GdkDragProtocol protocol) { - GdkWin32DropContext *context_win32; + GdkWin32Drop *drop_win32; GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display); - GdkDragContext *context; - context_win32 = g_object_new (GDK_TYPE_WIN32_DROP_CONTEXT, - "device", gdk_seat_get_pointer (gdk_display_get_default_seat (display)), - "formats", formats, - "surface", dest_surface, - NULL); - - context = GDK_DRAG_CONTEXT (context_win32); + drop_win32 = g_object_new (GDK_TYPE_WIN32_DROP, + "device", device, + "drag", drag, + "formats", formats, + "surface", surface, + NULL); if (win32_display->has_fixed_scale) - context_win32->scale = win32_display->surface_scale; + drop_win32->scale = win32_display->surface_scale; else - context_win32->scale = _gdk_win32_display_get_monitor_scale_factor (win32_display, NULL, NULL, NULL); + drop_win32->scale = _gdk_win32_display_get_monitor_scale_factor (win32_display, NULL, NULL, NULL); - context_win32->droptarget_w32format_contentformat_map = g_array_new (FALSE, FALSE, sizeof (GdkWin32ContentFormatPair)); + drop_win32->protocol = protocol; - context->is_source = FALSE; - g_set_object (&context->source_surface, source_surface); - g_set_object (&context->dest_surface, dest_surface); - gdk_drag_context_set_actions (context, actions, actions); - context_win32->protocol = protocol; - - gdk_content_formats_unref (formats); - - return context; + return GDK_DROP (drop_win32); } -GdkDragContext * -_gdk_win32_drop_context_find (GdkSurface *source, - GdkSurface *dest) +/* Gets the GdkDrop that corresponds to a particular GdkSurface. + * Will be NULL for surfaces that are not registered as drop targets, + * or for surfaces that are currently not under the drag cursor. + */ +GdkDrop * +_gdk_win32_get_drop_for_dest_surface (GdkSurface *dest) { - GList *tmp_list = dnd_target_contexts; - GdkDragContext *context; + GdkSurfaceImplWin32 *impl; - while (tmp_list) - { - context = (GdkDragContext *) tmp_list->data; + if (dest == NULL) + return NULL; - if (!context->is_source && - ((source == NULL) || (context->source_surface && (context->source_surface == source))) && - ((dest == NULL) || (context->dest_surface && (context->dest_surface == dest)))) - return context; + impl = GDK_SURFACE_IMPL_WIN32 (dest->impl); - tmp_list = tmp_list->next; - } + if (impl->drop_target != NULL) + return impl->drop_target->drop; - return NULL; + return impl->drop; } + #define PRINT_GUID(guid) \ g_print ("%.08lx-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x", \ ((gulong *) guid)[0], \ @@ -203,21 +231,10 @@ _gdk_win32_drop_context_find (GdkSurface *source, ((guchar *) guid)[14], \ ((guchar *) guid)[15]); -/* map windows -> target drag contexts. The table - * owns a ref to each context. - */ -static GHashTable* target_ctx_for_window = NULL; - -static target_drag_context * -find_droptarget_for_target_context (GdkDragContext *context) -{ - return g_hash_table_lookup (target_ctx_for_window, GDK_SURFACE_HWND (context->dest_surface)); -} - static ULONG STDMETHODCALLTYPE idroptarget_addref (LPDROPTARGET This) { - target_drag_context *ctx = (target_drag_context *) This; + drop_target_context *ctx = (drop_target_context *) This; int ref_count = ++ctx->ref_count; @@ -262,7 +279,7 @@ idroptarget_queryinterface (LPDROPTARGET This, static ULONG STDMETHODCALLTYPE idroptarget_release (LPDROPTARGET This) { - target_drag_context *ctx = (target_drag_context *) This; + drop_target_context *ctx = (drop_target_context *) This; int ref_count = --ctx->ref_count; @@ -270,66 +287,24 @@ idroptarget_release (LPDROPTARGET This) if (ref_count == 0) { - g_object_unref (ctx->context); - g_clear_object (&ctx->dest_surface); + g_clear_object (&ctx->drop); g_free (This); } return ref_count; } -static GdkDragAction -get_suggested_action (GdkWin32DropContext *win32_context, - 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; - else if (win32_context->local_source_context && - win32_context->local_source_context->util_data.state == GDK_WIN32_DND_DRAGGING) - return GDK_ACTION_MOVE; - else - return GDK_ACTION_COPY; - /* Any way to determine when to add in DROPEFFECT_SCROLL? */ -} - -static DWORD -drop_effect_for_action (GdkDragAction action) -{ - DWORD effect = 0; - - if (action & GDK_ACTION_MOVE) - effect |= DROPEFFECT_MOVE; - if (action & GDK_ACTION_LINK) - effect |= DROPEFFECT_LINK; - if (action & GDK_ACTION_COPY) - effect |= DROPEFFECT_COPY; - - if (effect == 0) - effect = DROPEFFECT_NONE; - - return effect; -} - static GdkContentFormats * -query_targets (LPDATAOBJECT pDataObj, - GArray *format_target_map) +query_object_formats (LPDATAOBJECT pDataObj, + GArray *w32format_contentformat_map) { IEnumFORMATETC *pfmt = NULL; FORMATETC fmt; - GList *result = NULL; HRESULT hr; GdkContentFormatsBuilder *builder; GdkContentFormats *result_formats; - GList *p; + + builder = gdk_content_formats_builder_new (); hr = IDataObject_EnumFormatEtc (pDataObj, DATADIR_GET, &pfmt); @@ -349,20 +324,14 @@ query_targets (LPDATAOBJECT pDataObj, GDK_NOTE (DND, g_print ("supported unnamed? source format 0x%x\n", fmt.cfFormat)); g_free (registered_name); - _gdk_win32_add_w32format_to_pairs (fmt.cfFormat, format_target_map, &result); + _gdk_win32_add_w32format_to_pairs (fmt.cfFormat, w32format_contentformat_map, builder); 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; } @@ -379,63 +348,276 @@ set_data_object (LPDATAOBJECT *location, LPDATAOBJECT data_object) IDataObject_AddRef (*location); } +/* Figures out an action that the user forces onto us by + * pressing some modifier keys. + */ +static GdkDragAction +get_user_action (DWORD grfKeyState) +{ + /* Windows explorer does this: + * 'C'ontrol for 'C'opy + * a'L't (or Contro'L' + Shift) for 'L'ink + * Shift for Move + * Control + Alt or Shift + Alt or Control + Alt + Shift for Default action (see below). + * + * Default action is 'Copy' when dragging between drives, 'Move' otherwise. + * For GTK 'between drives' turns into 'between applications'. + */ + if (((grfKeyState & (MK_CONTROL | MK_ALT)) == (MK_CONTROL | MK_ALT)) || + ((grfKeyState & (MK_ALT | MK_SHIFT)) == (MK_ALT | MK_SHIFT)) || + ((grfKeyState & (MK_CONTROL | MK_ALT | MK_SHIFT)) == (MK_CONTROL | MK_ALT | MK_SHIFT))) + { + return 0; + } + else if ((grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT)) + return GDK_ACTION_LINK; + else if (grfKeyState & MK_CONTROL) + return GDK_ACTION_COPY; + else if (grfKeyState & MK_ALT) + return GDK_ACTION_MOVE; + + return 0; +} + +static DWORD +drop_effect_for_actions (GdkDragAction actions) +{ + DWORD effects = 0; + int effect_count = 0; + + if (actions & GDK_ACTION_MOVE) + { + effects |= DROPEFFECT_MOVE; + effect_count++; + } + if (actions & GDK_ACTION_LINK) + { + effects |= DROPEFFECT_LINK; + effect_count++; + } + if (actions & GDK_ACTION_COPY) + { + effects |= DROPEFFECT_COPY; + effect_count++; + } + + if (effect_count == 0) + effects = DROPEFFECT_NONE; + else if (effect_count > 1) + /* Actually it should be DROPEFECT_ASK, but Windows doesn't support that */ + effects = DROPEFFECT_COPY; + + return effects; +} + +static GdkDragAction +actions_for_drop_effects (DWORD effects) +{ + GdkDragAction actions = 0; + + if (effects & DROPEFFECT_MOVE) + actions |= GDK_ACTION_MOVE; + if (effects & DROPEFFECT_LINK) + actions |= GDK_ACTION_LINK; + if (effects & DROPEFFECT_COPY) + actions |= GDK_ACTION_COPY; + + return actions; +} + +static GdkDragAction +filter_actions (GdkDragAction actions, + GdkDragAction filter) +{ + return actions & filter; +} + +static GdkDragAction +set_source_actions_helper (GdkDrop *drop, + GdkDragAction actions, + DWORD grfKeyState) +{ + GdkDragAction user_action; + + user_action = get_user_action (grfKeyState); + + if (user_action != 0) + gdk_drop_set_actions (drop, user_action); + else + gdk_drop_set_actions (drop, actions); + + return actions; +} + +void +_gdk_win32_local_drop_target_dragenter (GdkDragContext *drag, + GdkSurface *dest_surface, + gint x_root, + gint y_root, + DWORD grfKeyState, + guint32 time_, + GdkDragAction *actions) +{ + GdkDrop *drop; + GdkWin32Drop *drop_win32; + GdkDisplay *display; + GdkDragAction source_actions; + GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (dest_surface->impl); + + GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_dragenter %p @ %d : %d" + " for dest window 0x%p" + ". actions = %s\n", + drag, x_root, y_root, + dest_surface, + _gdk_win32_drag_action_to_string (*actions))); + + display = gdk_surface_get_display (dest_surface); + drop = gdk_drop_new (display, + gdk_seat_get_pointer (gdk_display_get_default_seat (display)), + drag, + gdk_content_formats_ref (gdk_drag_context_get_formats (drag)), + dest_surface, + GDK_DRAG_PROTO_LOCAL); + drop_win32 = GDK_WIN32_DROP (drop); + + impl->drop = drop; + + source_actions = set_source_actions_helper (drop, *actions, grfKeyState); + + gdk_drop_emit_enter_event (drop, TRUE, time_); + gdk_drop_emit_motion_event (drop, TRUE, x_root, y_root, time_); + drop_win32->last_key_state = grfKeyState; + drop_win32->last_x = x_root; + drop_win32->last_y = y_root; + *actions = filter_actions (drop_win32->actions, source_actions); + + GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_dragenter returns with actions %s\n", + _gdk_win32_drag_action_to_string (*actions))); +} + +/* The pdwEffect here initially points + * to a DWORD that contains the value of dwOKEffects argument in DoDragDrop, + * i.e. the drag action that the drag source deems acceptable. + * On return it should point to the effect value that denotes the + * action that is going to happen on drop, and that is what DoDragDrop will + * put into the DWORD that pdwEffect was pointing to. + */ static HRESULT STDMETHODCALLTYPE idroptarget_dragenter (LPDROPTARGET This, LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, - LPDWORD pdwEffect) + LPDWORD pdwEffect_and_dwOKEffects) { - target_drag_context *ctx = (target_drag_context *) This; - GdkDragContext *context; - GdkWin32DropContext *context_win32; + drop_target_context *ctx = (drop_target_context *) This; + GdkDrop *drop; + GdkWin32Drop *drop_win32; GdkDisplay *display; gint pt_x; gint pt_y; - GdkDragContext *source_context; + GdkDragContext *drag; + GdkDragAction source_actions; + GdkDragAction dest_actions; - 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)); + GDK_NOTE (DND, g_print ("idroptarget_dragenter %p @ %ld : %ld" + " for dest window 0x%p" + ". dwOKEffects = %lu\n", + This, pt.x, pt.y, + ctx->surface, + *pdwEffect_and_dwOKEffects)); - g_clear_object (&ctx->context); + g_clear_object (&ctx->drop); - source_context = _gdk_win32_find_source_context_for_dest_surface (ctx->dest_surface); + /* Try to find the GdkDragContext object for this DnD operation, + * if it originated in our own application. + */ + drag = _gdk_win32_find_drag_for_dest_surface (ctx->surface); - display = gdk_surface_get_display (ctx->dest_surface); - context = gdk_drop_context_new (display, - /* 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. - */ - source_context ? source_context->source_surface : NULL, - ctx->dest_surface, - query_targets (pDataObj, NULL), - GDK_ACTION_COPY | GDK_ACTION_MOVE, - GDK_DRAG_PROTO_OLE2); - context_win32 = GDK_WIN32_DROP_CONTEXT (context); - gdk_content_formats_unref (query_targets (pDataObj, context_win32->droptarget_w32format_contentformat_map)); - g_array_set_size (context_win32->droptarget_w32format_contentformat_map, 0); - g_set_object (&context_win32->local_source_context, GDK_WIN32_DRAG_CONTEXT (source_context)); + display = gdk_surface_get_display (ctx->surface); + drop = gdk_drop_new (display, + gdk_seat_get_pointer (gdk_display_get_default_seat (display)), + drag, + query_object_formats (pDataObj, NULL), + ctx->surface, + GDK_DRAG_PROTO_OLE2); + drop_win32 = GDK_WIN32_DROP (drop); + g_array_set_size (drop_win32->droptarget_w32format_contentformat_map, 0); + gdk_content_formats_unref (query_object_formats (pDataObj, drop_win32->droptarget_w32format_contentformat_map)); + + ctx->drop = drop; + + source_actions = set_source_actions_helper (drop, + actions_for_drop_effects (*pdwEffect_and_dwOKEffects), + grfKeyState); - ctx->context = context; - context->action = GDK_ACTION_MOVE; - gdk_drag_context_set_actions (context, - GDK_ACTION_COPY | GDK_ACTION_MOVE, - get_suggested_action (context_win32, grfKeyState)); set_data_object (&ctx->data_object, pDataObj); - pt_x = pt.x / context_win32->scale + _gdk_offset_x; - pt_y = pt.y / context_win32->scale + _gdk_offset_y; - gdk_drop_emit_enter_event (GDK_DROP (context), TRUE, GDK_CURRENT_TIME); - gdk_drop_emit_motion_event (GDK_DROP (context), TRUE, pt_x, pt_y, GDK_CURRENT_TIME); - context_win32->last_key_state = grfKeyState; - context_win32->last_x = pt_x; - context_win32->last_y = pt_y; - *pdwEffect = drop_effect_for_action (context->action); + pt_x = pt.x / drop_win32->scale + _gdk_offset_x; + pt_y = pt.y / drop_win32->scale + _gdk_offset_y; + gdk_drop_emit_enter_event (drop, TRUE, GDK_CURRENT_TIME); + gdk_drop_emit_motion_event (drop, TRUE, pt_x, pt_y, GDK_CURRENT_TIME); + drop_win32->last_key_state = grfKeyState; + drop_win32->last_x = pt_x; + drop_win32->last_y = pt_y; + dest_actions = filter_actions (drop_win32->actions, source_actions); + *pdwEffect_and_dwOKEffects = drop_effect_for_actions (dest_actions); - GDK_NOTE (DND, g_print ("idroptarget_dragenter returns with action %d and drop effect %lu\n", context->action, *pdwEffect)); + GDK_NOTE (DND, g_print ("idroptarget_dragenter returns S_OK with actions %s" + " and drop effect %lu\n", + _gdk_win32_drag_action_to_string (dest_actions), + *pdwEffect_and_dwOKEffects)); return S_OK; } +gboolean +_gdk_win32_local_drop_target_will_emit_motion (GdkDrop *drop, + gint x_root, + gint y_root, + DWORD grfKeyState) +{ + GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (drop); + + if (x_root != drop_win32->last_x || + y_root != drop_win32->last_y || + grfKeyState != drop_win32->last_key_state) + return TRUE; + + return FALSE; +} + +void +_gdk_win32_local_drop_target_dragover (GdkDrop *drop, + GdkDragContext *drag, + gint x_root, + gint y_root, + DWORD grfKeyState, + guint32 time_, + GdkDragAction *actions) +{ + GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (drop); + GdkDragAction source_actions; + + source_actions = set_source_actions_helper (drop, *actions, grfKeyState); + + GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_dragover %p @ %d : %d" + ", actions = %s\n", + drop, x_root, y_root, + _gdk_win32_drag_action_to_string (*actions))); + + if (_gdk_win32_local_drop_target_will_emit_motion (drop, x_root, y_root, grfKeyState)) + { + gdk_drop_emit_motion_event (drop, TRUE, x_root, y_root, time_); + drop_win32->last_key_state = grfKeyState; + drop_win32->last_x = x_root; + drop_win32->last_y = y_root; + } + + *actions = filter_actions (drop_win32->actions, source_actions); + + GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_dragover returns with actions %s\n", + _gdk_win32_drag_action_to_string (*actions))); +} + /* NOTE: This method is called continuously, even if nothing is * happening, as long as the drag operation is in progress and * the cursor is above our window. @@ -450,87 +632,151 @@ static HRESULT STDMETHODCALLTYPE idroptarget_dragover (LPDROPTARGET This, DWORD grfKeyState, POINTL pt, - LPDWORD pdwEffect) + LPDWORD pdwEffect_and_dwOKEffects) { - target_drag_context *ctx = (target_drag_context *) This; - GdkWin32DropContext *context_win32 = GDK_WIN32_DROP_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; + drop_target_context *ctx = (drop_target_context *) This; + GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (ctx->drop); + gint pt_x = pt.x / drop_win32->scale + _gdk_offset_x; + gint pt_y = pt.y / drop_win32->scale + _gdk_offset_y; + GdkDragAction source_actions; + GdkDragAction dest_actions; - gdk_drag_context_set_actions (ctx->context, - gdk_drag_context_get_actions (ctx->context), - get_suggested_action (context_win32, grfKeyState)); + source_actions = set_source_actions_helper (ctx->drop, + actions_for_drop_effects (*pdwEffect_and_dwOKEffects), + grfKeyState); - GDK_NOTE (DND, g_print ("idroptarget_dragover %p @ %d : %d (raw %ld : %ld), suggests %d action S_OK\n", This, pt_x, pt_y, pt.x, pt.y, gdk_drag_context_get_suggested_action (ctx->context))); + GDK_NOTE (DND, g_print ("idroptarget_dragover %p @ %d : %d" + " (raw %ld : %ld)" + ", dwOKEffects = %lu" + ", suggests %d action\n", + This, pt_x, pt_y, + pt.x, pt.y, + *pdwEffect_and_dwOKEffects, + source_actions)); - if (pt_x != context_win32->last_x || - pt_y != context_win32->last_y || - grfKeyState != context_win32->last_key_state) + if (pt_x != drop_win32->last_x || + pt_y != drop_win32->last_y || + grfKeyState != drop_win32->last_key_state) { - gdk_drop_emit_motion_event (GDK_DROP (ctx->context), TRUE, pt_x, pt_y, GDK_CURRENT_TIME); - context_win32->last_key_state = grfKeyState; - context_win32->last_x = pt_x; - context_win32->last_y = pt_y; + gdk_drop_emit_motion_event (ctx->drop, TRUE, pt_x, pt_y, GDK_CURRENT_TIME); + drop_win32->last_key_state = grfKeyState; + drop_win32->last_x = pt_x; + drop_win32->last_y = pt_y; } - *pdwEffect = drop_effect_for_action (ctx->context->action); + dest_actions = filter_actions (drop_win32->actions, source_actions); + *pdwEffect_and_dwOKEffects = drop_effect_for_actions (dest_actions); - GDK_NOTE (DND, g_print ("idroptarget_dragover returns with action %d and effect %lu\n", ctx->context->action, *pdwEffect)); + GDK_NOTE (DND, g_print ("idroptarget_dragover returns S_OK with actions %s" + " and effect %lu\n", + _gdk_win32_drag_action_to_string (dest_actions), + *pdwEffect_and_dwOKEffects)); return S_OK; } +void +_gdk_win32_local_drop_target_dragleave (GdkDrop *drop, + guint32 time_) +{ + GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (gdk_drop_get_surface (drop)->impl); + GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_dragleave %p\n", drop)); + + gdk_drop_emit_leave_event (drop, TRUE, time_); + + g_clear_object (&impl->drop); +} + static HRESULT STDMETHODCALLTYPE idroptarget_dragleave (LPDROPTARGET This) { - target_drag_context *ctx = (target_drag_context *) This; + drop_target_context *ctx = (drop_target_context *) This; GDK_NOTE (DND, g_print ("idroptarget_dragleave %p S_OK\n", This)); - gdk_drop_emit_leave_event (GDK_DROP (ctx->context), TRUE, GDK_CURRENT_TIME); + gdk_drop_emit_leave_event (GDK_DROP (ctx->drop), TRUE, GDK_CURRENT_TIME); - g_clear_object (&ctx->context); + g_clear_object (&ctx->drop); set_data_object (&ctx->data_object, NULL); return S_OK; } +void +_gdk_win32_local_drop_target_drop (GdkDrop *drop, + GdkDragContext *drag, + guint32 time_, + GdkDragAction *actions) +{ + GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (drop); + + GDK_NOTE (DND, g_print ("_gdk_win32_local_drop_target_drop %p ", drop)); + + set_source_actions_helper (drop, + *actions, + drop_win32->last_key_state); + + drop_win32->drop_finished = FALSE; + gdk_drop_emit_drop_event (drop, TRUE, drop_win32->last_x, drop_win32->last_y, time_); + + while (!drop_win32->drop_finished) + g_main_context_iteration (NULL, FALSE); + + /* Notify local source of the DnD result + * Special case: + * drop_win32->actions is guaranteed to contain 1 action after gdk_drop_finish () + */ + *actions = drop_win32->actions; + + GDK_NOTE (DND, g_print ("drop with action %s\n", _gdk_win32_drag_action_to_string (*actions))); +} + static HRESULT STDMETHODCALLTYPE idroptarget_drop (LPDROPTARGET This, LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, - LPDWORD pdwEffect) + LPDWORD pdwEffect_and_dwOKEffects) { - target_drag_context *ctx = (target_drag_context *) This; - GdkWin32DropContext *context_win32 = GDK_WIN32_DROP_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; + drop_target_context *ctx = (drop_target_context *) This; + GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (ctx->drop); + gint pt_x = pt.x / drop_win32->scale + _gdk_offset_x; + gint pt_y = pt.y / drop_win32->scale + _gdk_offset_y; + GdkDragAction dest_action; 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); + gdk_drop_emit_leave_event (ctx->drop, TRUE, GDK_CURRENT_TIME); + g_clear_object (&ctx->drop); set_data_object (&ctx->data_object, NULL); return E_POINTER; } - gdk_drag_context_set_actions (ctx->context, - gdk_drag_context_get_actions (ctx->context), - get_suggested_action (context_win32, grfKeyState)); + set_source_actions_helper (ctx->drop, + actions_for_drop_effects (*pdwEffect_and_dwOKEffects), + grfKeyState); - gdk_drop_emit_drop_event (GDK_DROP (ctx->context), TRUE, pt_x, pt_y, GDK_CURRENT_TIME); + drop_win32->drop_finished = FALSE; + gdk_drop_emit_drop_event (ctx->drop, TRUE, pt_x, pt_y, GDK_CURRENT_TIME); - /* Notify OLE of copy or move */ - *pdwEffect = drop_effect_for_action (ctx->context->action); + while (!drop_win32->drop_finished) + g_main_context_iteration (NULL, FALSE); - g_clear_object (&ctx->context); + /* Notify OLE of the DnD result + * Special case: + * drop_win32->actions is guaranteed to contain 1 action after gdk_drop_finish () + */ + dest_action = drop_win32->actions; + *pdwEffect_and_dwOKEffects = drop_effect_for_actions (dest_action); + + g_clear_object (&ctx->drop); set_data_object (&ctx->data_object, NULL); - GDK_NOTE (DND, g_print ("drop S_OK with effect %lx\n", *pdwEffect)); + GDK_NOTE (DND, g_print ("drop S_OK with effect %lx\n", *pdwEffect_and_dwOKEffects)); return S_OK; } @@ -545,20 +791,20 @@ static IDropTargetVtbl idt_vtbl = { idroptarget_drop }; -static target_drag_context * +static drop_target_context * target_context_new (GdkSurface *window) { - target_drag_context *result; + drop_target_context *result; - result = g_new0 (target_drag_context, 1); + result = g_new0 (drop_target_context, 1); result->idt.lpVtbl = &idt_vtbl; result->ref_count = 0; - result->dest_surface = g_object_ref (window); + result->surface = window; idroptarget_addref (&result->idt); - GDK_NOTE (DND, g_print ("target_context_new: %p (window %p)\n", result, result->dest_surface)); + GDK_NOTE (DND, g_print ("target_context_new: %p (window %p)\n", result, result->surface)); return result; } @@ -685,8 +931,8 @@ gdk_dropfiles_filter (GdkWin32Display *display, gpointer data) { GdkSurface *window; - GdkDragContext *context; - GdkWin32DropContext *context_win32; + GdkDrop *drop; + GdkWin32Drop *drop_win32; GString *result; HANDLE hdrop; POINT pt; @@ -696,190 +942,167 @@ gdk_dropfiles_filter (GdkWin32Display *display, if (msg->message != WM_DROPFILES) return GDK_WIN32_MESSAGE_FILTER_CONTINUE; - GDK_NOTE (DND, g_print ("WM_DROPFILES: %p\n", msg->hwnd)); + GDK_NOTE (DND, g_print ("WM_DROPFILES: %p\n", msg->hwnd)); - window = gdk_win32_handle_table_lookup (msg->hwnd); + window = gdk_win32_handle_table_lookup (msg->hwnd); - context = gdk_drop_context_new (GDK_DISPLAY (display), - NULL, - window, - gdk_content_formats_new ((const char *[2]) { - "text/uri-list", - NULL - }, 1), - GDK_ACTION_COPY, - GDK_DRAG_PROTO_WIN32_DROPFILES); - context_win32 = GDK_WIN32_DROP_CONTEXT (context); - /* WM_DROPFILES drops are always file names */ + drop = gdk_drop_new (GDK_DISPLAY (display), + gdk_seat_get_pointer (gdk_display_get_default_seat (GDK_DISPLAY (display))), + NULL, + /* WM_DROPFILES drops are always file names */ + gdk_content_formats_new ((const char *[2]) { + "text/uri-list", + NULL + }, 1), + window, + GDK_DRAG_PROTO_WIN32_DROPFILES); + drop_win32 = GDK_WIN32_DROP (drop); - gdk_drag_context_set_actions (context, GDK_ACTION_COPY, GDK_ACTION_COPY); - current_dest_drag = context; + gdk_drop_set_actions (drop, GDK_ACTION_COPY); - hdrop = (HANDLE) msg->wParam; - DragQueryPoint (hdrop, &pt); - ClientToScreen (msg->hwnd, &pt); + hdrop = (HANDLE) msg->wParam; + DragQueryPoint (hdrop, &pt); + ClientToScreen (msg->hwnd, &pt); - nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0); + nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0); - result = g_string_new (NULL); - for (i = 0; i < nfiles; i++) + 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)) { - 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) { - 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; + 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 { - 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)); - } + 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"); - } + g_free (fileName); + g_string_append (result, "\015\012"); + } - /* FIXME: this call is currently a no-op, but it should - * stash the string somewhere, and later produce it, - * maybe in response to gdk_win32_drop_context_read_async()? - */ - _gdk_dropfiles_store (result->str); - g_string_free (result, FALSE); + g_clear_pointer (&drop_win32->dropfiles_list, g_free); + drop_win32->dropfiles_list = result->str; + g_string_free (result, FALSE); + if (drop_win32->dropfiles_list == NULL) + drop_win32->dropfiles_list = g_strdup (""); - gdk_drop_emit_drop_event (GDK_DROP (context), - FALSE, - pt.x / context_win32->scale + _gdk_offset_x, - pt.y / context_win32->scale + _gdk_offset_y, - _gdk_win32_get_next_tick (msg->time)); + gdk_drop_emit_drop_event (drop, + FALSE, + pt.x / drop_win32->scale + _gdk_offset_x, + pt.y / drop_win32->scale + _gdk_offset_y, + _gdk_win32_get_next_tick (msg->time)); - DragFinish (hdrop); + DragFinish (hdrop); *ret_valp = 0; return GDK_WIN32_MESSAGE_FILTER_REMOVE; } -/* Destination side */ - static void -gdk_win32_drop_context_status (GdkDrop *drop, - GdkDragAction action) +gdk_win32_drop_status (GdkDrop *drop, + GdkDragAction actions) { - GdkDragContext *context = GDK_DRAG_CONTEXT (drop); - GdkDragContext *src_context; + GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (drop); + GdkDragContext *drag; - g_return_if_fail (context != NULL); + g_return_if_fail (drop != 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 (gdk_drag_context_get_actions (context)), - _gdk_win32_drag_action_to_string (gdk_drag_context_get_suggested_action (context)), - _gdk_win32_drag_action_to_string (context->action))); + GDK_NOTE (DND, g_print ("gdk_win32_drop_status: %s\n" + " context=%p:{source_actions=%s}\n", + _gdk_win32_drag_action_to_string (actions), + drop, + _gdk_win32_drag_action_to_string (gdk_drop_get_actions (drop)))); - context->action = action; + drop_win32->actions = actions; - if (!use_ole2_dnd) - { - src_context = _gdk_win32_drag_context_find (context->source_surface, - context->dest_surface); + if (drop_win32->protocol == GDK_DRAG_PROTO_OLE2) + return; - if (src_context) - { - _gdk_win32_drag_context_send_local_status_event (src_context, action); - } - } + drag = gdk_drop_get_drag (drop); + + if (drag != NULL) + _gdk_win32_local_drag_give_feedback (drag, actions); } static void -gdk_win32_drop_context_finish (GdkDrop *drop, - GdkDragAction action) +gdk_win32_drop_finish (GdkDrop *drop, + GdkDragAction action) { - GdkDragContext *context = GDK_DRAG_CONTEXT (drop); - GdkDragContext *src_context; - GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get (); + GdkDragContext *drag; + GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (drop); - g_return_if_fail (context != NULL); + g_return_if_fail (drop != NULL); - GDK_NOTE (DND, g_print ("gdk_drag_finish\n")); + GDK_NOTE (DND, g_print ("gdk_win32_drop_finish with action %s\n", + _gdk_win32_drag_action_to_string (action))); - if (context->action != action) - gdk_win32_drop_context_status (context, action); + drop_win32->actions = action; + drop_win32->drop_finished = TRUE; - if (!use_ole2_dnd) - { - src_context = _gdk_win32_drag_context_find (context->source_surface, - context->dest_surface); - if (src_context) - { - GDK_NOTE (DND, g_print ("gdk_dnd_handle_drop_finihsed: 0x%p\n", - context)); + if (drop_win32->protocol == GDK_DRAG_PROTO_OLE2) + return; +/* FIXME: remove? + drag = gdk_drop_get_drag (drop); - g_signal_emit_by_name (context, "dnd-finished"); - gdk_drag_drop_done (context, !GDK_WIN32_DROP_CONTEXT (context)->drop_failed); - } - } - else - { - _gdk_win32_drag_do_leave (context, GDK_CURRENT_TIME); - - if (action) - clipdrop->dnd_target_state = GDK_WIN32_DND_DROPPED; - else - clipdrop->dnd_target_state = GDK_WIN32_DND_FAILED; - } + if (drag != NULL) + _gdk_win32_local_drag_context_drop_response (drag, action); +*/ } #if 0 @@ -910,7 +1133,7 @@ gdk_destroy_filter (GdkXEvent *xev, void _gdk_win32_surface_register_dnd (GdkSurface *window) { - target_drag_context *ctx; + drop_target_context *ctx; HRESULT hr; g_return_if_fail (window != NULL); @@ -920,7 +1143,7 @@ _gdk_win32_surface_register_dnd (GdkSurface *window) 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))); + GDK_NOTE (DND, g_print ("gdk_win32_surface_register_dnd: %p\n", GDK_SURFACE_HWND (window))); if (!use_ole2_dnd) { @@ -934,8 +1157,10 @@ _gdk_win32_surface_register_dnd (GdkSurface *window) } else { + GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl); + /* Return if window is already setup for DND. */ - if (g_hash_table_lookup (target_ctx_for_window, GDK_SURFACE_HWND (window)) != NULL) + if (impl->drop_target != NULL) return; ctx = target_context_new (window); @@ -955,13 +1180,21 @@ _gdk_win32_surface_register_dnd (GdkSurface *window) OTHER_API_FAILED ("RegisterDragDrop"); else { - g_object_ref (window); - g_hash_table_insert (target_ctx_for_window, GDK_SURFACE_HWND (window), ctx); + impl->drop_target = ctx; } } } } +void +_gdk_win32_surface_unregister_dnd (GdkSurface *window) +{ + GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl); + + if (impl->drop_target) + idroptarget_release (&impl->drop_target->idt); +} + static gpointer grab_data_from_hdata (GTask *task, HANDLE hdata, @@ -1009,16 +1242,16 @@ grab_data_from_hdata (GTask *task, } static void -gdk_win32_drop_context_read_async (GdkDrop *drop, - GdkContentFormats *formats, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +gdk_win32_drop_read_async (GdkDrop *drop, + GdkContentFormats *formats, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - GdkWin32DropContext *context_win32 = GDK_WIN32_DROP_CONTEXT (drop); + GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (drop); GTask *task; - target_drag_context *tctx; + drop_target_context *tctx; const char * const *mime_types; gsize i, j, n_mime_types; GdkWin32ContentFormatPair *pair; @@ -1031,14 +1264,38 @@ gdk_win32_drop_context_read_async (GdkDrop *drop, task = g_task_new (drop, cancellable, callback, user_data); g_task_set_priority (task, io_priority); - g_task_set_source_tag (task, gdk_win32_drop_context_read_async); + g_task_set_source_tag (task, gdk_win32_drop_read_async); - tctx = find_droptarget_for_target_context (GDK_DRAG_CONTEXT (drop)); + mime_types = gdk_content_formats_get_mime_types (formats, &n_mime_types); + + if (drop_win32->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES) + { + for (i = 0; i < n_mime_types; i++) + if (g_strcmp0 (mime_types[i], "text/uri-list") == 0) + break; + if (i >= n_mime_types) + { + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + _("No compatible transfer format found")); + g_clear_pointer (&drop_win32->dropfiles_list, g_free); + + return; + } + + stream = g_memory_input_stream_new_from_data (drop_win32->dropfiles_list, strlen (drop_win32->dropfiles_list), g_free); + drop_win32->dropfiles_list = NULL; + g_object_set_data (G_OBJECT (stream), "gdk-dnd-stream-contenttype", (gpointer) "text/uri-list"); + g_task_return_pointer (task, stream, g_object_unref); + + return; + } + + tctx = GDK_SURFACE_IMPL_WIN32 (gdk_drop_get_surface (drop)->impl)->drop_target; if (tctx == NULL) { g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, - _("Failed to find target context record for context 0x%p"), drop); + _("GDK surface 0x%p is not registered as a drop target"), gdk_drop_get_surface (drop)); return; } @@ -1049,13 +1306,11 @@ gdk_win32_drop_context_read_async (GdkDrop *drop, return; } - mime_types = gdk_content_formats_get_mime_types (formats, &n_mime_types); - for (pair = NULL, i = 0; i < n_mime_types; i++) { - for (j = 0; j < context_win32->droptarget_w32format_contentformat_map->len; j++) + for (j = 0; j < drop_win32->droptarget_w32format_contentformat_map->len; j++) { - pair = &g_array_index (context_win32->droptarget_w32format_contentformat_map, GdkWin32ContentFormatPair, j); + pair = &g_array_index (drop_win32->droptarget_w32format_contentformat_map, GdkWin32ContentFormatPair, j); if (pair->contentformat == mime_types[i]) break; @@ -1127,17 +1382,17 @@ gdk_win32_drop_context_read_async (GdkDrop *drop, } static GInputStream * -gdk_win32_drop_context_read_finish (GdkDrop *drop, - const char **out_mime_type, - GAsyncResult *result, - GError **error) +gdk_win32_drop_read_finish (GdkDrop *drop, + const char **out_mime_type, + GAsyncResult *result, + GError **error) { GTask *task; GInputStream *stream; g_return_val_if_fail (g_task_is_valid (result, G_OBJECT (drop)), NULL); task = G_TASK (result); - g_return_val_if_fail (g_task_get_source_tag (task) == gdk_win32_drop_context_read_async, NULL); + g_return_val_if_fail (g_task_get_source_tag (task) == gdk_win32_drop_read_async, NULL); stream = g_task_propagate_pointer (task, error); @@ -1148,57 +1403,22 @@ gdk_win32_drop_context_read_finish (GdkDrop *drop, } static void -gdk_win32_drop_context_class_init (GdkWin32DropContextClass *klass) +gdk_win32_drop_class_init (GdkWin32DropClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GdkDropClass *drop_class = GDK_DROP_CLASS (klass); - GdkDragContextClass *context_class = GDK_DRAG_CONTEXT_CLASS (klass); - object_class->finalize = gdk_win32_drop_context_finalize; + object_class->finalize = gdk_win32_drop_finalize; - drop_class->status = gdk_win32_drop_context_status; - drop_class->finish = gdk_win32_drop_context_finish; - drop_class->read_async = gdk_win32_drop_context_read_async; - drop_class->read_finish = gdk_win32_drop_context_read_finish; -} - -void -_gdk_win32_local_send_enter (GdkDragContext *context, - guint32 time) -{ - 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_drop_context_new (gdk_surface_get_display (context->source_surface), - context->source_surface, - context->dest_surface, - gdk_content_formats_ref (gdk_drag_context_get_formats (context)), - gdk_drag_context_get_actions (context), - GDK_DRAG_PROTO_LOCAL); - - gdk_surface_set_events (new_context->source_surface, - gdk_surface_get_events (new_context->source_surface) | - GDK_PROPERTY_CHANGE_MASK); - - current_dest_drag = new_context; - - gdk_drop_emit_enter_event (GDK_DROP (new_context), FALSE, GDK_CURRENT_TIME); + drop_class->status = gdk_win32_drop_status; + drop_class->finish = gdk_win32_drop_finish; + drop_class->read_async = gdk_win32_drop_read_async; + drop_class->read_finish = gdk_win32_drop_read_finish; } void _gdk_drop_init (void) { - if (use_ole2_dnd) - { - target_ctx_for_window = g_hash_table_new (g_direct_hash, g_direct_equal); - } + if (g_strcmp0 (getenv ("GDK_WIN32_OLE2_DND"), "0") == 0) + use_ole2_dnd = FALSE; } diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h index b494816a00..1d1970872b 100644 --- a/gdk/win32/gdkprivate-win32.h +++ b/gdk/win32/gdkprivate-win32.h @@ -202,8 +202,6 @@ void _gdk_win32_adjust_client_rect (GdkSurface *window, void _gdk_selection_property_delete (GdkSurface *); -void _gdk_dropfiles_store (gchar *data); - void _gdk_push_modal_window (GdkSurface *window); void _gdk_remove_modal_window (GdkSurface *window); GdkSurface *_gdk_modal_current (void); @@ -424,6 +422,8 @@ void _gdk_win32_display_create_surface_impl (GdkDisplay *display, /* stray GdkSurfaceImplWin32 members */ void _gdk_win32_surface_register_dnd (GdkSurface *window); +void _gdk_win32_surface_unregister_dnd (GdkSurface *window); + GdkDragContext *_gdk_win32_surface_drag_begin (GdkSurface *window, GdkDevice *device, GdkContentProvider *content, diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c index 932ca4a663..ddd117eb67 100644 --- a/gdk/win32/gdksurface-win32.c +++ b/gdk/win32/gdksurface-win32.c @@ -250,6 +250,9 @@ gdk_surface_impl_win32_finalize (GObject *object) surface_impl->cache_surface = NULL; } + _gdk_win32_surface_unregister_dnd (wrapper); + g_clear_object (&surface_impl->drop); + g_assert (surface_impl->transient_owner == NULL); g_assert (surface_impl->transient_children == NULL); diff --git a/gdk/win32/gdksurface-win32.h b/gdk/win32/gdksurface-win32.h index a0e7309eab..2a14578197 100644 --- a/gdk/win32/gdksurface-win32.h +++ b/gdk/win32/gdksurface-win32.h @@ -216,6 +216,9 @@ struct _GdkW32DragMoveResizeContext typedef struct _GdkW32DragMoveResizeContext GdkW32DragMoveResizeContext; +/* defined in gdkdrop-win32.c */ +typedef struct _drop_target_context drop_target_context; + struct _GdkSurfaceImplWin32 { GdkSurfaceImpl parent_instance; @@ -243,6 +246,15 @@ struct _GdkSurfaceImplWin32 GdkEventMask native_event_mask; + /* Non-NULL for any window that is registered as a drop target. + * For OLE2 protocol only. + */ + drop_target_context *drop_target; + /* Temporarily holds the GdkDrop currently associated with this window. + * For LOCAL protocol only. + */ + GdkDrop *drop; + GdkSurfaceTypeHint type_hint; GdkSurface *transient_owner; diff --git a/gdk/win32/gdkwin32dnd-private.h b/gdk/win32/gdkwin32dnd-private.h index 1492313322..443cc78448 100644 --- a/gdk/win32/gdkwin32dnd-private.h +++ b/gdk/win32/gdkwin32dnd-private.h @@ -38,13 +38,12 @@ struct _GdkWin32DragContextUtilityData struct _GdkWin32DragContext { - GdkDragContext context; + GdkDragContext drag; GdkDragProtocol protocol; GdkSurface *ipc_window; GdkSurface *drag_surface; GdkCursor *cursor; GdkSeat *grab_seat; - GdkDragAction actions; GdkDragAction current_action; GdkWin32DragContextUtilityData util_data; @@ -57,6 +56,7 @@ struct _GdkWin32DragContext guint drag_status : 4; /* Current status of drag */ guint drop_failed : 1; /* Whether the drop was unsuccessful */ + guint handle_events : 1; /* Whether handle_event() should do anything */ }; struct _GdkWin32DragContextClass @@ -64,51 +64,54 @@ struct _GdkWin32DragContextClass GdkDragContextClass parent_class; }; -struct _GdkWin32DropContext -{ - GdkDragContext context; - GdkDragProtocol protocol; - GdkDragAction actions; - GdkDragAction current_action; - guint scale; /* Temporarily caches the HiDPI scale */ - gint last_x; /* Coordinates from last event, in GDK space */ - gint last_y; - DWORD last_key_state; /* Key state from last event */ +gpointer _gdk_win32_dnd_thread_main (gpointer data); - /* Just like context->formats, but an array, and with format IDs - * stored inside. - */ - GArray *droptarget_w32format_contentformat_map; +GdkDragContext *_gdk_win32_find_drag_for_dest_surface (GdkSurface *dest_surface); - GdkWin32DragContext *local_source_context; +void _gdk_win32_drag_send_local_status_event (GdkDragContext *drag, + GdkDragAction action); +void _gdk_win32_local_send_enter (GdkDragContext *drag, + GdkSurface *dest_surface, + guint32 time); - guint drag_status : 4; /* Current status of drag */ - guint drop_failed : 1; /* Whether the drop was unsuccessful */ -}; +GdkDragContext *_gdk_win32_drag_context_find (GdkSurface *source, + GdkSurface *dest); +GdkDrop *_gdk_win32_get_drop_for_dest_surface (GdkSurface *dest); -struct _GdkWin32DropContextClass -{ - GdkDragContextClass parent_class; -}; +void _gdk_win32_drag_do_leave (GdkDragContext *context, + guint32 time); -gpointer _gdk_win32_dnd_thread_main (gpointer data); +gboolean _gdk_win32_local_drop_target_will_emit_motion (GdkDrop *drop, + gint x_root, + gint y_root, + DWORD grfKeyState); -GdkDragContext *_gdk_win32_find_source_context_for_dest_surface (GdkSurface *dest_surface); +void _gdk_win32_local_drop_target_dragenter (GdkDragContext *drag, + GdkSurface *dest_surface, + gint x_root, + gint y_root, + DWORD grfKeyState, + guint32 time_, + GdkDragAction *actions); +void _gdk_win32_local_drop_target_dragover (GdkDrop *drop, + GdkDragContext *drag, + gint x_root, + gint y_root, + DWORD grfKeyState, + guint32 time_, + GdkDragAction *actions); +void _gdk_win32_local_drop_target_dragleave (GdkDrop *drop, + guint32 time_); +void _gdk_win32_local_drop_target_drop (GdkDrop *drop, + GdkDragContext *drag, + guint32 time_, + GdkDragAction *actions); -void _gdk_win32_drag_context_send_local_status_event (GdkDragContext *src_context, - GdkDragAction action); -void _gdk_win32_local_send_enter (GdkDragContext *context, - guint32 time); - -GdkDragContext *_gdk_win32_drag_context_find (GdkSurface *source, - GdkSurface *dest); -GdkDragContext *_gdk_win32_drop_context_find (GdkSurface *source, - GdkSurface *dest); - - -void _gdk_win32_drag_do_leave (GdkDragContext *context, - guint32 time); +void _gdk_win32_local_drag_give_feedback (GdkDragContext *drag, + GdkDragAction actions); +void _gdk_win32_local_drag_context_drop_response (GdkDragContext *drag, + GdkDragAction action); G_END_DECLS diff --git a/gdk/win32/gdkwin32dnd.h b/gdk/win32/gdkwin32dnd.h index a59aefa9b3..31a0ee85e4 100644 --- a/gdk/win32/gdkwin32dnd.h +++ b/gdk/win32/gdkwin32dnd.h @@ -43,23 +43,6 @@ typedef struct _GdkWin32DragContextClass GdkWin32DragContextClass; GDK_AVAILABLE_IN_ALL GType gdk_win32_drag_context_get_type (void); -#define GDK_TYPE_WIN32_DROP_CONTEXT (gdk_win32_drop_context_get_type ()) -#define GDK_WIN32_DROP_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WIN32_DROP_CONTEXT, GdkWin32DropContext)) -#define GDK_WIN32_DROP_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WIN32_DROP_CONTEXT, GdkWin32DropContextClass)) -#define GDK_IS_WIN32_DROP_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WIN32_DROP_CONTEXT)) -#define GDK_IS_WIN32_DROP_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WIN32_DROP_CONTEXT)) -#define GDK_WIN32_DROP_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WIN32_DROP_CONTEXT, GdkWin32DropContextClass)) - -#ifdef GDK_COMPILATION -typedef struct _GdkWin32DropContext GdkWin32DropContext; -#else -typedef GdkDragContext GdkWin32DropContext; -#endif -typedef struct _GdkWin32DropContextClass GdkWin32DropContextClass; - -GDK_AVAILABLE_IN_ALL -GType gdk_win32_drop_context_get_type (void); - G_END_DECLS #endif /* __GDK_WIN32_DRAG_CONTEXT_H__ */