Fix DND coordinates on Windows
authorLuca Bacci <luca.bacci982@gmail.com>
Mon, 6 Sep 2021 16:54:30 +0000 (18:54 +0200)
committerLuca Bacci <luca.bacci982@gmail.com>
Fri, 8 Oct 2021 12:24:29 +0000 (14:24 +0200)
gdk/win32/gdkdrag-win32.c
gdk/win32/gdkdrop-win32.c

index 4482e1b3adef62a7c822960404e31f7cabf4110c..65bd80dadccbbee94a39de74522b4fed6b3ad86d 100644 (file)
@@ -2081,8 +2081,8 @@ gdk_dnd_handle_motion_event (GdkDrag  *drag,
   API_CALL (PostThreadMessage, (clipdrop->dnd_thread_id,
                                 WM_MOUSEMOVE,
                                 key_state,
-                                MAKELPARAM (x * drag_win32->scale,
-                                            y * drag_win32->scale)));
+                                MAKELPARAM (x_root * drag_win32->scale - _gdk_offset_x,
+                                            y_root * drag_win32->scale - _gdk_offset_y)));
 
   return TRUE;
 }
index d6e13a3d871a96132ed849ab41cd75fbb023d7fc..fc8ae391e23c919541b5e038a58c78b0feb3525a 100644 (file)
@@ -426,6 +426,31 @@ set_source_actions_helper (GdkDrop       *drop,
   return actions;
 }
 
+/* Utility function to translate win32 screen coordinates to
+ * client coordinates (i.e. relative to the surface origin)
+ *
+ * Note that input is expected to be:
+ * a) NOT scaled by dpi_scale
+ * b) NOT translated by the GDK screen offset (gdk_offset_x / y)
+ *
+ * This utility function preserves subpixel precision
+ */
+static void
+unscaled_screen_to_client (GdkSurface* surface,
+                           double screen_x,
+                           double screen_y,
+                           double *client_x,
+                           double *client_y)
+{
+  POINT client_origin;
+
+  client_origin.x = 0;
+  client_origin.y = 0;
+  ClientToScreen (GDK_SURFACE_HWND (surface), &client_origin);
+  *client_x = screen_x - client_origin.x;
+  *client_y = screen_y - client_origin.y;
+}
+
 /* 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.
@@ -446,6 +471,8 @@ idroptarget_dragenter (LPDROPTARGET This,
   GdkDisplay *display;
   int pt_x;
   int pt_y;
+  double x = 0.0;
+  double y = 0.0;
   GdkDrag *drag;
   GdkDragAction source_actions;
   GdkDragAction dest_actions;
@@ -490,7 +517,12 @@ idroptarget_dragenter (LPDROPTARGET This,
   set_data_object (&ctx->data_object, pDataObj);
   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, pt_x, pt_y, GDK_CURRENT_TIME);
+
+  unscaled_screen_to_client (ctx->surface, pt.x, pt.y, &x, &y);
+  x /= drop_win32->scale;
+  y /= drop_win32->scale;
+
+  gdk_drop_emit_enter_event (drop, TRUE, x, y, GDK_CURRENT_TIME);
   drop_win32->last_key_state = grfKeyState;
   drop_win32->last_x = pt_x;
   drop_win32->last_y = pt_y;
@@ -545,7 +577,14 @@ idroptarget_dragover (LPDROPTARGET This,
       pt_y != drop_win32->last_y ||
       grfKeyState != drop_win32->last_key_state)
     {
-      gdk_drop_emit_motion_event (ctx->drop, TRUE, pt_x, pt_y, GDK_CURRENT_TIME);
+      double x = 0.0;
+      double y = 0.0;
+
+      unscaled_screen_to_client (ctx->surface, pt.x, pt.y, &x, &y);
+      x /= drop_win32->scale;
+      y /= drop_win32->scale;
+
+      gdk_drop_emit_motion_event (ctx->drop, TRUE, x, y, GDK_CURRENT_TIME);
       drop_win32->last_key_state = grfKeyState;
       drop_win32->last_x = pt_x;
       drop_win32->last_y = pt_y;
@@ -588,6 +627,8 @@ idroptarget_drop (LPDROPTARGET This,
   GdkWin32Drop *drop_win32 = GDK_WIN32_DROP (ctx->drop);
   int pt_x = pt.x / drop_win32->scale + _gdk_offset_x;
   int pt_y = pt.y / drop_win32->scale + _gdk_offset_y;
+  double x = 0.0;
+  double y = 0.0;
   GdkDragAction dest_action;
 
   GDK_NOTE (DND, g_print ("idroptarget_drop %p ", This));
@@ -607,7 +648,12 @@ idroptarget_drop (LPDROPTARGET This,
                              grfKeyState);
 
   drop_win32->drop_finished = FALSE;
-  gdk_drop_emit_drop_event (ctx->drop, TRUE, pt_x, pt_y, GDK_CURRENT_TIME);
+
+  unscaled_screen_to_client (ctx->surface, pt.x, pt.y, &x, &y);
+  x /= drop_win32->scale;
+  y /= drop_win32->scale;
+
+  gdk_drop_emit_drop_event (ctx->drop, TRUE, x, y, GDK_CURRENT_TIME);
 
   while (!drop_win32->drop_finished)
     g_main_context_iteration (NULL, FALSE);