Skip to content

Commit 08c161c

Browse files
authored
fix(core): remove window from HashMap on close (#2024)
1 parent 8a7921e commit 08c161c

5 files changed

Lines changed: 76 additions & 31 deletions

File tree

.changes/remove-window-on-exit.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch
3+
---
4+
5+
Remove window object from the `Manager` internal `HashMap` on close. This fixes the behavior of using `[App|AppHandle|Window]#get_window` after the window is closed (now correctly returns `None`).

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

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use tauri_runtime::{
1313
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
1414
DetachedWindow, PendingWindow, WindowEvent,
1515
},
16-
Dispatch, Error, Icon, Params, Result, RunIteration, Runtime, RuntimeHandle,
16+
Dispatch, Error, Icon, Params, Result, RunEvent, RunIteration, Runtime, RuntimeHandle,
1717
};
1818

1919
#[cfg(feature = "menu")]
@@ -951,6 +951,7 @@ struct TrayContext {
951951
}
952952

953953
struct WebviewWrapper {
954+
label: String,
954955
inner: WebView,
955956
#[cfg(feature = "menu")]
956957
menu_items: HashMap<u32, WryCustomMenuItem>,
@@ -1130,7 +1131,7 @@ impl Runtime for Wry {
11301131
}
11311132

11321133
#[cfg(any(target_os = "windows", target_os = "macos"))]
1133-
fn run_iteration(&mut self) -> RunIteration {
1134+
fn run_iteration<F: Fn(RunEvent) + 'static>(&mut self, callback: F) -> RunIteration {
11341135
use wry::application::platform::run_return::EventLoopExtRunReturn;
11351136
let webviews = self.webviews.clone();
11361137
let window_event_listeners = self.window_event_listeners.clone();
@@ -1153,7 +1154,7 @@ impl Runtime for Wry {
11531154
event_loop,
11541155
control_flow,
11551156
EventLoopIterationContext {
1156-
callback: None,
1157+
callback: &callback,
11571158
webviews: webviews.lock().expect("poisoned webview collection"),
11581159
window_event_listeners: window_event_listeners.clone(),
11591160
#[cfg(feature = "menu")]
@@ -1168,7 +1169,7 @@ impl Runtime for Wry {
11681169
iteration
11691170
}
11701171

1171-
fn run<F: Fn() + 'static>(self, callback: F) {
1172+
fn run<F: Fn(RunEvent) + 'static>(self, callback: F) {
11721173
self.is_event_loop_running.store(true, Ordering::Relaxed);
11731174
let webviews = self.webviews.clone();
11741175
let window_event_listeners = self.window_event_listeners.clone();
@@ -1183,7 +1184,7 @@ impl Runtime for Wry {
11831184
event_loop,
11841185
control_flow,
11851186
EventLoopIterationContext {
1186-
callback: Some(&callback),
1187+
callback: &callback,
11871188
webviews: webviews.lock().expect("poisoned webview collection"),
11881189
window_event_listeners: window_event_listeners.clone(),
11891190
#[cfg(feature = "menu")]
@@ -1197,7 +1198,7 @@ impl Runtime for Wry {
11971198
}
11981199

11991200
struct EventLoopIterationContext<'a> {
1200-
callback: Option<&'a (dyn Fn() + 'static)>,
1201+
callback: &'a (dyn Fn(RunEvent) + 'static),
12011202
webviews: MutexGuard<'a, HashMap<WindowId, WebviewWrapper>>,
12021203
window_event_listeners: WindowEventListeners,
12031204
#[cfg(feature = "menu")]
@@ -1273,13 +1274,7 @@ fn handle_event_loop(
12731274
}
12741275
match event {
12751276
WryWindowEvent::CloseRequested => {
1276-
webviews.remove(&window_id);
1277-
if webviews.is_empty() {
1278-
*control_flow = ControlFlow::Exit;
1279-
if let Some(callback) = callback {
1280-
callback();
1281-
}
1282-
}
1277+
on_window_close(callback, window_id, &mut webviews, control_flow);
12831278
}
12841279
WryWindowEvent::Resized(_) => {
12851280
if let Err(e) = webviews[&window_id].inner.resize() {
@@ -1365,10 +1360,7 @@ fn handle_event_loop(
13651360
WindowMessage::Show => window.set_visible(true),
13661361
WindowMessage::Hide => window.set_visible(false),
13671362
WindowMessage::Close => {
1368-
webviews.remove(&id);
1369-
if webviews.is_empty() {
1370-
*control_flow = ControlFlow::Exit;
1371-
}
1363+
on_window_close(callback, id, &mut webviews, control_flow);
13721364
}
13731365
WindowMessage::SetDecorations(decorations) => window.set_decorations(decorations),
13741366
WindowMessage::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top),
@@ -1489,6 +1481,21 @@ fn handle_event_loop(
14891481
}
14901482
}
14911483

1484+
fn on_window_close<'a>(
1485+
callback: &'a (dyn Fn(RunEvent) + 'static),
1486+
window_id: WindowId,
1487+
webviews: &mut MutexGuard<'a, HashMap<WindowId, WebviewWrapper>>,
1488+
control_flow: &mut ControlFlow,
1489+
) {
1490+
if let Some(webview) = webviews.remove(&window_id) {
1491+
callback(RunEvent::WindowClose(webview.label));
1492+
}
1493+
if webviews.is_empty() {
1494+
*control_flow = ControlFlow::Exit;
1495+
callback(RunEvent::Exit);
1496+
}
1497+
}
1498+
14921499
fn center_window(window: &Window) -> Result<()> {
14931500
if let Some(monitor) = window.current_monitor() {
14941501
let screen_size = monitor.size();
@@ -1534,8 +1541,11 @@ fn create_webview<P: Params<Runtime = Wry>>(
15341541
webview_builder.with_rpc_handler(create_rpc_handler(context.clone(), label.clone(), handler));
15351542
}
15361543
if let Some(handler) = file_drop_handler {
1537-
webview_builder =
1538-
webview_builder.with_file_drop_handler(create_file_drop_handler(context, label, handler));
1544+
webview_builder = webview_builder.with_file_drop_handler(create_file_drop_handler(
1545+
context,
1546+
label.clone(),
1547+
handler,
1548+
));
15391549
}
15401550
for (scheme, protocol) in webview_attributes.uri_scheme_protocols {
15411551
webview_builder = webview_builder.with_custom_protocol(scheme, move |_window, url| {
@@ -1558,6 +1568,7 @@ fn create_webview<P: Params<Runtime = Wry>>(
15581568
.map_err(|e| Error::CreateWebview(Box::new(e)))?;
15591569

15601570
Ok(WebviewWrapper {
1571+
label: format!("{}", label),
15611572
inner: webview,
15621573
#[cfg(feature = "menu")]
15631574
menu_items,

core/tauri-runtime/src/lib.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,14 @@ impl Icon {
169169
}
170170
}
171171

172+
/// Event triggered on the event loop run.
173+
pub enum RunEvent {
174+
/// Event loop is exiting.
175+
Exit,
176+
/// Window closed.
177+
WindowClose(String),
178+
}
179+
172180
/// A system tray event.
173181
pub enum SystemTrayEvent {
174182
MenuItemClick(u32),
@@ -240,10 +248,10 @@ pub trait Runtime: Sized + 'static {
240248

241249
/// Runs the one step of the webview runtime event loop and returns control flow to the caller.
242250
#[cfg(any(target_os = "windows", target_os = "macos"))]
243-
fn run_iteration(&mut self) -> RunIteration;
251+
fn run_iteration<F: Fn(RunEvent) + 'static>(&mut self, callback: F) -> RunIteration;
244252

245253
/// Run the webview runtime.
246-
fn run<F: Fn() + 'static>(self, callback: F);
254+
fn run<F: Fn(RunEvent) + 'static>(self, callback: F);
247255
}
248256

249257
/// Webview dispatcher. A thread-safe handle to the webview API.

core/tauri/src/app.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::{
1616
tag::Tag,
1717
webview::{CustomProtocol, WebviewAttributes, WindowBuilder},
1818
window::{PendingWindow, WindowEvent},
19-
Dispatch, MenuId, Params, Runtime,
19+
Dispatch, MenuId, Params, RunEvent, Runtime,
2020
},
2121
sealed::{ManagerBase, RuntimeOrDispatch},
2222
Context, Invoke, Manager, StateManager, Window,
@@ -260,7 +260,12 @@ impl<P: Params> App<P> {
260260
/// }
261261
#[cfg(any(target_os = "windows", target_os = "macos"))]
262262
pub fn run_iteration(&mut self) -> crate::runtime::RunIteration {
263-
self.runtime.as_mut().unwrap().run_iteration()
263+
let manager = self.manager.clone();
264+
self
265+
.runtime
266+
.as_mut()
267+
.unwrap()
268+
.run_iteration(move |event| on_event_loop_event(event, &manager))
264269
}
265270
}
266271

@@ -807,20 +812,30 @@ where
807812
let mut app = self.build(context)?;
808813
#[cfg(all(windows, feature = "system-tray"))]
809814
let app_handle = app.handle();
810-
app.runtime.take().unwrap().run(move || {
811-
#[cfg(shell_execute)]
812-
{
813-
crate::api::process::kill_children();
814-
}
815-
#[cfg(all(windows, feature = "system-tray"))]
816-
{
817-
let _ = app_handle.remove_system_tray();
815+
let manager = app.manager.clone();
816+
app.runtime.take().unwrap().run(move |event| match event {
817+
RunEvent::Exit => {
818+
#[cfg(shell_execute)]
819+
{
820+
crate::api::process::kill_children();
821+
}
822+
#[cfg(all(windows, feature = "system-tray"))]
823+
{
824+
let _ = app_handle.remove_system_tray();
825+
}
818826
}
827+
_ => on_event_loop_event(event, &manager),
819828
});
820829
Ok(())
821830
}
822831
}
823832

833+
fn on_event_loop_event<P: Params>(event: RunEvent, manager: &WindowManager<P>) {
834+
if let RunEvent::WindowClose(label) = event {
835+
manager.on_window_close(label);
836+
}
837+
}
838+
824839
/// Make `Wry` the default `Runtime` for `Builder`
825840
#[cfg(feature = "wry")]
826841
impl<A: Assets> Default for Builder<String, String, String, String, A, crate::Wry> {

core/tauri/src/manager.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,12 @@ impl<P: Params> WindowManager<P> {
685685
window
686686
}
687687

688+
pub(crate) fn on_window_close(&self, label: String) {
689+
self
690+
.windows_lock()
691+
.remove(&label.parse().unwrap_or_else(|_| panic!("bad label")));
692+
}
693+
688694
pub fn emit_filter<E: ?Sized, S, F>(&self, event: &E, payload: S, filter: F) -> crate::Result<()>
689695
where
690696
P::Event: Borrow<E>,

0 commit comments

Comments
 (0)