Skip to content

Commit

Permalink
fix(core): emit tauri://close-requested to JS, closes #2996 (#3041)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog committed Dec 9, 2021
1 parent 1458ab3 commit 74dff53
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .changes/fix-close-requested-js-event.md
@@ -0,0 +1,5 @@
---
"tauri": patch
---

Prevent window closing if `tauri://close-requested` is listened on the JS layer. Users must call `appWindow.close()` manually when listening to that event.
5 changes: 5 additions & 0 deletions .changes/refactor-window-event-close-requested.md
@@ -0,0 +1,5 @@
---
"tauri": patch
---

**Breaking change:** The `WindowEvent::CloseRequested` variant now includes `label` and `signal_tx` fields to allow preventing closing the window.
30 changes: 28 additions & 2 deletions core/tauri-runtime-wry/src/lib.rs
Expand Up @@ -88,7 +88,7 @@ pub use wry::application::platform::macos::{
use std::{
collections::{
hash_map::Entry::{Occupied, Vacant},
HashMap,
HashMap, HashSet,
},
fmt,
fs::read,
Expand Down Expand Up @@ -555,7 +555,6 @@ impl<'a> From<&WryWindowEvent<'a>> for WindowEventWrapper {
WryWindowEvent::Moved(position) => {
WindowEvent::Moved(PhysicalPositionWrapper(*position).into())
}
WryWindowEvent::CloseRequested => WindowEvent::CloseRequested,
WryWindowEvent::Destroyed => WindowEvent::Destroyed,
WryWindowEvent::ScaleFactorChanged {
scale_factor,
Expand Down Expand Up @@ -1213,6 +1212,7 @@ impl Dispatch for WryDispatcher {
let (tx, rx) = channel();
let label = pending.label.clone();
let menu_ids = pending.menu_ids.clone();
let js_event_listeners = pending.js_event_listeners.clone();
let context = self.context.clone();

send_user_message(
Expand All @@ -1234,6 +1234,7 @@ impl Dispatch for WryDispatcher {
label,
dispatcher,
menu_ids,
js_event_listeners,
})
}

Expand Down Expand Up @@ -1521,6 +1522,7 @@ impl RuntimeHandle for WryHandle {
let (tx, rx) = channel();
let label = pending.label.clone();
let menu_ids = pending.menu_ids.clone();
let js_event_listeners = pending.js_event_listeners.clone();
let context = self.context.clone();
send_user_message(
&self.context,
Expand All @@ -1541,6 +1543,7 @@ impl RuntimeHandle for WryHandle {
label,
dispatcher,
menu_ids,
js_event_listeners,
})
}

Expand Down Expand Up @@ -1649,6 +1652,7 @@ impl Runtime for Wry {
fn create_window(&self, pending: PendingWindow<Self>) -> Result<DetachedWindow<Self>> {
let label = pending.label.clone();
let menu_ids = pending.menu_ids.clone();
let js_event_listeners = pending.js_event_listeners.clone();
let proxy = self.event_loop.create_proxy();
let webview = create_webview(
&self.event_loop,
Expand Down Expand Up @@ -1738,6 +1742,7 @@ impl Runtime for Wry {
label,
dispatcher,
menu_ids,
js_event_listeners,
})
}

Expand Down Expand Up @@ -2356,6 +2361,20 @@ fn handle_event_loop(
if let Some(w) = windows_guard.get(&window_id) {
let label = w.label.clone();
drop(windows_guard);
for handler in window_event_listeners
.lock()
.unwrap()
.get(&window_id)
.unwrap()
.lock()
.unwrap()
.values()
{
handler(&WindowEvent::CloseRequested {
label: label.clone(),
signal_tx: tx.clone(),
});
}
callback(RunEvent::CloseRequested {
label,
signal_tx: tx,
Expand Down Expand Up @@ -2534,6 +2553,7 @@ fn create_webview(
label,
url,
menu_ids,
js_event_listeners,
..
} = pending;

Expand Down Expand Up @@ -2573,6 +2593,7 @@ fn create_webview(
context.clone(),
label.clone(),
menu_ids.clone(),
js_event_listeners.clone(),
handler,
));
}
Expand All @@ -2581,6 +2602,7 @@ fn create_webview(
context,
label.clone(),
menu_ids,
js_event_listeners,
handler,
));
}
Expand Down Expand Up @@ -2637,6 +2659,7 @@ fn create_rpc_handler(
context: Context,
label: String,
menu_ids: Arc<Mutex<HashMap<MenuHash, MenuId>>>,
js_event_listeners: Arc<Mutex<HashMap<String, HashSet<u64>>>>,
handler: WebviewRpcHandler<Wry>,
) -> Box<dyn Fn(&Window, WryRpcRequest) -> Option<RpcResponse> + 'static> {
Box::new(move |window, request| {
Expand All @@ -2648,6 +2671,7 @@ fn create_rpc_handler(
},
label: label.clone(),
menu_ids: menu_ids.clone(),
js_event_listeners: js_event_listeners.clone(),
},
RpcRequestWrapper(request).into(),
);
Expand All @@ -2660,6 +2684,7 @@ fn create_file_drop_handler(
context: Context,
label: String,
menu_ids: Arc<Mutex<HashMap<MenuHash, MenuId>>>,
js_event_listeners: Arc<Mutex<HashMap<String, HashSet<u64>>>>,
handler: FileDropHandler<Wry>,
) -> Box<dyn Fn(&Window, WryFileDropEvent) -> bool + 'static> {
Box::new(move |window, event| {
Expand All @@ -2672,6 +2697,7 @@ fn create_file_drop_handler(
},
label: label.clone(),
menu_ids: menu_ids.clone(),
js_event_listeners: js_event_listeners.clone(),
},
)
})
Expand Down
20 changes: 17 additions & 3 deletions core/tauri-runtime/src/window.rs
Expand Up @@ -14,9 +14,9 @@ use serde::Serialize;
use tauri_utils::config::WindowConfig;

use std::{
collections::HashMap,
collections::{HashMap, HashSet},
hash::{Hash, Hasher},
sync::{Arc, Mutex},
sync::{mpsc::Sender, Arc, Mutex},
};

type UriSchemeProtocol =
Expand All @@ -34,7 +34,12 @@ pub enum WindowEvent {
/// The position of the window has changed. Contains the window's new position.
Moved(dpi::PhysicalPosition<i32>),
/// The window has been requested to close.
CloseRequested,
CloseRequested {
/// The window label.
label: String,
/// A signal sender. If a `true` value is emitted, the window won't be closed.
signal_tx: Sender<bool>,
},
/// The window has been destroyed.
Destroyed,
/// The window gained or lost focus.
Expand Down Expand Up @@ -99,6 +104,9 @@ pub struct PendingWindow<R: Runtime> {

/// Maps runtime id to a string menu id.
pub menu_ids: Arc<Mutex<HashMap<MenuHash, MenuId>>>,

/// A HashMap mapping JS event names with listener ids associated.
pub js_event_listeners: Arc<Mutex<HashMap<String, HashSet<u64>>>>,
}

impl<R: Runtime> PendingWindow<R> {
Expand All @@ -121,6 +129,7 @@ impl<R: Runtime> PendingWindow<R> {
file_drop_handler: None,
url: "tauri://localhost".to_string(),
menu_ids: Arc::new(Mutex::new(menu_ids)),
js_event_listeners: Default::default(),
}
}

Expand All @@ -144,6 +153,7 @@ impl<R: Runtime> PendingWindow<R> {
file_drop_handler: None,
url: "tauri://localhost".to_string(),
menu_ids: Arc::new(Mutex::new(menu_ids)),
js_event_listeners: Default::default(),
}
}

Expand Down Expand Up @@ -181,6 +191,9 @@ pub struct DetachedWindow<R: Runtime> {

/// Maps runtime id to a string menu id.
pub menu_ids: Arc<Mutex<HashMap<MenuHash, MenuId>>>,

/// A HashMap mapping JS event names with listener ids associated.
pub js_event_listeners: Arc<Mutex<HashMap<String, HashSet<u64>>>>,
}

impl<R: Runtime> Clone for DetachedWindow<R> {
Expand All @@ -189,6 +202,7 @@ impl<R: Runtime> Clone for DetachedWindow<R> {
label: self.label.clone(),
dispatcher: self.dispatcher.clone(),
menu_ids: self.menu_ids.clone(),
js_event_listeners: self.js_event_listeners.clone(),
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion core/tauri/src/endpoints/event.rs
Expand Up @@ -29,11 +29,13 @@ impl Cmd {
match self {
Self::Listen { event, handler } => {
let event_id = rand::random();
window.eval(&listen_js(&window, event, event_id, handler))?;
window.eval(&listen_js(&window, event.clone(), event_id, handler))?;
window.register_js_listener(event, event_id);
Ok(event_id.into())
}
Self::Unlisten { event_id } => {
window.eval(&unlisten_js(&window, event_id))?;
window.unregister_js_listener(event_id);
Ok(().into())
}
Self::Emit {
Expand Down
8 changes: 7 additions & 1 deletion core/tauri/src/manager.rs
Expand Up @@ -815,7 +815,13 @@ fn on_window_event<R: Runtime>(
match event {
WindowEvent::Resized(size) => window.emit_and_trigger(WINDOW_RESIZED_EVENT, size)?,
WindowEvent::Moved(position) => window.emit_and_trigger(WINDOW_MOVED_EVENT, position)?,
WindowEvent::CloseRequested => {
WindowEvent::CloseRequested {
label: _,
signal_tx,
} => {
if window.has_js_listener(WINDOW_CLOSE_REQUESTED_EVENT) {
signal_tx.send(true).unwrap();
}
window.emit_and_trigger(WINDOW_CLOSE_REQUESTED_EVENT, ())?;
}
WindowEvent::Destroyed => {
Expand Down
38 changes: 38 additions & 0 deletions core/tauri/src/window.rs
Expand Up @@ -352,6 +352,44 @@ impl<R: Runtime> Window<R> {
})
}

pub(crate) fn register_js_listener(&self, event: String, id: u64) {
self
.window
.js_event_listeners
.lock()
.unwrap()
.entry(event)
.or_insert_with(Default::default)
.insert(id);
}

pub(crate) fn unregister_js_listener(&self, id: u64) {
let mut empty = None;
let mut js_listeners = self.window.js_event_listeners.lock().unwrap();
for (event, ids) in js_listeners.iter_mut() {
if ids.contains(&id) {
ids.remove(&id);
if ids.is_empty() {
empty.replace(event.clone());
}
break;
}
}

if let Some(event) = empty {
js_listeners.remove(&event);
}
}

pub(crate) fn has_js_listener(&self, event: &str) -> bool {
self
.window
.js_event_listeners
.lock()
.unwrap()
.contains_key(event)
}

// Getters

/// Gets a handle to the window menu.
Expand Down

0 comments on commit 74dff53

Please sign in to comment.