From bce39e2be195194e547b0021e770e45a3df15fa1 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Tue, 17 Jan 2023 14:07:10 +0200 Subject: [PATCH] feat: add file drop position (#847) * feat: add file drop position * Update src/webview/mod.rs * Update src/webview/mod.rs --- .changes/file-drop-cursor-position.md | 5 ++++ src/file_drop.rs | 5 ---- src/webview/mod.rs | 13 +++++++++-- src/webview/webkitgtk/file_drop.rs | 29 +++++++++++++++++++---- src/webview/webview2/file_drop.rs | 33 ++++++++++++++++++++++----- src/webview/wkwebview/file_drop.rs | 22 ++++++++++++++---- 6 files changed, 85 insertions(+), 22 deletions(-) create mode 100644 .changes/file-drop-cursor-position.md delete mode 100644 src/file_drop.rs diff --git a/.changes/file-drop-cursor-position.md b/.changes/file-drop-cursor-position.md new file mode 100644 index 000000000..a7d857bcd --- /dev/null +++ b/.changes/file-drop-cursor-position.md @@ -0,0 +1,5 @@ +--- +"wry": "minor" +--- + +**Breaking** Add position of the drop to `FileDropEvent` struct. \ No newline at end of file diff --git a/src/file_drop.rs b/src/file_drop.rs deleted file mode 100644 index bf9b516f7..000000000 --- a/src/file_drop.rs +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2020-2023 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use std::path::PathBuf; diff --git a/src/webview/mod.rs b/src/webview/mod.rs index a24d50978..775f79471 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -42,6 +42,7 @@ use wkwebview::*; pub(crate) mod webview2; #[cfg(target_os = "windows")] use self::webview2::*; +use crate::application::dpi::PhysicalPosition; use crate::Result; #[cfg(target_os = "windows")] use webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Controller; @@ -822,9 +823,17 @@ impl WebView { #[derive(Debug, Serialize, Clone)] pub enum FileDropEvent { /// The file(s) have been dragged onto the window, but have not been dropped yet. - Hovered(Vec), + Hovered { + paths: Vec, + /// The position of the mouse cursor. + position: PhysicalPosition, + }, /// The file(s) have been dropped onto the window. - Dropped(Vec), + Dropped { + paths: Vec, + /// The position of the mouse cursor. + position: PhysicalPosition, + }, /// The file drop was aborted. Cancelled, } diff --git a/src/webview/webkitgtk/file_drop.rs b/src/webview/webkitgtk/file_drop.rs index 15b8dfe02..e0e0af08e 100644 --- a/src/webview/webkitgtk/file_drop.rs +++ b/src/webview/webkitgtk/file_drop.rs @@ -5,6 +5,7 @@ use std::{cell::Cell, path::PathBuf, rc::Rc}; use gtk::prelude::*; +use tao::dpi::LogicalPosition; use webkit2gtk::WebView; use crate::{application::window::Window, webview::FileDropEvent}; @@ -18,7 +19,7 @@ pub(crate) fn connect_drag_event( let listener_ref = listener.clone(); let w = window.clone(); - webview.connect_drag_data_received(move |_, _, _, _, data, info, _| { + webview.connect_drag_data_received(move |_, _, x, y, data, info, _| { if info == 2 { let uris = data .uris() @@ -28,9 +29,18 @@ pub(crate) fn connect_drag_event( PathBuf::from(path.to_string().strip_prefix("file://").unwrap_or(path)) }) .collect::>(); - listener_ref.1.set(Some(uris.clone())); - listener_ref.0(&w, FileDropEvent::Hovered(uris)); + + let scale_factor = w.scale_factor(); + let position = LogicalPosition::new(x, y).to_physical(scale_factor); + + listener_ref.0( + &w, + FileDropEvent::Hovered { + paths: uris, + position, + }, + ); } else { // drag_data_received is called twice, so we can ignore this signal } @@ -38,10 +48,19 @@ pub(crate) fn connect_drag_event( let listener_ref = listener.clone(); let w = window.clone(); - webview.connect_drag_drop(move |_, _, _, _, _| { + webview.connect_drag_drop(move |_, _, x, y, _| { let uris = listener_ref.1.take(); if let Some(uris) = uris { - listener_ref.0(&w, FileDropEvent::Dropped(uris)) + let scale_factor = w.scale_factor(); + let position = LogicalPosition::new(x, y).to_physical(scale_factor); + + listener_ref.0( + &w, + FileDropEvent::Dropped { + paths: uris, + position, + }, + ) } else { false } diff --git a/src/webview/webview2/file_drop.rs b/src/webview/webview2/file_drop.rs index 77cc1471b..fce43345f 100644 --- a/src/webview/webview2/file_drop.rs +++ b/src/webview/webview2/file_drop.rs @@ -19,7 +19,8 @@ use std::{ }; use windows::Win32::{ - Foundation::{self as win32f, BOOL, DRAGDROP_E_INVALIDHWND, HWND, LPARAM, POINTL}, + Foundation::{self as win32f, BOOL, DRAGDROP_E_INVALIDHWND, HWND, LPARAM, POINT, POINTL}, + Graphics::Gdi::ScreenToClient, System::{ Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL}, Ole::{ @@ -36,7 +37,9 @@ use windows::Win32::{ use windows_implement::implement; -use crate::application::window::Window; +use crate::application::{ + dpi::PhysicalPosition, platform::windows::WindowExtWindows, window::Window, +}; pub(crate) struct FileDropController { drop_targets: Vec, @@ -188,7 +191,7 @@ impl IDropTarget_Impl for FileDropHandler { &self, pDataObj: &Option, _grfKeyState: u32, - _pt: &POINTL, + pt: &POINTL, pdwEffect: *mut u32, ) -> windows::core::Result<()> { let mut paths = Vec::new(); @@ -203,9 +206,18 @@ impl IDropTarget_Impl for FileDropHandler { *pdwEffect = cursor_effect.0; *self.hovered_is_valid.get() = hovered_is_valid; *self.cursor_effect.get() = cursor_effect.0; + + let mut pt = POINT { x: pt.x, y: pt.y }; + ScreenToClient(HWND(self.window.hwnd() as _), &mut pt); } - (self.listener)(&self.window, FileDropEvent::Hovered(paths)); + (self.listener)( + &self.window, + FileDropEvent::Hovered { + paths, + position: PhysicalPosition::new(pt.x as _, pt.y as _), + }, + ); Ok(()) } @@ -231,7 +243,7 @@ impl IDropTarget_Impl for FileDropHandler { &self, pDataObj: &Option, _grfKeyState: u32, - _pt: &POINTL, + pt: &POINTL, _pdwEffect: *mut u32, ) -> windows::core::Result<()> { let mut paths = Vec::new(); @@ -240,9 +252,18 @@ impl IDropTarget_Impl for FileDropHandler { if let Some(hdrop) = hdrop { DragFinish(hdrop); } + + let mut pt = POINT { x: pt.x, y: pt.y }; + ScreenToClient(HWND(self.window.hwnd() as _), &mut pt); } - (self.listener)(&self.window, FileDropEvent::Dropped(paths)); + (self.listener)( + &self.window, + FileDropEvent::Dropped { + paths, + position: PhysicalPosition::new(pt.x as _, pt.y as _), + }, + ); Ok(()) } diff --git a/src/webview/wkwebview/file_drop.rs b/src/webview/wkwebview/file_drop.rs index 52b128fff..91d499dd7 100644 --- a/src/webview/wkwebview/file_drop.rs +++ b/src/webview/wkwebview/file_drop.rs @@ -8,14 +8,20 @@ use std::{ rc::Rc, }; -use cocoa::base::{id, BOOL, YES}; +use cocoa::{ + base::{id, BOOL, YES}, + foundation::NSPoint, +}; use objc::{ declare::ClassDecl, runtime::{class_getInstanceMethod, method_getImplementation, Object, Sel}, }; use once_cell::sync::Lazy; -use crate::{application::window::Window, webview::FileDropEvent}; +use crate::{ + application::{dpi::LogicalPosition, window::Window}, + webview::FileDropEvent, +}; pub(crate) type NSDragOperation = cocoa::foundation::NSUInteger; #[allow(non_upper_case_globals)] @@ -109,7 +115,11 @@ extern "C" fn dragging_entered(this: &mut Object, sel: Sel, drag_info: id) -> NS let listener = unsafe { get_handler(this) }; let paths = unsafe { collect_paths(drag_info) }; - if !listener.0(&listener.1, FileDropEvent::Hovered(paths)) { + let dl: NSPoint = unsafe { msg_send![this, draggingLocation] }; + let scale_factor = listener.1.scale_factor(); + let position = LogicalPosition::::from((dl.x, dl.y)).to_physical(scale_factor); + + if !listener.0(&listener.1, FileDropEvent::Hovered { paths, position }) { // Reject the Wry file drop (invoke the OS default behaviour) OBJC_DRAGGING_ENTERED(this, sel, drag_info) } else { @@ -121,7 +131,11 @@ extern "C" fn perform_drag_operation(this: &mut Object, sel: Sel, drag_info: id) let listener = unsafe { get_handler(this) }; let paths = unsafe { collect_paths(drag_info) }; - if !listener.0(&listener.1, FileDropEvent::Dropped(paths)) { + let dl: NSPoint = unsafe { msg_send![this, draggingLocation] }; + let scale_factor = listener.1.scale_factor(); + let position = LogicalPosition::::from((dl.x, dl.y)).to_physical(scale_factor); + + if !listener.0(&listener.1, FileDropEvent::Dropped { paths, position }) { // Reject the Wry file drop (invoke the OS default behaviour) OBJC_PERFORM_DRAG_OPERATION(this, sel, drag_info) } else {