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__ */