[gtk/gtk-3-24: 1/2] GdkWin32: Make OLE2 DND work in monitors with different OS scales




commit 4d40300d8a996ca1ef57d327a6e24342cf72c516
Author: Luca Bacci <luca bacci982 gmail com>
Date:   Sat Nov 13 19:38:11 2021 +0100

    GdkWin32: Make OLE2 DND work in monitors with different OS scales
    
    Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/3734

 gdk/win32/gdkdnd-win32.c        | 19 +++++++++++++++++++
 gdk/win32/gdkwin32dnd-private.h |  9 +++++++++
 2 files changed, 28 insertions(+)
---
diff --git a/gdk/win32/gdkdnd-win32.c b/gdk/win32/gdkdnd-win32.c
index e4a0257bf5..b968294ba9 100644
--- a/gdk/win32/gdkdnd-win32.c
+++ b/gdk/win32/gdkdnd-win32.c
@@ -774,6 +774,7 @@ send_change_events (GdkDragContext *context,
   GdkWin32DragContext *context_win32 = GDK_WIN32_DRAG_CONTEXT (context);
   POINT pt;
   POINT pt_client;
+  HMONITOR monitor = NULL;
   gboolean changed = FALSE;
   HWND hwnd = GDK_WINDOW_HWND (context->source_window);
   LPARAM lparam;
@@ -784,6 +785,24 @@ send_change_events (GdkDragContext *context,
   if (!API_CALL (GetCursorPos, (&pt)))
     return FALSE;
 
+  /* Move the DND IPC window to the monitor the cursor is currently on.
+     This esures that OLE2 DND works correctly even if the DPI awareness
+     isn't per-monitor.
+  */
+  monitor = MonitorFromPoint (pt, MONITOR_DEFAULTTONEAREST);
+  if (monitor != context_win32->last_monitor)
+    {
+      MONITORINFO mi;
+
+      mi.cbSize = sizeof(mi);
+      if (GetMonitorInfoW (monitor, &mi))
+        {
+          MoveWindow (hwnd, mi.rcWork.left, mi.rcWork.top, 1, 1, FALSE);
+        }
+
+      context_win32->last_monitor = monitor;
+    }
+
   pt_client = pt;
 
   if (!API_CALL (ScreenToClient, (hwnd, &pt_client)))
diff --git a/gdk/win32/gdkwin32dnd-private.h b/gdk/win32/gdkwin32dnd-private.h
index b0476b468e..a7d11a31de 100644
--- a/gdk/win32/gdkwin32dnd-private.h
+++ b/gdk/win32/gdkwin32dnd-private.h
@@ -55,6 +55,15 @@ struct _GdkWin32DragContext
   gint start_x;           /* Coordinates of the drag start, in GDK space */
   gint start_y;
   DWORD last_key_state;     /* Key state from last event */
+  HMONITOR last_monitor;  /* While dragging we keep track of the monitor the cursor
+                             is currently on. As the cursor moves between monitors,
+                             we move the invisible dnd ipc window to the top-left
+                             corner of the current monitor, because OLE2 does not
+                             work correctly if the source window and the dest window
+                             are on monitors with different scales (say one is 125%
+                             and the other 100%) and the drag-initiating application
+                             (effectively driving the DND) is not per-monitor DPI aware
+                           */
 
   /* Just like context->targets, but an array, and with format IDs
    * stored inside.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]