From 638533dc09f7fe497eee7e7826c1c9a24ddcf4bb Mon Sep 17 00:00:00 2001 From: Alex Charlton Date: Sun, 8 Nov 2026 17:12:55 -0800 Subject: [PATCH 1/2] Port old solution Apply DPI-aware conversion around ScreenToClient in HWnd::screen_to_client --- src/wrappers/win32/window/handle.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/wrappers/win32/window/handle.rs b/src/wrappers/win32/window/handle.rs index 72d855b7..fbd35396 100644 --- a/src/wrappers/win32/window/handle.rs +++ b/src/wrappers/win32/window/handle.rs @@ -15,7 +15,10 @@ use windows_sys::Win32::Graphics::Gdi::{ MONITOR_DEFAULTTOPRIMARY, }; use windows_sys::Win32::System::Ole::{RegisterDragDrop, RevokeDragDrop}; -use windows_sys::Win32::UI::HiDpi::{DPI_HOSTING_BEHAVIOR_MIXED, MDT_DEFAULT}; +use windows_sys::Win32::UI::HiDpi::{ + LogicalToPhysicalPointForPerMonitorDPI, PhysicalToLogicalPointForPerMonitorDPI, + DPI_HOSTING_BEHAVIOR_MIXED, MDT_DEFAULT, +}; use windows_sys::Win32::UI::Input::KeyboardAndMouse::{ GetFocus, ReleaseCapture, SetCapture, SetFocus, TrackMouseEvent, TME_LEAVE, TRACKMOUSEEVENT, }; @@ -300,9 +303,17 @@ impl HWnd { pub fn screen_to_client(&self, pt: PhysicalPosition) -> Result> { let mut pt = POINT { x: pt.x, y: pt.y }; - let result = unsafe { ScreenToClient(self.as_raw(), &mut pt as *mut POINT) }; - if result == 0 { + // ScreenToClient isn't DPI-aware + if unsafe { PhysicalToLogicalPointForPerMonitorDPI(null_mut(), &mut pt) } == 0 { + return Err(Error::from_thread()); + } + + if unsafe { ScreenToClient(self.as_raw(), &mut pt) } == 0 { + return Err(Error::from_thread()); + } + + if unsafe { LogicalToPhysicalPointForPerMonitorDPI(null_mut(), &mut pt) } == 0 { return Err(Error::from_thread()); } From 21900b678fe648a504fb099bb44e8176eefbe112 Mon Sep 17 00:00:00 2001 From: Alex Charlton Date: Mon, 9 Nov 2026 15:07:03 -0800 Subject: [PATCH 2/2] Gate on dpi awareness --- src/platform/win/drop_target.rs | 9 ++++++++- src/wrappers/win32/window/handle.rs | 15 +++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/platform/win/drop_target.rs b/src/platform/win/drop_target.rs index 5a84fe68..b2c7c56c 100644 --- a/src/platform/win/drop_target.rs +++ b/src/platform/win/drop_target.rs @@ -66,7 +66,14 @@ impl DropTarget { } fn parse_coordinates(&self, pt: POINTL) { - let Ok(phy_point) = self.hwnd.screen_to_client(PhysicalPosition::new(pt.x, pt.y)) else { + let Some(window_state) = self.window_state.upgrade() else { + return; + }; + + let dpi_aware = !window_state.shared.dpi_scaling_strategy.get().assume_96_dpi; + let Ok(phy_point) = + self.hwnd.screen_to_client(PhysicalPosition::new(pt.x, pt.y), dpi_aware) + else { return; }; diff --git a/src/wrappers/win32/window/handle.rs b/src/wrappers/win32/window/handle.rs index fbd35396..8b4e718e 100644 --- a/src/wrappers/win32/window/handle.rs +++ b/src/wrappers/win32/window/handle.rs @@ -301,11 +301,17 @@ impl HWnd { } } - pub fn screen_to_client(&self, pt: PhysicalPosition) -> Result> { + /// Converts screen coordinates to client coordinates. + /// + /// For DPI-aware windows, OLE screen points can disagree with what + /// [`ScreenToClient`] expects, so we convert to logical space first and then back to physical. + pub fn screen_to_client( + &self, pt: PhysicalPosition, dpi_aware: bool, + ) -> Result> { let mut pt = POINT { x: pt.x, y: pt.y }; - // ScreenToClient isn't DPI-aware - if unsafe { PhysicalToLogicalPointForPerMonitorDPI(null_mut(), &mut pt) } == 0 { + if dpi_aware && unsafe { PhysicalToLogicalPointForPerMonitorDPI(null_mut(), &mut pt) } == 0 + { return Err(Error::from_thread()); } @@ -313,7 +319,8 @@ impl HWnd { return Err(Error::from_thread()); } - if unsafe { LogicalToPhysicalPointForPerMonitorDPI(null_mut(), &mut pt) } == 0 { + if dpi_aware && unsafe { LogicalToPhysicalPointForPerMonitorDPI(null_mut(), &mut pt) } == 0 + { return Err(Error::from_thread()); }