1
1
mirror of https://github.com/tauri-apps/tauri.git synced 2025-01-08 04:06:53 +03:00

fix(core): Replace Rc with Arc to prevent crashes when sending events ()

* fix(core): Prevent crash when sending events.

* add change file

* use dedicated type for windows refcell map

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
This commit is contained in:
Fabian-Lars 2023-12-20 16:13:00 +01:00 committed by GitHub
parent 0a2175eabb
commit b2f83f03a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 22 deletions
.changes
core/tauri-runtime-wry/src

View File

@ -0,0 +1,5 @@
---
"tauri-runtime-wry": patch:bug
---
Use `Arc` instead of `Rc` to prevent crashes on macOS.

View File

@ -268,13 +268,25 @@ pub enum ActiveTracingSpan {
}, },
} }
#[derive(Debug)]
pub struct WindowsStore(RefCell<HashMap<WebviewId, WindowWrapper>>);
// 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)] #[derive(Debug, Clone)]
pub struct DispatcherMainThreadContext<T: UserEvent> { pub struct DispatcherMainThreadContext<T: UserEvent> {
pub window_target: EventLoopWindowTarget<Message<T>>, pub window_target: EventLoopWindowTarget<Message<T>>,
pub web_context: WebContextStore, pub web_context: WebContextStore,
#[cfg(all(desktop, feature = "global-shortcut"))] #[cfg(all(desktop, feature = "global-shortcut"))]
pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>, pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
pub windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>, // changing this to an Rc will cause frequent app crashes.
pub windows: Arc<WindowsStore>,
#[cfg(all(desktop, feature = "system-tray"))] #[cfg(all(desktop, feature = "system-tray"))]
system_tray_manager: SystemTrayManager, system_tray_manager: SystemTrayManager,
#[cfg(feature = "tracing")] #[cfg(feature = "tracing")]
@ -1973,7 +1985,7 @@ impl<T: UserEvent> Wry<T> {
#[cfg(all(desktop, feature = "global-shortcut"))] #[cfg(all(desktop, feature = "global-shortcut"))]
let global_shortcut_manager = Rc::new(Mutex::new(WryShortcutManager::new(&event_loop))); 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(); let webview_id_map = WebviewIdStore::default();
#[cfg(all(desktop, feature = "system-tray"))] #[cfg(all(desktop, feature = "system-tray"))]
@ -2104,6 +2116,7 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
.context .context
.main_thread .main_thread
.windows .windows
.0
.borrow_mut() .borrow_mut()
.insert(window_id, webview); .insert(window_id, webview);
@ -2337,7 +2350,7 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
pub struct EventLoopIterationContext<'a, T: UserEvent> { pub struct EventLoopIterationContext<'a, T: UserEvent> {
pub callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static), pub callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static),
pub webview_id_map: WebviewIdStore, pub webview_id_map: WebviewIdStore,
pub windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>, pub windows: Arc<WindowsStore>,
#[cfg(all(desktop, feature = "global-shortcut"))] #[cfg(all(desktop, feature = "global-shortcut"))]
pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>, pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
#[cfg(all(desktop, feature = "global-shortcut"))] #[cfg(all(desktop, feature = "global-shortcut"))]
@ -2349,7 +2362,7 @@ pub struct EventLoopIterationContext<'a, T: UserEvent> {
} }
struct UserMessageContext { struct UserMessageContext {
windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>, windows: Arc<WindowsStore>,
webview_id_map: WebviewIdStore, webview_id_map: WebviewIdStore,
#[cfg(all(desktop, feature = "global-shortcut"))] #[cfg(all(desktop, feature = "global-shortcut"))]
global_shortcut_manager: Rc<Mutex<WryShortcutManager>>, global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
@ -2384,7 +2397,12 @@ fn handle_user_message<T: UserEvent>(
}, },
Message::Window(id, window_message) => { Message::Window(id, window_message) => {
if let WindowMessage::UpdateMenuItem(item_id, update) = 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() { if let Some(menu_items) = menu_items.as_mut() {
let item = menu_items.get_mut(&item_id).expect("menu item not found"); let item = menu_items.get_mut(&item_id).expect("menu item not found");
match update { match update {
@ -2399,7 +2417,7 @@ fn handle_user_message<T: UserEvent>(
} }
} }
} else { } else {
let w = windows.borrow().get(&id).map(|w| { let w = windows.0.borrow().get(&id).map(|w| {
( (
w.inner.clone(), w.inner.clone(),
w.window_event_listeners.clone(), w.window_event_listeners.clone(),
@ -2622,7 +2640,7 @@ fn handle_user_message<T: UserEvent>(
WebviewMessage::EvaluateScript(script, tx, span) => { WebviewMessage::EvaluateScript(script, tx, span) => {
let _span = span.entered(); let _span = span.entered();
if let Some(WindowHandle::Webview { inner: webview, .. }) = 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) { if let Err(e) = webview.evaluate_script(&script) {
debug_eprintln!("{}", e); debug_eprintln!("{}", e);
@ -2633,7 +2651,7 @@ fn handle_user_message<T: UserEvent>(
#[cfg(not(feature = "tracing"))] #[cfg(not(feature = "tracing"))]
WebviewMessage::EvaluateScript(script) => { WebviewMessage::EvaluateScript(script) => {
if let Some(WindowHandle::Webview { inner: webview, .. }) = 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) { if let Err(e) = webview.evaluate_script(&script) {
debug_eprintln!("{}", e); debug_eprintln!("{}", e);
@ -2642,7 +2660,7 @@ fn handle_user_message<T: UserEvent>(
} }
WebviewMessage::Print => { WebviewMessage::Print => {
if let Some(WindowHandle::Webview { inner: webview, .. }) = 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(); let _ = webview.print();
} }
@ -2651,7 +2669,7 @@ fn handle_user_message<T: UserEvent>(
}, },
Message::CreateWebview(window_id, handler) => match handler(event_loop, web_context) { Message::CreateWebview(window_id, handler) => match handler(event_loop, web_context) {
Ok(webview) => { Ok(webview) => {
windows.borrow_mut().insert(window_id, webview); windows.0.borrow_mut().insert(window_id, webview);
} }
Err(e) => { Err(e) => {
debug_eprintln!("{}", e); debug_eprintln!("{}", e);
@ -2664,7 +2682,7 @@ fn handle_user_message<T: UserEvent>(
let w = Arc::new(window); let w = Arc::new(window);
windows.borrow_mut().insert( windows.0.borrow_mut().insert(
window_id, window_id,
WindowWrapper { WindowWrapper {
label, label,
@ -2773,7 +2791,7 @@ fn handle_user_message<T: UserEvent>(
} }
let it = RunIteration { let it = RunIteration {
window_count: windows.borrow().len(), window_count: windows.0.borrow().len(),
}; };
it it
} }
@ -2861,6 +2879,7 @@ fn handle_event_loop<T: UserEvent>(
*webview_id_map.0.lock().unwrap().values().next().unwrap() *webview_id_map.0.lock().unwrap().values().next().unwrap()
}; };
windows windows
.0
.borrow() .borrow()
.get(&window_id) .get(&window_id)
.unwrap() .unwrap()
@ -2946,7 +2965,7 @@ fn handle_event_loop<T: UserEvent>(
} }
Event::UserEvent(Message::Webview(id, WebviewMessage::WebviewEvent(event))) => { Event::UserEvent(Message::Webview(id, WebviewMessage::WebviewEvent(event))) => {
if let Some(event) = WindowEventWrapper::from(&event).0 { if let Some(event) = WindowEventWrapper::from(&event).0 {
let windows = windows.borrow(); let windows = windows.0.borrow();
let window = windows.get(&id); let window = windows.get(&id);
if let Some(window) = window { if let Some(window) = window {
callback(RunEvent::WindowEvent { callback(RunEvent::WindowEvent {
@ -2967,7 +2986,7 @@ fn handle_event_loop<T: UserEvent>(
} => { } => {
if let Some(window_id) = webview_id_map.get(&window_id) { 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(window) = windows_ref.get(&window_id) {
if let Some(event) = WindowEventWrapper::parse(&window.inner, &event).0 { if let Some(event) = WindowEventWrapper::parse(&window.inner, &event).0 {
let label = window.label.clone(); let label = window.label.clone();
@ -2991,7 +3010,7 @@ fn handle_event_loop<T: UserEvent>(
match event { match event {
#[cfg(windows)] #[cfg(windows)]
WryWindowEvent::ThemeChanged(theme) => { 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 { if let Some(WindowHandle::Webview { inner, .. }) = &window.inner {
let theme = match theme { let theme = match theme {
WryTheme::Dark => wry::webview::Theme::Dark, WryTheme::Dark => wry::webview::Theme::Dark,
@ -3006,9 +3025,9 @@ fn handle_event_loop<T: UserEvent>(
on_close_requested(callback, window_id, windows.clone()); on_close_requested(callback, window_id, windows.clone());
} }
WryWindowEvent::Destroyed => { 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 { if removed {
let is_empty = windows.borrow().is_empty(); let is_empty = windows.0.borrow().is_empty();
if is_empty { if is_empty {
let (tx, rx) = channel(); let (tx, rx) = channel();
callback(RunEvent::ExitRequested { tx }); callback(RunEvent::ExitRequested { tx });
@ -3051,7 +3070,7 @@ fn handle_event_loop<T: UserEvent>(
} }
let it = RunIteration { let it = RunIteration {
window_count: windows.borrow().len(), window_count: windows.0.borrow().len(),
}; };
it it
} }
@ -3059,10 +3078,10 @@ fn handle_event_loop<T: UserEvent>(
fn on_close_requested<'a, T: UserEvent>( fn on_close_requested<'a, T: UserEvent>(
callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static), callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static),
window_id: WebviewId, window_id: WebviewId,
windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>, windows: Arc<WindowsStore>,
) { ) {
let (tx, rx) = channel(); let (tx, rx) = channel();
let windows_ref = windows.borrow(); let windows_ref = windows.0.borrow();
if let Some(w) = windows_ref.get(&window_id) { if let Some(w) = windows_ref.get(&window_id) {
let label = w.label.clone(); let label = w.label.clone();
let window_event_listeners = w.window_event_listeners.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<RefCell<HashMap<WebviewId, WindowWrapper>>>) { fn on_window_close(window_id: WebviewId, windows: Arc<WindowsStore>) {
if let Some(window_wrapper) = windows.borrow_mut().get_mut(&window_id) { if let Some(window_wrapper) = windows.0.borrow_mut().get_mut(&window_id) {
window_wrapper.inner = None; window_wrapper.inner = None;
} }
} }