diff --git a/.changes/prevent-crash.md b/.changes/prevent-crash.md new file mode 100644 index 00000000000..2230da3ec23 --- /dev/null +++ b/.changes/prevent-crash.md @@ -0,0 +1,5 @@ +--- +"tauri-runtime-wry": patch:bug +--- + +Use `Arc` instead of `Rc` to prevent crashes on macOS. diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index e944917d459..acbf1a10095 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -268,13 +268,25 @@ pub enum ActiveTracingSpan { }, } +#[derive(Debug)] +pub struct WindowsStore(RefCell>); + +// SAFETY: we ensure this type is only used on the main thread. +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Send for WindowsStore {} + +// SAFETY: we ensure this type is only used on the main thread. +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Sync for WindowsStore {} + #[derive(Debug, Clone)] pub struct DispatcherMainThreadContext { pub window_target: EventLoopWindowTarget>, pub web_context: WebContextStore, #[cfg(all(desktop, feature = "global-shortcut"))] pub global_shortcut_manager: Rc>, - pub windows: Rc>>, + // changing this to an Rc will cause frequent app crashes. + pub windows: Arc, #[cfg(all(desktop, feature = "system-tray"))] system_tray_manager: SystemTrayManager, #[cfg(feature = "tracing")] @@ -1973,7 +1985,7 @@ impl Wry { #[cfg(all(desktop, feature = "global-shortcut"))] let global_shortcut_manager = Rc::new(Mutex::new(WryShortcutManager::new(&event_loop))); - let windows = Rc::new(RefCell::new(HashMap::default())); + let windows = Arc::new(WindowsStore(RefCell::new(HashMap::default()))); let webview_id_map = WebviewIdStore::default(); #[cfg(all(desktop, feature = "system-tray"))] @@ -2104,6 +2116,7 @@ impl Runtime for Wry { .context .main_thread .windows + .0 .borrow_mut() .insert(window_id, webview); @@ -2337,7 +2350,7 @@ impl Runtime for Wry { pub struct EventLoopIterationContext<'a, T: UserEvent> { pub callback: &'a mut (dyn FnMut(RunEvent) + 'static), pub webview_id_map: WebviewIdStore, - pub windows: Rc>>, + pub windows: Arc, #[cfg(all(desktop, feature = "global-shortcut"))] pub global_shortcut_manager: Rc>, #[cfg(all(desktop, feature = "global-shortcut"))] @@ -2349,7 +2362,7 @@ pub struct EventLoopIterationContext<'a, T: UserEvent> { } struct UserMessageContext { - windows: Rc>>, + windows: Arc, webview_id_map: WebviewIdStore, #[cfg(all(desktop, feature = "global-shortcut"))] global_shortcut_manager: Rc>, @@ -2384,7 +2397,12 @@ fn handle_user_message( }, Message::Window(id, window_message) => { if let WindowMessage::UpdateMenuItem(item_id, update) = window_message { - if let Some(menu_items) = windows.borrow_mut().get_mut(&id).map(|w| &mut w.menu_items) { + if let Some(menu_items) = windows + .0 + .borrow_mut() + .get_mut(&id) + .map(|w| &mut w.menu_items) + { if let Some(menu_items) = menu_items.as_mut() { let item = menu_items.get_mut(&item_id).expect("menu item not found"); match update { @@ -2399,7 +2417,7 @@ fn handle_user_message( } } } else { - let w = windows.borrow().get(&id).map(|w| { + let w = windows.0.borrow().get(&id).map(|w| { ( w.inner.clone(), w.window_event_listeners.clone(), @@ -2622,7 +2640,7 @@ fn handle_user_message( WebviewMessage::EvaluateScript(script, tx, span) => { let _span = span.entered(); if let Some(WindowHandle::Webview { inner: webview, .. }) = - windows.borrow().get(&id).and_then(|w| w.inner.as_ref()) + windows.0.borrow().get(&id).and_then(|w| w.inner.as_ref()) { if let Err(e) = webview.evaluate_script(&script) { debug_eprintln!("{}", e); @@ -2633,7 +2651,7 @@ fn handle_user_message( #[cfg(not(feature = "tracing"))] WebviewMessage::EvaluateScript(script) => { if let Some(WindowHandle::Webview { inner: webview, .. }) = - windows.borrow().get(&id).and_then(|w| w.inner.as_ref()) + windows.0.borrow().get(&id).and_then(|w| w.inner.as_ref()) { if let Err(e) = webview.evaluate_script(&script) { debug_eprintln!("{}", e); @@ -2642,7 +2660,7 @@ fn handle_user_message( } WebviewMessage::Print => { if let Some(WindowHandle::Webview { inner: webview, .. }) = - windows.borrow().get(&id).and_then(|w| w.inner.as_ref()) + windows.0.borrow().get(&id).and_then(|w| w.inner.as_ref()) { let _ = webview.print(); } @@ -2651,7 +2669,7 @@ fn handle_user_message( }, Message::CreateWebview(window_id, handler) => match handler(event_loop, web_context) { Ok(webview) => { - windows.borrow_mut().insert(window_id, webview); + windows.0.borrow_mut().insert(window_id, webview); } Err(e) => { debug_eprintln!("{}", e); @@ -2664,7 +2682,7 @@ fn handle_user_message( let w = Arc::new(window); - windows.borrow_mut().insert( + windows.0.borrow_mut().insert( window_id, WindowWrapper { label, @@ -2773,7 +2791,7 @@ fn handle_user_message( } let it = RunIteration { - window_count: windows.borrow().len(), + window_count: windows.0.borrow().len(), }; it } @@ -2861,6 +2879,7 @@ fn handle_event_loop( *webview_id_map.0.lock().unwrap().values().next().unwrap() }; windows + .0 .borrow() .get(&window_id) .unwrap() @@ -2946,7 +2965,7 @@ fn handle_event_loop( } Event::UserEvent(Message::Webview(id, WebviewMessage::WebviewEvent(event))) => { if let Some(event) = WindowEventWrapper::from(&event).0 { - let windows = windows.borrow(); + let windows = windows.0.borrow(); let window = windows.get(&id); if let Some(window) = window { callback(RunEvent::WindowEvent { @@ -2967,7 +2986,7 @@ fn handle_event_loop( } => { if let Some(window_id) = webview_id_map.get(&window_id) { { - let windows_ref = windows.borrow(); + let windows_ref = windows.0.borrow(); if let Some(window) = windows_ref.get(&window_id) { if let Some(event) = WindowEventWrapper::parse(&window.inner, &event).0 { let label = window.label.clone(); @@ -2991,7 +3010,7 @@ fn handle_event_loop( match event { #[cfg(windows)] WryWindowEvent::ThemeChanged(theme) => { - if let Some(window) = windows.borrow().get(&window_id) { + if let Some(window) = windows.0.borrow().get(&window_id) { if let Some(WindowHandle::Webview { inner, .. }) = &window.inner { let theme = match theme { WryTheme::Dark => wry::webview::Theme::Dark, @@ -3006,9 +3025,9 @@ fn handle_event_loop( on_close_requested(callback, window_id, windows.clone()); } WryWindowEvent::Destroyed => { - let removed = windows.borrow_mut().remove(&window_id).is_some(); + let removed = windows.0.borrow_mut().remove(&window_id).is_some(); if removed { - let is_empty = windows.borrow().is_empty(); + let is_empty = windows.0.borrow().is_empty(); if is_empty { let (tx, rx) = channel(); callback(RunEvent::ExitRequested { tx }); @@ -3051,7 +3070,7 @@ fn handle_event_loop( } let it = RunIteration { - window_count: windows.borrow().len(), + window_count: windows.0.borrow().len(), }; it } @@ -3059,10 +3078,10 @@ fn handle_event_loop( fn on_close_requested<'a, T: UserEvent>( callback: &'a mut (dyn FnMut(RunEvent) + 'static), window_id: WebviewId, - windows: Rc>>, + windows: Arc, ) { let (tx, rx) = channel(); - let windows_ref = windows.borrow(); + let windows_ref = windows.0.borrow(); if let Some(w) = windows_ref.get(&window_id) { let label = w.label.clone(); let window_event_listeners = w.window_event_listeners.clone(); @@ -3087,8 +3106,8 @@ fn on_close_requested<'a, T: UserEvent>( } } -fn on_window_close(window_id: WebviewId, windows: Rc>>) { - if let Some(window_wrapper) = windows.borrow_mut().get_mut(&window_id) { +fn on_window_close(window_id: WebviewId, windows: Arc) { + if let Some(window_wrapper) = windows.0.borrow_mut().get_mut(&window_id) { window_wrapper.inner = None; } }