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 (#8402)
* 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:
parent
0a2175eabb
commit
b2f83f03a8
5
.changes/prevent-crash.md
Normal file
5
.changes/prevent-crash.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"tauri-runtime-wry": patch:bug
|
||||||
|
---
|
||||||
|
|
||||||
|
Use `Arc` instead of `Rc` to prevent crashes on macOS.
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user