Skip to content

Commit 07d1584

Browse files
authored
feat(core): add WindowEvent::FileDrop, closes #3664 (#3686)
1 parent c40f640 commit 07d1584

File tree

8 files changed

+76
-84
lines changed

8 files changed

+76
-84
lines changed

.changes/refactor-file-drop.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"tauri-runtime": minor
3+
"tauri-runtime-wry": minor
4+
---
5+
6+
The file drop event is now part of the `WindowEvent` enum instead of a having a dedicated handler.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri-runtime": patch
3+
---
4+
5+
**Breaking change:** Move the `FileDropEvent` struct to the `window` module.

.changes/window-event-file-drop.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"tauri": patch
3+
"tauri-runtime": minor
4+
"tauri-runtime-wry": minor
5+
---
6+
7+
Added the `WindowEvent::FileDrop` variant.

core/tauri-runtime-wry/src/lib.rs

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ use tauri_runtime::{
1111
},
1212
menu::{CustomMenuItem, Menu, MenuEntry, MenuHash, MenuId, MenuItem, MenuUpdate},
1313
monitor::Monitor,
14-
webview::{FileDropEvent, FileDropHandler, WebviewIpcHandler, WindowBuilder, WindowBuilderBase},
14+
webview::{WebviewIpcHandler, WindowBuilder, WindowBuilderBase},
1515
window::{
1616
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
17-
DetachedWindow, JsEventListenerKey, PendingWindow, WindowEvent,
17+
DetachedWindow, FileDropEvent, JsEventListenerKey, PendingWindow, WindowEvent,
1818
},
1919
ClipboardManager, Dispatch, Error, ExitRequestedEventAction, GlobalShortcutManager, Result,
2020
RunEvent, RunIteration, Runtime, RuntimeHandle, UserAttentionType, WindowIcon,
@@ -2624,7 +2624,6 @@ fn create_webview(
26242624
uri_scheme_protocols,
26252625
mut window_builder,
26262626
ipc_handler,
2627-
file_drop_handler,
26282627
label,
26292628
url,
26302629
menu_ids,
@@ -2663,17 +2662,11 @@ fn create_webview(
26632662
.with_url(&url)
26642663
.unwrap() // safe to unwrap because we validate the URL beforehand
26652664
.with_transparent(is_window_transparent);
2665+
if webview_attributes.file_drop_handler_enabled {
2666+
webview_builder = webview_builder.with_file_drop_handler(create_file_drop_handler(&context));
2667+
}
26662668
if let Some(handler) = ipc_handler {
26672669
webview_builder = webview_builder.with_ipc_handler(create_ipc_handler(
2668-
context.clone(),
2669-
label.clone(),
2670-
menu_ids.clone(),
2671-
js_event_listeners.clone(),
2672-
handler,
2673-
));
2674-
}
2675-
if let Some(handler) = file_drop_handler {
2676-
webview_builder = webview_builder.with_file_drop_handler(create_file_drop_handler(
26772670
context,
26782671
label.clone(),
26792672
menu_ids,
@@ -2763,26 +2756,25 @@ fn create_ipc_handler(
27632756
})
27642757
}
27652758

2766-
/// Create a wry file drop handler from a tauri file drop handler.
2759+
/// Create a wry file drop handler.
27672760
fn create_file_drop_handler(
2768-
context: Context,
2769-
label: String,
2770-
menu_ids: Arc<Mutex<HashMap<MenuHash, MenuId>>>,
2771-
js_event_listeners: Arc<Mutex<HashMap<JsEventListenerKey, HashSet<u64>>>>,
2772-
handler: FileDropHandler<Wry>,
2761+
context: &Context,
27732762
) -> Box<dyn Fn(&Window, WryFileDropEvent) -> bool + 'static> {
2763+
let window_event_listeners = context.window_event_listeners.clone();
27742764
Box::new(move |window, event| {
2775-
handler(
2776-
FileDropEventWrapper(event).into(),
2777-
DetachedWindow {
2778-
dispatcher: WryDispatcher {
2779-
window_id: window.id(),
2780-
context: context.clone(),
2781-
},
2782-
label: label.clone(),
2783-
menu_ids: menu_ids.clone(),
2784-
js_event_listeners: js_event_listeners.clone(),
2785-
},
2786-
)
2765+
let event: FileDropEvent = FileDropEventWrapper(event).into();
2766+
let window_event = WindowEvent::FileDrop(event);
2767+
let listeners = window_event_listeners.lock().unwrap();
2768+
if let Some(window_listeners) = listeners.get(&window.id()) {
2769+
let listeners_map = window_listeners.lock().unwrap();
2770+
let has_listener = !listeners_map.is_empty();
2771+
for listener in listeners_map.values() {
2772+
listener(&window_event);
2773+
}
2774+
// block the default OS action on file drop if we had a listener
2775+
has_listener
2776+
} else {
2777+
false
2778+
}
27872779
})
27882780
}

core/tauri-runtime/src/webview.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -184,21 +184,5 @@ pub trait WindowBuilder: WindowBuilderBase {
184184
fn get_menu(&self) -> Option<&Menu>;
185185
}
186186

187-
/// The file drop event payload.
188-
#[derive(Debug, Clone)]
189-
#[non_exhaustive]
190-
pub enum FileDropEvent {
191-
/// The file(s) have been dragged onto the window, but have not been dropped yet.
192-
Hovered(Vec<PathBuf>),
193-
/// The file(s) have been dropped onto the window.
194-
Dropped(Vec<PathBuf>),
195-
/// The file drop was aborted.
196-
Cancelled,
197-
}
198-
199187
/// IPC handler.
200188
pub type WebviewIpcHandler<R> = Box<dyn Fn(DetachedWindow<R>, String) + Send>;
201-
202-
/// File drop handler callback
203-
/// Return `true` in the callback to block the OS' default behavior of handling a file drop.
204-
pub type FileDropHandler<R> = Box<dyn Fn(FileDropEvent, DetachedWindow<R>) -> bool + Send>;

core/tauri-runtime/src/window.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use crate::{
88
http::{Request as HttpRequest, Response as HttpResponse},
99
menu::{Menu, MenuEntry, MenuHash, MenuId},
10-
webview::{FileDropHandler, WebviewAttributes, WebviewIpcHandler},
10+
webview::{WebviewAttributes, WebviewIpcHandler},
1111
Dispatch, Runtime, WindowBuilder,
1212
};
1313
use serde::Serialize;
@@ -16,6 +16,7 @@ use tauri_utils::config::WindowConfig;
1616
use std::{
1717
collections::{HashMap, HashSet},
1818
hash::{Hash, Hasher},
19+
path::PathBuf,
1920
sync::{mpsc::Sender, Arc, Mutex},
2021
};
2122

@@ -59,6 +60,20 @@ pub enum WindowEvent {
5960
/// The window inner size.
6061
new_inner_size: dpi::PhysicalSize<u32>,
6162
},
63+
/// An event associated with the file drop action.
64+
FileDrop(FileDropEvent),
65+
}
66+
67+
/// The file drop event payload.
68+
#[derive(Debug, Clone)]
69+
#[non_exhaustive]
70+
pub enum FileDropEvent {
71+
/// The file(s) have been dragged onto the window, but have not been dropped yet.
72+
Hovered(Vec<PathBuf>),
73+
/// The file(s) have been dropped onto the window.
74+
Dropped(Vec<PathBuf>),
75+
/// The file drop was aborted.
76+
Cancelled,
6277
}
6378

6479
/// A menu event.
@@ -96,9 +111,6 @@ pub struct PendingWindow<R: Runtime> {
96111
/// How to handle IPC calls on the webview window.
97112
pub ipc_handler: Option<WebviewIpcHandler<R>>,
98113

99-
/// How to handle a file dropping onto the webview window.
100-
pub file_drop_handler: Option<FileDropHandler<R>>,
101-
102114
/// The resolved URL to load on the webview.
103115
pub url: String,
104116

@@ -143,7 +155,6 @@ impl<R: Runtime> PendingWindow<R> {
143155
uri_scheme_protocols: Default::default(),
144156
label,
145157
ipc_handler: None,
146-
file_drop_handler: None,
147158
url: "tauri://localhost".to_string(),
148159
menu_ids: Arc::new(Mutex::new(menu_ids)),
149160
js_event_listeners: Default::default(),
@@ -172,7 +183,6 @@ impl<R: Runtime> PendingWindow<R> {
172183
uri_scheme_protocols: Default::default(),
173184
label,
174185
ipc_handler: None,
175-
file_drop_handler: None,
176186
url: "tauri://localhost".to_string(),
177187
menu_ids: Arc::new(Mutex::new(menu_ids)),
178188
js_event_listeners: Default::default(),

core/tauri/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ pub use {
213213
webview::{WebviewAttributes, WindowBuilder},
214214
window::{
215215
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size},
216-
WindowEvent,
216+
FileDropEvent, WindowEvent,
217217
},
218218
ClipboardManager, GlobalShortcutManager, RunIteration, Runtime, TrayIcon, UserAttentionType,
219219
},

core/tauri/src/manager.rs

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ use crate::{
3939
MimeType, Request as HttpRequest, Response as HttpResponse,
4040
ResponseBuilder as HttpResponseBuilder,
4141
},
42-
webview::{FileDropEvent, FileDropHandler, WebviewIpcHandler, WindowBuilder},
43-
window::{dpi::PhysicalSize, DetachedWindow, PendingWindow, WindowEvent},
42+
webview::{WebviewIpcHandler, WindowBuilder},
43+
window::{dpi::PhysicalSize, DetachedWindow, FileDropEvent, PendingWindow, WindowEvent},
4444
Runtime,
4545
},
4646
utils::{
@@ -838,30 +838,6 @@ impl<R: Runtime> WindowManager<R> {
838838
})
839839
}
840840

841-
fn prepare_file_drop(&self, app_handle: AppHandle<R>) -> FileDropHandler<R> {
842-
let manager = self.clone();
843-
Box::new(move |event, window| {
844-
let window = Window::new(manager.clone(), window, app_handle.clone());
845-
let _ = match event {
846-
FileDropEvent::Hovered(paths) => window.emit_and_trigger("tauri://file-drop-hover", paths),
847-
FileDropEvent::Dropped(paths) => {
848-
let scopes = window.state::<Scopes>();
849-
for path in &paths {
850-
if path.is_file() {
851-
let _ = scopes.allow_file(path);
852-
} else {
853-
let _ = scopes.allow_directory(path, false);
854-
}
855-
}
856-
window.emit_and_trigger("tauri://file-drop", paths)
857-
}
858-
FileDropEvent::Cancelled => window.emit_and_trigger("tauri://file-drop-cancelled", ()),
859-
_ => unimplemented!(),
860-
};
861-
true
862-
})
863-
}
864-
865841
fn initialization_script(
866842
&self,
867843
ipc_script: &str,
@@ -1082,11 +1058,7 @@ impl<R: Runtime> WindowManager<R> {
10821058
app_handle.clone(),
10831059
web_resource_request_handler,
10841060
)?;
1085-
pending.ipc_handler = Some(self.prepare_ipc_handler(app_handle.clone()));
1086-
}
1087-
1088-
if pending.webview_attributes.file_drop_handler_enabled {
1089-
pending.file_drop_handler = Some(self.prepare_file_drop(app_handle));
1061+
pending.ipc_handler = Some(self.prepare_ipc_handler(app_handle));
10901062
}
10911063

10921064
// in `Windows`, we need to force a data_directory
@@ -1291,6 +1263,22 @@ fn on_window_event<R: Runtime>(
12911263
size: *new_inner_size,
12921264
},
12931265
)?,
1266+
WindowEvent::FileDrop(event) => match event {
1267+
FileDropEvent::Hovered(paths) => window.emit_and_trigger("tauri://file-drop-hover", paths)?,
1268+
FileDropEvent::Dropped(paths) => {
1269+
let scopes = window.state::<Scopes>();
1270+
for path in paths {
1271+
if path.is_file() {
1272+
let _ = scopes.allow_file(path);
1273+
} else {
1274+
let _ = scopes.allow_directory(path, false);
1275+
}
1276+
}
1277+
window.emit_and_trigger("tauri://file-drop", paths)?
1278+
}
1279+
FileDropEvent::Cancelled => window.emit_and_trigger("tauri://file-drop-cancelled", ())?,
1280+
_ => unimplemented!(),
1281+
},
12941282
_ => unimplemented!(),
12951283
}
12961284
Ok(())

0 commit comments

Comments
 (0)