Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework DnD #2615

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre

# Unreleased

- **Breaking:** Add cursor position to `DroppedFile` and `HoveredFile` events.
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
- **Breaking:** On Web, touch input no longer fires `WindowEvent::Cursor*`, `WindowEvent::MouseInput`, or `DeviceEvent::MouseMotion` like other platforms, but instead it fires `WindowEvent::Touch`.
- **Breaking:** Removed platform specific `WindowBuilder::with_parent` API in favor of `WindowBuilder::with_parent_window`.
- On Windows, retain `WS_MAXIMIZE` window style when un-minimizing a maximized window.
Expand Down
2 changes: 1 addition & 1 deletion examples/window_icon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn main() {
use winit::event::WindowEvent::*;
match event {
CloseRequested => control_flow.set_exit(),
DroppedFile(path) => {
DroppedFile { path, .. } => {
window.set_window_icon(Some(load_icon(&path)));
}
_ => (),
Expand Down
26 changes: 20 additions & 6 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,13 +337,21 @@ pub enum WindowEvent<'a> {
///
/// When the user drops multiple files at once, this event will be emitted for each file
/// separately.
DroppedFile(PathBuf),
DroppedFile {
path: PathBuf,
// (x,y) coords in pixels relative to the top-left corner of the window.
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
position: PhysicalPosition<f64>,
},

/// A file is being hovered over the window.
///
/// When the user hovers multiple files at once, this event will be emitted for each file
/// separately.
HoveredFile(PathBuf),
HoveredFile {
path: PathBuf,
// (x,y) coords in pixels relative to the top-left corner of the window.
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
position: PhysicalPosition<f64>,
},

/// A file was hovered, but has exited the window.
///
Expand Down Expand Up @@ -529,8 +537,14 @@ impl Clone for WindowEvent<'static> {
Moved(pos) => Moved(*pos),
CloseRequested => CloseRequested,
Destroyed => Destroyed,
DroppedFile(file) => DroppedFile(file.clone()),
HoveredFile(file) => HoveredFile(file.clone()),
DroppedFile { path, position } => DroppedFile {
path: path.clone(),
position: *position,
},
HoveredFile { path, position } => HoveredFile {
path: path.clone(),
position: *position,
},
HoveredFileCancelled => HoveredFileCancelled,
ReceivedCharacter(c) => ReceivedCharacter(*c),
Focused(f) => Focused(*f),
Expand Down Expand Up @@ -639,8 +653,8 @@ impl<'a> WindowEvent<'a> {
Moved(position) => Some(Moved(position)),
CloseRequested => Some(CloseRequested),
Destroyed => Some(Destroyed),
DroppedFile(file) => Some(DroppedFile(file)),
HoveredFile(file) => Some(HoveredFile(file)),
DroppedFile { path, position } => Some(DroppedFile { path, position }),
HoveredFile { path, position } => Some(HoveredFile { path, position }),
HoveredFileCancelled => Some(HoveredFileCancelled),
ReceivedCharacter(c) => Some(ReceivedCharacter(c)),
Focused(focused) => Some(Focused(focused)),
Expand Down
3 changes: 3 additions & 0 deletions src/platform_impl/linux/x11/dnd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ pub struct Dnd {
pub type_list: Option<Vec<c_ulong>>,
// Populated by XdndPosition event handler
pub source_window: Option<c_ulong>,
// Populated by XdndPosition event handler
pub position: (c_long, c_long),
// Populated by SelectionNotify event handler (triggered by XdndPosition event handler)
pub result: Option<Result<Vec<PathBuf>, DndDataParseError>>,
}
Expand All @@ -108,6 +110,7 @@ impl Dnd {
version: None,
type_list: None,
source_window: None,
position: (0, 0),
result: None,
})
}
Expand Down
25 changes: 19 additions & 6 deletions src/platform_impl/linux/x11/event_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,11 @@ impl<T: 'static> EventProcessor<T> {
// where `shift = mem::size_of::<c_short>() * 8`
// Note that coordinates are in "desktop space", not "window space"
// (in X11 parlance, they're root window coordinates)
//let packed_coordinates = client_msg.data.get_long(2);
//let shift = mem::size_of::<libc::c_short>() * 8;
//let x = packed_coordinates >> shift;
//let y = packed_coordinates & !(x << shift);
let packed_coordinates = client_msg.data.get_long(2);
let shift = std::mem::size_of::<libc::c_short>() * 8;
let x = packed_coordinates >> shift;
let y = packed_coordinates & !(x << shift);
self.dnd.position = (x, y);

// By our own state flow, `version` should never be `None` at this point.
let version = self.dnd.version.unwrap_or(5);
Expand Down Expand Up @@ -277,7 +278,13 @@ impl<T: 'static> EventProcessor<T> {
for path in path_list {
callback(Event::WindowEvent {
window_id,
event: WindowEvent::DroppedFile(path.clone()),
event: WindowEvent::DroppedFile {
path: path.clone(),
position: PhysicalPosition::new(
self.dnd.position.0 as f64,
self.dnd.position.1 as f64,
),
},
});
}
}
Expand Down Expand Up @@ -319,7 +326,13 @@ impl<T: 'static> EventProcessor<T> {
for path in path_list {
callback(Event::WindowEvent {
window_id,
event: WindowEvent::HoveredFile(path.clone()),
event: WindowEvent::HoveredFile {
path: path.clone(),
position: PhysicalPosition::new(
self.dnd.position.0 as f64,
self.dnd.position.1 as f64,
),
},
});
}
}
Expand Down
14 changes: 11 additions & 3 deletions src/platform_impl/macos/window_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::ptr;

use objc2::declare::{Ivar, IvarDrop};
use objc2::foundation::{NSArray, NSObject, NSString};
use objc2::foundation::{NSArray, NSObject, NSPoint, NSString};
use objc2::rc::{autoreleasepool, Id, Shared};
use objc2::runtime::Object;
use objc2::{class, declare_class, msg_send, msg_send_id, sel, ClassType};
Expand Down Expand Up @@ -172,9 +172,13 @@ declare_class!(
let filenames = pb.propertyListForType(unsafe { NSFilenamesPboardType });
let filenames: Id<NSArray<NSString>, Shared> = unsafe { Id::cast(filenames) };

let dl: NSPoint = unsafe { msg_send![sender, draggingLocation] };
let scale_factor = self.window.scale_factor();
let position = LogicalPosition::<f64>::from((dl.x, dl.y)).to_physical(scale_factor);
amrbashir marked this conversation as resolved.
Show resolved Hide resolved

filenames.into_iter().for_each(|file| {
let path = PathBuf::from(file.to_string());
self.emit_event(WindowEvent::HoveredFile(path));
self.emit_event(WindowEvent::HoveredFile { path, position });
});

true
Expand All @@ -198,9 +202,13 @@ declare_class!(
let filenames = pb.propertyListForType(unsafe { NSFilenamesPboardType });
let filenames: Id<NSArray<NSString>, Shared> = unsafe { Id::cast(filenames) };

let dl: NSPoint = unsafe { msg_send![sender, draggingLocation] };
let scale_factor = self.window.scale_factor();
let position = LogicalPosition::<f64>::from((dl.x, dl.y)).to_physical(scale_factor);

filenames.into_iter().for_each(|file| {
let path = PathBuf::from(file.to_string());
self.emit_event(WindowEvent::DroppedFile(path));
self.emit_event(WindowEvent::DroppedFile { path, position });
});

true
Expand Down
6 changes: 3 additions & 3 deletions src/platform_impl/windows/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,21 @@ pub struct IDropTargetVtbl {
This: *mut IDropTarget,
pDataObj: *const IDataObject,
grfKeyState: u32,
pt: *const POINTL,
pt: POINTL,
pdwEffect: *mut u32,
) -> HRESULT,
pub DragOver: unsafe extern "system" fn(
This: *mut IDropTarget,
grfKeyState: u32,
pt: *const POINTL,
pt: POINTL,
pdwEffect: *mut u32,
) -> HRESULT,
pub DragLeave: unsafe extern "system" fn(This: *mut IDropTarget) -> HRESULT,
pub Drop: unsafe extern "system" fn(
This: *mut IDropTarget,
pDataObj: *const IDataObject,
grfKeyState: u32,
pt: *const POINTL,
pt: POINTL,
pdwEffect: *mut u32,
) -> HRESULT,
}
Expand Down
32 changes: 21 additions & 11 deletions src/platform_impl/windows/drop_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use std::{
use windows_sys::{
core::{IUnknown, GUID, HRESULT},
Win32::{
Foundation::{DV_E_FORMATETC, HWND, POINTL, S_OK},
Foundation::{DV_E_FORMATETC, HWND, POINT, POINTL, S_OK},
Graphics::Gdi::ScreenToClient,
System::{
Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL},
Ole::{DROPEFFECT_COPY, DROPEFFECT_NONE},
Expand All @@ -19,9 +20,12 @@ use windows_sys::{
},
};

use crate::platform_impl::platform::{
definitions::{IDataObjectVtbl, IDropTarget, IDropTargetVtbl, IUnknownVtbl},
WindowId,
use crate::{
dpi::PhysicalPosition,
platform_impl::platform::{
definitions::{IDataObjectVtbl, IDropTarget, IDropTargetVtbl, IUnknownVtbl},
WindowId,
},
};

use crate::{event::Event, window::WindowId as RootWindowId};
Expand Down Expand Up @@ -89,15 +93,18 @@ impl FileDropHandler {
this: *mut IDropTarget,
pDataObj: *const IDataObject,
_grfKeyState: u32,
_pt: *const POINTL,
pt: POINTL,
pdwEffect: *mut u32,
) -> HRESULT {
use crate::event::WindowEvent::HoveredFile;
let drop_handler = Self::from_interface(this);
let hdrop = Self::iterate_filenames(pDataObj, |filename| {
let mut pt = POINT { x: pt.x, y: pt.y };
ScreenToClient(drop_handler.window, &mut pt);
let position = PhysicalPosition::new(pt.x as f64, pt.y as f64);
let hdrop = Self::iterate_filenames(pDataObj, |path| {
drop_handler.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(drop_handler.window)),
event: HoveredFile(filename),
event: HoveredFile { path, position },
});
});
drop_handler.hovered_is_valid = hdrop.is_some();
Expand All @@ -114,7 +121,7 @@ impl FileDropHandler {
pub unsafe extern "system" fn DragOver(
this: *mut IDropTarget,
_grfKeyState: u32,
_pt: *const POINTL,
_pt: POINTL,
pdwEffect: *mut u32,
) -> HRESULT {
let drop_handler = Self::from_interface(this);
Expand All @@ -140,15 +147,18 @@ impl FileDropHandler {
this: *mut IDropTarget,
pDataObj: *const IDataObject,
_grfKeyState: u32,
_pt: *const POINTL,
pt: POINTL,
_pdwEffect: *mut u32,
) -> HRESULT {
use crate::event::WindowEvent::DroppedFile;
let drop_handler = Self::from_interface(this);
let hdrop = Self::iterate_filenames(pDataObj, |filename| {
let mut pt = POINT { x: pt.x, y: pt.y };
ScreenToClient(drop_handler.window, &mut pt);
let position = PhysicalPosition::new(pt.x as f64, pt.y as f64);
let hdrop = Self::iterate_filenames(pDataObj, |path| {
drop_handler.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(drop_handler.window)),
event: DroppedFile(filename),
event: DroppedFile { path, position },
});
});
if let Some(hdrop) = hdrop {
Expand Down