/* We get this from the OS via IDropSourceNotify and pass it to the
* main thread.
+ * Will be INVALID_HANDLE_VALUE (not NULL!) when unset.
*/
HWND dest_window_handle;
} source_drag_context;
_win32_main_thread == g_thread_self ());
drag->handle_events = TRUE;
+ drag->dest_window = INVALID_HANDLE_VALUE;
GDK_NOTE (DND, g_print ("gdk_win32_drag_context_init %p\n", drag));
}
gdk_drag_context_set_cursor (drag, NULL);
- g_set_object (&drag_win32->ipc_window, NULL);
+ g_set_object (&drag_win32->grab_surface, NULL);
drag_surface = drag_win32->drag_surface;
G_OBJECT_CLASS (gdk_win32_drag_context_parent_class)->finalize (object);
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
+ * which is currently targetting the dest_window
* Does not give a reference.
*/
GdkDragContext *
-_gdk_win32_find_drag_for_dest_surface (GdkSurface *dest_surface)
+_gdk_win32_find_drag_for_dest_window (HWND dest_window)
{
GHashTableIter iter;
GdkWin32DragContext *drag_win32;
g_hash_table_iter_init (&iter, clipdrop->active_source_drags);
while (g_hash_table_iter_next (&iter, (gpointer *) &drag_win32, (gpointer *) &ddd))
- if (ddd->src_context->dest_window_handle == GDK_SURFACE_HWND (dest_surface))
+ if (ddd->src_context->dest_window_handle == dest_window)
return GDK_DRAG_CONTEXT (drag_win32);
return NULL;
notify_dnd_enter (gpointer user_data)
{
GdkWin32DnDEnterLeaveNotify *notify = (GdkWin32DnDEnterLeaveNotify *) user_data;
- GdkDragContext *drag = GDK_DRAG_CONTEXT (notify->opaque_context);
- GdkSurface *dest_surface, *dw;
+ GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (notify->opaque_context);
- dw = gdk_win32_handle_table_lookup (notify->target_window_handle);
-
- if (dw)
- dest_surface = g_object_ref (dw);
- else
- dest_surface = gdk_win32_surface_foreign_new_for_display (gdk_drag_context_get_display (drag), notify->target_window_handle);
-
- g_clear_object (&drag->dest_surface);
- drag->dest_surface = dest_surface;
+ drag_win32->dest_window = notify->target_window_handle;
g_free (notify);
notify_dnd_leave (gpointer user_data)
{
GdkWin32DnDEnterLeaveNotify *notify = (GdkWin32DnDEnterLeaveNotify *) user_data;
- GdkDragContext *drag = GDK_DRAG_CONTEXT (notify->opaque_context);
- GdkSurface *dest_surface, *dw;
+ GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (notify->opaque_context);
- dw = gdk_win32_handle_table_lookup (notify->target_window_handle);
+ if (notify->target_window_handle != drag_win32->dest_window)
+ g_warning ("DnD leave says that the window handle is 0x%p, but drag has 0x%p", notify->target_window_handle, drag_win32->dest_window);
- if (dw)
- {
- dest_surface = gdk_surface_get_toplevel (dw);
-
- 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 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);
+ drag_win32->dest_window = INVALID_HANDLE_VALUE;
g_free (notify);
notify = g_new0 (GdkWin32DnDEnterLeaveNotify, 1);
notify->target_window_handle = ctx->dest_window_handle;
- ctx->dest_window_handle = NULL;
+ ctx->dest_window_handle = INVALID_HANDLE_VALUE;
notify->opaque_context = ctx->drag;
g_idle_add_full (G_PRIORITY_DEFAULT, notify_dnd_leave, notify, NULL);
static source_drag_context *
source_context_new (GdkDragContext *drag,
- GdkSurface *window,
GdkContentFormats *formats)
{
GdkWin32DragContext *drag_win32;
result->source_window_handle = GDK_SURFACE_HWND (drag->source_surface);
result->scale = drag_win32->scale;
result->util_data.state = GDK_WIN32_DND_PENDING; /* Implicit */
+ result->dest_window_handle = INVALID_HANDLE_VALUE;
GDK_NOTE (DND, g_print ("source_context_new: %p (drag %p)\n", result, result->drag));
static GdkSurface *
create_drag_surface (GdkDisplay *display)
{
- GdkSurface *window;
+ GdkSurface *surface;
- window = gdk_surface_new_popup (display, &(GdkRectangle) { 0, 0, 100, 100 });
+ surface = gdk_surface_new_popup (display, &(GdkRectangle) { 0, 0, 100, 100 });
- gdk_surface_set_type_hint (window, GDK_SURFACE_TYPE_HINT_DND);
+ gdk_surface_set_type_hint (surface, GDK_SURFACE_TYPE_HINT_DND);
- return window;
+ return surface;
}
GdkDragContext *
-_gdk_win32_surface_drag_begin (GdkSurface *window,
+_gdk_win32_surface_drag_begin (GdkSurface *surface,
GdkDevice *device,
GdkContentProvider *content,
GdkDragAction actions,
GdkWin32Clipdrop *clipdrop = _gdk_win32_clipdrop_get ();
int x_root, y_root;
- g_return_val_if_fail (window != NULL, NULL);
+ g_return_val_if_fail (surface != NULL, NULL);
- drag = gdk_drag_context_new (gdk_surface_get_display (window),
+ drag = gdk_drag_context_new (gdk_surface_get_display (surface),
content,
actions,
device,
use_ole2_dnd ? GDK_DRAG_PROTO_OLE2 : GDK_DRAG_PROTO_LOCAL);
drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag);
- g_set_object (&drag->source_surface, window);
+ g_set_object (&drag->source_surface, surface);
GDK_NOTE (DND, g_print ("_gdk_win32_surface_drag_begin\n"));
drag_win32->util_data.last_x = drag_win32->start_x;
drag_win32->util_data.last_y = drag_win32->start_y;
- g_set_object (&drag_win32->ipc_window, window);
+ g_set_object (&drag_win32->grab_surface, surface);
- drag_win32->drag_surface = create_drag_surface (gdk_surface_get_display (window));
+ drag_win32->drag_surface = create_drag_surface (gdk_surface_get_display (surface));
if (!drag_context_grab (drag))
{
data_object *data_obj;
source_ctx = source_context_new (drag,
- window,
gdk_drag_context_get_formats (drag));
data_obj = data_object_new (drag);
return TRUE;
}
-/* Finds the GdkSurface under cursor. Local DnD protcol
+/* Finds the HWND 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 *drag,
- GdkSurface *drag_surface,
- gint x_root,
- gint y_root)
+static HWND
+gdk_win32_drag_context_find_window (GdkDragContext *drag,
+ GdkSurface *drag_surface,
+ gint x_root,
+ gint y_root)
{
GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag);
- GdkSurface *dest_surface, *dw;
find_window_enum_arg a;
+ HWND result;
g_assert (_win32_main_thread == NULL ||
_win32_main_thread == g_thread_self ());
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;
+ a.result = INVALID_HANDLE_VALUE;
GDK_NOTE (DND,
- g_print ("gdk_win32_drag_context_find_surface: %p %+d%+d\n",
+ g_print ("gdk_win32_drag_context_find_window: %p %+d%+d\n",
(drag_surface ? GDK_SURFACE_HWND (drag_surface) : NULL),
a.x, a.y));
EnumWindows (find_window_enum_proc, (LPARAM) &a);
- *protocol = GDK_DRAG_PROTO_NONE;
-
- if (a.result == NULL)
- dest_surface = NULL;
- else
- {
- dw = gdk_win32_handle_table_lookup (a.result);
- if (dw)
- {
- dest_surface = gdk_surface_get_toplevel (dw);
- g_object_ref (dest_surface);
- }
- else
- dest_surface = gdk_win32_surface_foreign_new_for_display (gdk_drag_context_get_display (drag), a.result);
- }
-
GDK_NOTE (DND,
- g_print ("gdk_win32_drag_context_find_surface: %p %+d%+d: %p: %p\n",
+ g_print ("gdk_win32_drag_context_find_window: %p %+d%+d: %p\n",
(drag_surface ? GDK_SURFACE_HWND (drag_surface) : NULL),
x_root, y_root,
- a.result,
- (dest_surface ? GDK_SURFACE_HWND (dest_surface) : NULL)));
+ a.result));
- return dest_surface;
+ return a.result;
}
static DWORD
return key_state;
}
+/* This only works if dest_window our window and the DnD operation
+ * is currently local to the application.
+ */
+static GdkDrop *
+_gdk_win32_get_drop_for_dest_window (HWND dest_window)
+{
+ GdkSurface *drop_surface = gdk_win32_handle_table_lookup (dest_window);
+ GdkDrop *result = NULL;
+
+ if (drop_surface)
+ result = _gdk_win32_get_drop_for_dest_surface (drop_surface);
+
+ return result;
+}
+
static gboolean
gdk_win32_local_drag_motion (GdkDragContext *drag,
- GdkSurface *dest_surface,
+ HWND dest_window,
gint x_root,
gint y_root,
GdkDragAction possible_actions,
drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag);
- drop = _gdk_win32_get_drop_for_dest_surface (drag->dest_surface);
+ drop = _gdk_win32_get_drop_for_dest_window (drag_win32->dest_window);
actions = gdk_drag_context_get_actions (drag);
" dest=%p (current %p) drop=%p drag=%p:{actions=%s,suggested=%s,action=%s}\n",
x_root, y_root,
_gdk_win32_drag_action_to_string (possible_actions),
- dest_surface, drag->dest_surface, drop, drag,
+ dest_window, drag_win32->dest_window, 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)));
- if (drag->dest_surface != dest_surface)
+ if (drag_win32->dest_window != dest_window)
{
/* Send a leave to the last destination */
if (drop)
_gdk_win32_local_drop_target_dragleave (drop, time_);
- g_set_object (&drag->dest_surface, dest_surface);
-
+ drag_win32->dest_window = dest_window;
drag_win32->drag_status = GDK_DRAG_STATUS_DRAG;
- _gdk_win32_local_drop_target_dragenter (drag, dest_surface, x_root, y_root, key_state, time_, &actions);
+ _gdk_win32_local_drop_target_dragenter (drag,
+ gdk_win32_handle_table_lookup (dest_window),
+ x_root,
+ y_root,
+ key_state,
+ time_,
+ &actions);
- drop = _gdk_win32_get_drop_for_dest_surface (drag->dest_surface);
+ drop = _gdk_win32_get_drop_for_dest_window (drag_win32->dest_window);
maybe_emit_action_changed (drag_win32, actions);
}
if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL)
{
- GdkDrop *drop;
- drop = _gdk_win32_get_drop_for_dest_surface (drag->dest_surface);
+ GdkDrop *drop = _gdk_win32_get_drop_for_dest_window (drag_win32->dest_window);
if (drop)
{
{
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
gdk_device_grab (gdk_seat_get_pointer (drag_win32->grab_seat),
- drag_win32->ipc_window,
+ drag_win32->grab_surface,
GDK_OWNERSHIP_APPLICATION, FALSE,
GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
cursor, GDK_CURRENT_TIME);
GdkSeat *seat;
GdkCursor *cursor;
- GDK_NOTE (DND, g_print ("drag_context_grab: 0x%p with ipc window 0x%p\n",
+ GDK_NOTE (DND, g_print ("drag_context_grab: 0x%p with grab surface 0x%p\n",
drag,
- drag_win32->ipc_window));
+ drag_win32->grab_surface));
- if (!drag_win32->ipc_window)
+ if (!drag_win32->grab_surface)
return FALSE;
seat = gdk_device_get_seat (gdk_drag_context_get_device (drag));
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, drag_win32->ipc_window,
+ if (gdk_seat_grab (seat, drag_win32->grab_surface,
capabilities, FALSE,
drag_win32->cursor, NULL, NULL, NULL) != GDK_GRAB_SUCCESS)
return FALSE;
if (drag_win32->protocol == GDK_DRAG_PROTO_LOCAL)
{
- GdkDrop *drop = _gdk_win32_get_drop_for_dest_surface (drag->dest_surface);
+ GdkDrop *drop = _gdk_win32_get_drop_for_dest_window (drag_win32->dest_window);
if (drop)
_gdk_win32_local_drop_target_dragleave (drop, GDK_CURRENT_TIME);
drop = NULL;
guint32 evtime)
{
GdkWin32DragContext *drag_win32 = GDK_WIN32_DRAG_CONTEXT (drag);
- GdkSurface *dest_surface;
+ HWND dest_window;
g_assert (_win32_main_thread == NULL ||
_win32_main_thread == g_thread_self ());
- dest_surface = gdk_win32_drag_context_find_surface (drag,
- drag_win32->drag_surface,
- x_root, y_root);
+ dest_window = gdk_win32_drag_context_find_window (drag,
+ drag_win32->drag_surface,
+ x_root, y_root);
- gdk_win32_local_drag_motion (drag, dest_surface, x_root, y_root,
+ gdk_win32_local_drag_motion (drag, dest_window, x_root, y_root,
gdk_drag_context_get_actions (drag),
grfKeyState, evtime);
}
case GDK_KEY_KP_Enter:
case GDK_KEY_KP_Space:
if ((gdk_drag_context_get_selected_action (drag) != 0) &&
- (drag->dest_surface != NULL))
+ (drag_win32->dest_window != INVALID_HANDLE_VALUE))
{
g_signal_emit_by_name (drag, "drop-performed",
gdk_event_get_time ((GdkEvent *) event));
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
+ * Also, don't cancel if we re-grab on the widget or on our grab window, for
* example, when changing the drag cursor.
*/
if (event->implicit ||
event->grab_surface == drag_win32->drag_surface ||
- event->grab_surface == drag_win32->ipc_window)
+ event->grab_surface == drag_win32->grab_surface)
return FALSE;
if (gdk_event_get_device ((GdkEvent *) event) !=
typedef struct _GdkWin32DragContextUtilityData GdkWin32DragContextUtilityData;
+/* This structure is deliberately designed to be
+ * copyable with memcpy(), i.e. no pointers inside.
+ */
struct _GdkWin32DragContextUtilityData
{
gint last_x; /* Coordinates from last event, in GDK space */
struct _GdkWin32DragContext
{
- GdkDragContext drag;
- GdkDragProtocol protocol;
- GdkSurface *ipc_window;
- GdkSurface *drag_surface;
- GdkCursor *cursor;
- GdkSeat *grab_seat;
- GdkDragAction current_action;
+ GdkDragContext drag;
+
+ /* The drag protocol being used */
+ GdkDragProtocol protocol;
+
+ /* The surface used for grabs.
+ * Usually the same as GdkDragContext->source_surface
+ */
+ GdkSurface *grab_surface;
+
+ /* The window currently under cursor.
+ * Will be INVALID_HANDLE_VALUE (not NULL!) if it is not known
+ */
+ HWND dest_window;
+
+ /* The surface that we move along with the cursor to indicate
+ * what exactly is being dragged.
+ */
+ GdkSurface *drag_surface;
+ GdkCursor *cursor;
+ GdkSeat *grab_seat;
+
+ /* Used to keep track of current drag action, and
+ * emit an "action-changed" signal whenever it changes.
+ * In the end the actual action is decided on the basis of
+ * the last information we receive from the drop site, this
+ * field is not used for that purpose.
+ */
+ GdkDragAction current_action;
GdkWin32DragContextUtilityData util_data;
- guint scale; /* Temporarily caches the HiDPI scale */
- gint hot_x; /* Hotspot offset from the top-left of the drag-window, scaled (can be added to GDK space coordinates) */
- gint hot_y;
- gint start_x; /* Coordinates of the drag start, in GDK space */
- gint start_y;
+ guint scale; /* Temporarily caches the HiDPI scale */
+ gint hot_x; /* Hotspot offset from the top-left of the drag-window, scaled (can be added to GDK space coordinates) */
+ gint hot_y;
+ gint start_x; /* Coordinates of the drag start, in GDK space */
+ gint start_y;
- 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 */
+ 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
gpointer _gdk_win32_dnd_thread_main (gpointer data);
-GdkDragContext *_gdk_win32_find_drag_for_dest_surface (GdkSurface *dest_surface);
-
-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);
-
-GdkDragContext *_gdk_win32_drag_context_find (GdkSurface *source,
- GdkSurface *dest);
+GdkDragContext *_gdk_win32_find_drag_for_dest_window (HWND dest_window);
GdkDrop *_gdk_win32_get_drop_for_dest_surface (GdkSurface *dest);
-void _gdk_win32_drag_do_leave (GdkDragContext *context,
- guint32 time);
-
-gboolean _gdk_win32_local_drop_target_will_emit_motion (GdkDrop *drop,
- gint x_root,
- gint y_root,
- DWORD grfKeyState);
-
-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_local_drag_give_feedback (GdkDragContext *drag,
- GdkDragAction actions);
-void _gdk_win32_local_drag_context_drop_response (GdkDragContext *drag,
- GdkDragAction action);
+gboolean _gdk_win32_local_drop_target_will_emit_motion (GdkDrop *drop,
+ gint x_root,
+ gint y_root,
+ DWORD grfKeyState);
+
+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_local_drag_give_feedback (GdkDragContext *drag,
+ GdkDragAction actions);
+void _gdk_win32_local_drag_context_drop_response (GdkDragContext *drag,
+ GdkDragAction action);
G_END_DECLS