Skip to content

Commit daf6cbd

Browse files
committed
Fix drag & drop event coordinates on Windows
1 parent dd350f8 commit daf6cbd

2 files changed

Lines changed: 52 additions & 38 deletions

File tree

plugin-canvas/src/platform/win32/drop_target.rs

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,17 @@ use std::ptr::null_mut;
66
use std::sync::Weak;
77

88
use windows::Win32::Foundation::{POINTL, POINT};
9-
use windows::Win32::Graphics::Gdi::MapWindowPoints;
9+
use windows::Win32::Graphics::Gdi::ScreenToClient;
1010
use windows::Win32::System::Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL};
1111
use windows::Win32::System::SystemServices::MODIFIERKEYS_FLAGS;
12+
use windows::Win32::UI::HiDpi::{LogicalToPhysicalPointForPerMonitorDPI, PhysicalToLogicalPointForPerMonitorDPI};
1213
use windows::Win32::UI::Shell::{DragQueryFileW, HDROP};
1314
use windows::core::implement;
1415
use windows::Win32::System::Ole::{IDropTarget, IDropTarget_Impl, DROPEFFECT, CF_HDROP, DROPEFFECT_NONE, DROPEFFECT_COPY, DROPEFFECT_MOVE, DROPEFFECT_LINK};
15-
use windows::Win32::UI::WindowsAndMessaging::HWND_DESKTOP;
1616

1717
use crate::event::EventResponse;
18-
use crate::platform::interface::OsWindowInterface;
1918
use crate::thread_bound::ThreadBound;
20-
use crate::{LogicalPosition, PhysicalPosition};
19+
use crate::LogicalPosition;
2120
use crate::drag_drop::{DropData, DropOperation};
2221
use super::window::OsWindow;
2322

@@ -52,7 +51,7 @@ impl DropTarget {
5251
unsafe {
5352
let medium = data_object.GetData(&format)?;
5453
let hdrop = HDROP(medium.u.hGlobal.0);
55-
54+
5655
let item_count = DragQueryFileW(hdrop, 0xFFFFFFFF, None);
5756
if item_count == 0 {
5857
*self.drop_data.borrow_mut() = DropData::None;
@@ -91,24 +90,29 @@ impl DropTarget {
9190
}
9291
}
9392

94-
fn convert_coordinates(&self, point: &POINTL) -> LogicalPosition {
95-
let Some(window) = self.window.upgrade() else {
96-
return LogicalPosition::default();
97-
};
93+
fn convert_coordinates(&self, point: &POINTL) -> Option<LogicalPosition> {
94+
let window = self.window.upgrade()?;
9895

99-
let scale = window.os_scale();
96+
let scale = window.scale();
97+
let mut point = POINT { x: (point.x as f64) as _, y: (point.y as f64) as _ };
10098

101-
// It looks like MapWindowPoints isn't DPI aware (and neither is ScreenToClient),
102-
// so we need to pre-scale the point here?
103-
// TODO: Find out what's going on
104-
let mut points = [POINT { x: (point.x as f64 / scale) as i32, y: (point.y as f64 / scale) as i32 }];
99+
// ScreenToClient doesn't seem to be DPI-aware
100+
if unsafe { !PhysicalToLogicalPointForPerMonitorDPI(None, &mut point).as_bool() } {
101+
return None;
102+
}
105103

106-
unsafe { MapWindowPoints(Some(HWND_DESKTOP), Some(window.hwnd()), &mut points); }
104+
if unsafe { !ScreenToClient(window.hwnd(), &mut point).as_bool() } {
105+
return None;
106+
}
107+
108+
if unsafe { !LogicalToPhysicalPointForPerMonitorDPI(None, &mut point).as_bool() } {
109+
return None;
110+
}
107111

108-
PhysicalPosition {
109-
x: points[0].x,
110-
y: points[0].y,
111-
}.to_logical(1.0)
112+
Some(LogicalPosition {
113+
x: point.x as f64 / scale,
114+
y: point.y as f64 / scale,
115+
})
112116
}
113117
}
114118

@@ -121,13 +125,15 @@ impl IDropTarget_Impl for DropTarget_Impl {
121125

122126
self.parse_drag_data(pdataobj)?;
123127

124-
let response = window.send_event(crate::Event::DragEntered {
125-
position: self.convert_coordinates(pt),
126-
data: self.drop_data.borrow().clone(),
127-
});
128-
129-
unsafe { *pdweffect = self.convert_drag_operation(response) };
130-
128+
if let Some(position) = self.convert_coordinates(pt) {
129+
let response = window.send_event(crate::Event::DragEntered {
130+
position,
131+
data: self.drop_data.borrow().clone(),
132+
});
133+
134+
unsafe { *pdweffect = self.convert_drag_operation(response) };
135+
}
136+
131137
Ok(())
132138
}
133139

@@ -136,12 +142,14 @@ impl IDropTarget_Impl for DropTarget_Impl {
136142
return Ok(());
137143
};
138144

139-
let response = window.send_event(crate::Event::DragMoved {
140-
position: self.convert_coordinates(pt),
141-
data: self.drop_data.borrow().clone(),
142-
});
143-
144-
unsafe { *pdweffect = self.convert_drag_operation(response) };
145+
if let Some(position) = self.convert_coordinates(pt) {
146+
let response = window.send_event(crate::Event::DragMoved {
147+
position,
148+
data: self.drop_data.borrow().clone(),
149+
});
150+
151+
unsafe { *pdweffect = self.convert_drag_operation(response) };
152+
}
145153

146154
Ok(())
147155
}
@@ -163,12 +171,14 @@ impl IDropTarget_Impl for DropTarget_Impl {
163171

164172
self.parse_drag_data(pdataobj)?;
165173

166-
let response = window.send_event(crate::Event::DragDropped {
167-
position: self.convert_coordinates(pt),
168-
data: self.drop_data.borrow().clone(),
169-
});
170-
171-
unsafe { *pdweffect = self.convert_drag_operation(response) };
174+
if let Some(position) = self.convert_coordinates(pt) {
175+
let response = window.send_event(crate::Event::DragDropped {
176+
position,
177+
data: self.drop_data.borrow().clone(),
178+
});
179+
180+
unsafe { *pdweffect = self.convert_drag_operation(response) };
181+
}
172182

173183
Ok(())
174184
}

plugin-canvas/src/platform/win32/window.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ impl OsWindow {
4848
HWND(self.window_handle.hwnd.get() as _)
4949
}
5050

51+
pub(super) fn scale(&self) -> f64 {
52+
self.scale.load(Ordering::Acquire)
53+
}
54+
5155
fn button_down(&self, button: MouseButton, position: LogicalPosition) {
5256
{
5357
let mut buttons_down = self.buttons_down.borrow_mut();

0 commit comments

Comments
 (0)