diff --git a/.changes/refactor-file-drop.md b/.changes/refactor-file-drop.md new file mode 100644 index 000000000..d2bfbc377 --- /dev/null +++ b/.changes/refactor-file-drop.md @@ -0,0 +1,6 @@ +--- +"tauri-runtime": minor +"tauri-runtime-wry": minor +--- + +The file drop event is now part of the `WindowEvent` enum instead of a having a dedicated handler. diff --git a/.changes/runtime-file-drop-event.md b/.changes/runtime-file-drop-event.md new file mode 100644 index 000000000..6fd9beb2b --- /dev/null +++ b/.changes/runtime-file-drop-event.md @@ -0,0 +1,5 @@ +--- +"tauri-runtime": patch +--- + +**Breaking change:** Move the `FileDropEvent` struct to the `window` module. diff --git a/.changes/window-event-file-drop.md b/.changes/window-event-file-drop.md new file mode 100644 index 000000000..42c3de0ce --- /dev/null +++ b/.changes/window-event-file-drop.md @@ -0,0 +1,7 @@ +--- +"tauri": patch +"tauri-runtime": minor +"tauri-runtime-wry": minor +--- + +Added the `WindowEvent::FileDrop` variant. diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index 1a5d882e9..684ae1d99 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -11,10 +11,10 @@ use tauri_runtime::{ }, menu::{CustomMenuItem, Menu, MenuEntry, MenuHash, MenuId, MenuItem, MenuUpdate}, monitor::Monitor, - webview::{FileDropEvent, FileDropHandler, WebviewIpcHandler, WindowBuilder, WindowBuilderBase}, + webview::{WebviewIpcHandler, WindowBuilder, WindowBuilderBase}, window::{ dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}, - DetachedWindow, JsEventListenerKey, PendingWindow, WindowEvent, + DetachedWindow, FileDropEvent, JsEventListenerKey, PendingWindow, WindowEvent, }, ClipboardManager, Dispatch, Error, ExitRequestedEventAction, GlobalShortcutManager, Result, RunEvent, RunIteration, Runtime, RuntimeHandle, UserAttentionType, WindowIcon, @@ -2624,7 +2624,6 @@ fn create_webview( uri_scheme_protocols, mut window_builder, ipc_handler, - file_drop_handler, label, url, menu_ids, @@ -2663,17 +2662,11 @@ fn create_webview( .with_url(&url) .unwrap() // safe to unwrap because we validate the URL beforehand .with_transparent(is_window_transparent); + if webview_attributes.file_drop_handler_enabled { + webview_builder = webview_builder.with_file_drop_handler(create_file_drop_handler(&context)); + } if let Some(handler) = ipc_handler { webview_builder = webview_builder.with_ipc_handler(create_ipc_handler( - context.clone(), - label.clone(), - menu_ids.clone(), - js_event_listeners.clone(), - handler, - )); - } - if let Some(handler) = file_drop_handler { - webview_builder = webview_builder.with_file_drop_handler(create_file_drop_handler( context, label.clone(), menu_ids, @@ -2763,26 +2756,25 @@ fn create_ipc_handler( }) } -/// Create a wry file drop handler from a tauri file drop handler. +/// Create a wry file drop handler. fn create_file_drop_handler( - context: Context, - label: String, - menu_ids: Arc>>, - js_event_listeners: Arc>>>, - handler: FileDropHandler, + context: &Context, ) -> Box bool + 'static> { + let window_event_listeners = context.window_event_listeners.clone(); Box::new(move |window, event| { - handler( - FileDropEventWrapper(event).into(), - DetachedWindow { - dispatcher: WryDispatcher { - window_id: window.id(), - context: context.clone(), - }, - label: label.clone(), - menu_ids: menu_ids.clone(), - js_event_listeners: js_event_listeners.clone(), - }, - ) + let event: FileDropEvent = FileDropEventWrapper(event).into(); + let window_event = WindowEvent::FileDrop(event); + let listeners = window_event_listeners.lock().unwrap(); + if let Some(window_listeners) = listeners.get(&window.id()) { + let listeners_map = window_listeners.lock().unwrap(); + let has_listener = !listeners_map.is_empty(); + for listener in listeners_map.values() { + listener(&window_event); + } + // block the default OS action on file drop if we had a listener + has_listener + } else { + false + } }) } diff --git a/core/tauri-runtime/src/webview.rs b/core/tauri-runtime/src/webview.rs index b33f9e14a..5ee462f42 100644 --- a/core/tauri-runtime/src/webview.rs +++ b/core/tauri-runtime/src/webview.rs @@ -184,21 +184,5 @@ pub trait WindowBuilder: WindowBuilderBase { fn get_menu(&self) -> Option<&Menu>; } -/// The file drop event payload. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum FileDropEvent { - /// The file(s) have been dragged onto the window, but have not been dropped yet. - Hovered(Vec), - /// The file(s) have been dropped onto the window. - Dropped(Vec), - /// The file drop was aborted. - Cancelled, -} - /// IPC handler. pub type WebviewIpcHandler = Box, String) + Send>; - -/// File drop handler callback -/// Return `true` in the callback to block the OS' default behavior of handling a file drop. -pub type FileDropHandler = Box) -> bool + Send>; diff --git a/core/tauri-runtime/src/window.rs b/core/tauri-runtime/src/window.rs index 059cd7339..4e58404d2 100644 --- a/core/tauri-runtime/src/window.rs +++ b/core/tauri-runtime/src/window.rs @@ -7,7 +7,7 @@ use crate::{ http::{Request as HttpRequest, Response as HttpResponse}, menu::{Menu, MenuEntry, MenuHash, MenuId}, - webview::{FileDropHandler, WebviewAttributes, WebviewIpcHandler}, + webview::{WebviewAttributes, WebviewIpcHandler}, Dispatch, Runtime, WindowBuilder, }; use serde::Serialize; @@ -16,6 +16,7 @@ use tauri_utils::config::WindowConfig; use std::{ collections::{HashMap, HashSet}, hash::{Hash, Hasher}, + path::PathBuf, sync::{mpsc::Sender, Arc, Mutex}, }; @@ -59,6 +60,20 @@ pub enum WindowEvent { /// The window inner size. new_inner_size: dpi::PhysicalSize, }, + /// An event associated with the file drop action. + FileDrop(FileDropEvent), +} + +/// The file drop event payload. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum FileDropEvent { + /// The file(s) have been dragged onto the window, but have not been dropped yet. + Hovered(Vec), + /// The file(s) have been dropped onto the window. + Dropped(Vec), + /// The file drop was aborted. + Cancelled, } /// A menu event. @@ -96,9 +111,6 @@ pub struct PendingWindow { /// How to handle IPC calls on the webview window. pub ipc_handler: Option>, - /// How to handle a file dropping onto the webview window. - pub file_drop_handler: Option>, - /// The resolved URL to load on the webview. pub url: String, @@ -143,7 +155,6 @@ impl PendingWindow { uri_scheme_protocols: Default::default(), label, ipc_handler: None, - file_drop_handler: None, url: "tauri://localhost".to_string(), menu_ids: Arc::new(Mutex::new(menu_ids)), js_event_listeners: Default::default(), @@ -172,7 +183,6 @@ impl PendingWindow { uri_scheme_protocols: Default::default(), label, ipc_handler: None, - file_drop_handler: None, url: "tauri://localhost".to_string(), menu_ids: Arc::new(Mutex::new(menu_ids)), js_event_listeners: Default::default(), diff --git a/core/tauri/src/lib.rs b/core/tauri/src/lib.rs index f6c50ad66..2f2ce2551 100644 --- a/core/tauri/src/lib.rs +++ b/core/tauri/src/lib.rs @@ -213,7 +213,7 @@ pub use { webview::{WebviewAttributes, WindowBuilder}, window::{ dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size}, - WindowEvent, + FileDropEvent, WindowEvent, }, ClipboardManager, GlobalShortcutManager, RunIteration, Runtime, TrayIcon, UserAttentionType, }, diff --git a/core/tauri/src/manager.rs b/core/tauri/src/manager.rs index 53374e3d3..20a1a081b 100644 --- a/core/tauri/src/manager.rs +++ b/core/tauri/src/manager.rs @@ -39,8 +39,8 @@ use crate::{ MimeType, Request as HttpRequest, Response as HttpResponse, ResponseBuilder as HttpResponseBuilder, }, - webview::{FileDropEvent, FileDropHandler, WebviewIpcHandler, WindowBuilder}, - window::{dpi::PhysicalSize, DetachedWindow, PendingWindow, WindowEvent}, + webview::{WebviewIpcHandler, WindowBuilder}, + window::{dpi::PhysicalSize, DetachedWindow, FileDropEvent, PendingWindow, WindowEvent}, Runtime, }, utils::{ @@ -838,30 +838,6 @@ impl WindowManager { }) } - fn prepare_file_drop(&self, app_handle: AppHandle) -> FileDropHandler { - let manager = self.clone(); - Box::new(move |event, window| { - let window = Window::new(manager.clone(), window, app_handle.clone()); - let _ = match event { - FileDropEvent::Hovered(paths) => window.emit_and_trigger("tauri://file-drop-hover", paths), - FileDropEvent::Dropped(paths) => { - let scopes = window.state::(); - for path in &paths { - if path.is_file() { - let _ = scopes.allow_file(path); - } else { - let _ = scopes.allow_directory(path, false); - } - } - window.emit_and_trigger("tauri://file-drop", paths) - } - FileDropEvent::Cancelled => window.emit_and_trigger("tauri://file-drop-cancelled", ()), - _ => unimplemented!(), - }; - true - }) - } - fn initialization_script( &self, ipc_script: &str, @@ -1082,11 +1058,7 @@ impl WindowManager { app_handle.clone(), web_resource_request_handler, )?; - pending.ipc_handler = Some(self.prepare_ipc_handler(app_handle.clone())); - } - - if pending.webview_attributes.file_drop_handler_enabled { - pending.file_drop_handler = Some(self.prepare_file_drop(app_handle)); + pending.ipc_handler = Some(self.prepare_ipc_handler(app_handle)); } // in `Windows`, we need to force a data_directory @@ -1291,6 +1263,22 @@ fn on_window_event( size: *new_inner_size, }, )?, + WindowEvent::FileDrop(event) => match event { + FileDropEvent::Hovered(paths) => window.emit_and_trigger("tauri://file-drop-hover", paths)?, + FileDropEvent::Dropped(paths) => { + let scopes = window.state::(); + for path in paths { + if path.is_file() { + let _ = scopes.allow_file(path); + } else { + let _ = scopes.allow_directory(path, false); + } + } + window.emit_and_trigger("tauri://file-drop", paths)? + } + FileDropEvent::Cancelled => window.emit_and_trigger("tauri://file-drop-cancelled", ())?, + _ => unimplemented!(), + }, _ => unimplemented!(), } Ok(())