mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-11-03 20:31:54 +03:00
parent
48a7415c21
commit
937849f28c
5
.changes/wry-arc.md
Normal file
5
.changes/wry-arc.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-runtime-wry": patch:bug
|
||||
---
|
||||
|
||||
Use `Arc` instead of `Rc` on global shortcut and tray types to prevent crashes on macOS.
|
@ -8,7 +8,6 @@ use std::{
|
||||
collections::HashMap,
|
||||
error::Error as StdError,
|
||||
fmt,
|
||||
rc::Rc,
|
||||
sync::{
|
||||
mpsc::{channel, Sender},
|
||||
Arc, Mutex,
|
||||
@ -18,14 +17,34 @@ use std::{
|
||||
use crate::{getter, Context, Message};
|
||||
|
||||
use tauri_runtime::{Error, GlobalShortcutManager, Result, UserEvent};
|
||||
#[cfg(desktop)]
|
||||
|
||||
pub use wry::application::{
|
||||
accelerator::{Accelerator, AcceleratorId, AcceleratorParseError},
|
||||
global_shortcut::{GlobalShortcut, ShortcutManager as WryShortcutManager},
|
||||
event_loop::EventLoopWindowTarget,
|
||||
global_shortcut::GlobalShortcut,
|
||||
};
|
||||
|
||||
pub type GlobalShortcutListeners = Arc<Mutex<HashMap<AcceleratorId, Box<dyn Fn() + Send>>>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WryShortcutManager(pub wry::application::global_shortcut::ShortcutManager);
|
||||
|
||||
// SAFETY: we ensure this type is only used on the main thread.
|
||||
#[allow(clippy::non_send_fields_in_send_ty)]
|
||||
unsafe impl Send for WryShortcutManager {}
|
||||
|
||||
// SAFETY: we ensure this type is only used on the main thread.
|
||||
#[allow(clippy::non_send_fields_in_send_ty)]
|
||||
unsafe impl Sync for WryShortcutManager {}
|
||||
|
||||
impl WryShortcutManager {
|
||||
pub fn new<T: 'static>(event_loop: &EventLoopWindowTarget<T>) -> Self {
|
||||
Self(wry::application::global_shortcut::ShortcutManager::new(
|
||||
event_loop,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum GlobalShortcutMessage {
|
||||
IsRegistered(Accelerator, Sender<bool>),
|
||||
@ -139,7 +158,7 @@ impl<T: UserEvent> GlobalShortcutManager for GlobalShortcutManagerHandle<T> {
|
||||
|
||||
pub fn handle_global_shortcut_message(
|
||||
message: GlobalShortcutMessage,
|
||||
global_shortcut_manager: &Rc<Mutex<WryShortcutManager>>,
|
||||
global_shortcut_manager: &Mutex<WryShortcutManager>,
|
||||
) {
|
||||
match message {
|
||||
GlobalShortcutMessage::IsRegistered(accelerator, tx) => tx
|
||||
@ -147,6 +166,7 @@ pub fn handle_global_shortcut_message(
|
||||
global_shortcut_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.0
|
||||
.is_registered(&accelerator),
|
||||
)
|
||||
.unwrap(),
|
||||
@ -155,6 +175,7 @@ pub fn handle_global_shortcut_message(
|
||||
global_shortcut_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.0
|
||||
.register(accelerator)
|
||||
.map(GlobalShortcutWrapper)
|
||||
.map_err(|e| Error::GlobalShortcut(Box::new(e))),
|
||||
@ -165,6 +186,7 @@ pub fn handle_global_shortcut_message(
|
||||
global_shortcut_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.0
|
||||
.unregister(shortcut.0)
|
||||
.map_err(|e| Error::GlobalShortcut(Box::new(e))),
|
||||
)
|
||||
@ -174,6 +196,7 @@ pub fn handle_global_shortcut_message(
|
||||
global_shortcut_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.0
|
||||
.unregister_all()
|
||||
.map_err(|e| Error::GlobalShortcut(Box::new(e))),
|
||||
)
|
||||
|
@ -211,35 +211,37 @@ impl<T: UserEvent> Context<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: UserEvent> Context<T> {
|
||||
fn create_webview(&self, pending: PendingWindow<T, Wry<T>>) -> Result<DetachedWindow<T, Wry<T>>> {
|
||||
let label = pending.label.clone();
|
||||
let menu_ids = pending.menu_ids.clone();
|
||||
let js_event_listeners = pending.js_event_listeners.clone();
|
||||
let context = self.clone();
|
||||
let window_id = rand::random();
|
||||
fn context_create_webview<T: UserEvent>(
|
||||
context: Context<T>,
|
||||
pending: PendingWindow<T, Wry<T>>,
|
||||
) -> Result<DetachedWindow<T, Wry<T>>> {
|
||||
let label = pending.label.clone();
|
||||
let menu_ids = pending.menu_ids.clone();
|
||||
let js_event_listeners = pending.js_event_listeners.clone();
|
||||
|
||||
send_user_message(
|
||||
self,
|
||||
Message::CreateWebview(
|
||||
window_id,
|
||||
Box::new(move |event_loop, web_context| {
|
||||
create_webview(window_id, event_loop, web_context, context, pending)
|
||||
}),
|
||||
),
|
||||
)?;
|
||||
let window_id = rand::random();
|
||||
|
||||
let dispatcher = WryDispatcher {
|
||||
let context_ = context.clone();
|
||||
send_user_message(
|
||||
&context,
|
||||
Message::CreateWebview(
|
||||
window_id,
|
||||
context: self.clone(),
|
||||
};
|
||||
Ok(DetachedWindow {
|
||||
label,
|
||||
dispatcher,
|
||||
menu_ids,
|
||||
js_event_listeners,
|
||||
})
|
||||
}
|
||||
Box::new(move |event_loop, web_context| {
|
||||
create_webview(window_id, event_loop, web_context, context_, pending)
|
||||
}),
|
||||
),
|
||||
)?;
|
||||
|
||||
let dispatcher = WryDispatcher {
|
||||
window_id,
|
||||
context: context.clone(),
|
||||
};
|
||||
Ok(DetachedWindow {
|
||||
label,
|
||||
dispatcher,
|
||||
menu_ids,
|
||||
js_event_listeners,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
@ -281,7 +283,7 @@ pub struct DispatcherMainThreadContext<T: UserEvent> {
|
||||
pub window_target: EventLoopWindowTarget<Message<T>>,
|
||||
pub web_context: WebContextStore,
|
||||
#[cfg(all(desktop, feature = "global-shortcut"))]
|
||||
pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
|
||||
pub global_shortcut_manager: Arc<Mutex<WryShortcutManager>>,
|
||||
// changing this to an Rc will cause frequent app crashes.
|
||||
pub windows: Arc<WindowsStore>,
|
||||
#[cfg(all(desktop, feature = "system-tray"))]
|
||||
@ -1452,7 +1454,7 @@ impl<T: UserEvent> Dispatch<T> for WryDispatcher<T> {
|
||||
&mut self,
|
||||
pending: PendingWindow<T, Self::Runtime>,
|
||||
) -> Result<DetachedWindow<T, Self::Runtime>> {
|
||||
self.context.create_webview(pending)
|
||||
context_create_webview(self.context.clone(), pending)
|
||||
}
|
||||
|
||||
fn set_resizable(&self, resizable: bool) -> Result<()> {
|
||||
@ -1927,7 +1929,7 @@ impl<T: UserEvent> RuntimeHandle<T> for WryHandle<T> {
|
||||
&self,
|
||||
pending: PendingWindow<T, Self::Runtime>,
|
||||
) -> Result<DetachedWindow<T, Self::Runtime>> {
|
||||
self.context.create_webview(pending)
|
||||
context_create_webview(self.context.clone(), pending)
|
||||
}
|
||||
|
||||
fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
|
||||
@ -1980,7 +1982,7 @@ impl<T: UserEvent> Wry<T> {
|
||||
let web_context = WebContextStore::default();
|
||||
|
||||
#[cfg(all(desktop, feature = "global-shortcut"))]
|
||||
let global_shortcut_manager = Rc::new(Mutex::new(WryShortcutManager::new(&event_loop)));
|
||||
let global_shortcut_manager = Arc::new(Mutex::new(WryShortcutManager::new(&event_loop)));
|
||||
|
||||
let windows = Arc::new(WindowsStore(RefCell::new(BTreeMap::default())));
|
||||
|
||||
@ -2131,7 +2133,8 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
|
||||
let id = system_tray.id;
|
||||
let mut listeners = Vec::new();
|
||||
if let Some(l) = system_tray.on_event.take() {
|
||||
listeners.push(Rc::new(l));
|
||||
#[allow(clippy::arc_with_non_send_sync)]
|
||||
listeners.push(Arc::new(l));
|
||||
}
|
||||
let (tray, items) = create_tray(WryTrayId(id), system_tray, &self.event_loop)?;
|
||||
self
|
||||
@ -2144,9 +2147,9 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
|
||||
.insert(
|
||||
id,
|
||||
TrayContext {
|
||||
tray: Rc::new(RefCell::new(Some(tray))),
|
||||
listeners: Rc::new(RefCell::new(listeners)),
|
||||
items: Rc::new(RefCell::new(items)),
|
||||
tray: Arc::new(TrayCell(RefCell::new(Some(tray)))),
|
||||
listeners: Arc::new(TrayListenersCell(RefCell::new(listeners))),
|
||||
items: Arc::new(TrayItemsCell(RefCell::new(items))),
|
||||
},
|
||||
);
|
||||
|
||||
@ -2280,14 +2283,14 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
|
||||
fn run<F: FnMut(RunEvent<T>) + 'static>(self, mut callback: F) {
|
||||
let windows = self.context.main_thread.windows.clone();
|
||||
let webview_id_map = self.context.webview_id_map.clone();
|
||||
let web_context = self.context.main_thread.web_context;
|
||||
let web_context = self.context.main_thread.web_context.clone();
|
||||
let mut plugins = self.plugins;
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
let active_tracing_spans = self.context.main_thread.active_tracing_spans.clone();
|
||||
|
||||
#[cfg(all(desktop, feature = "system-tray"))]
|
||||
let system_tray_manager = self.context.main_thread.system_tray_manager;
|
||||
let system_tray_manager = self.context.main_thread.system_tray_manager.clone();
|
||||
|
||||
#[cfg(all(desktop, feature = "global-shortcut"))]
|
||||
let global_shortcut_manager = self.context.main_thread.global_shortcut_manager.clone();
|
||||
@ -2350,7 +2353,7 @@ pub struct EventLoopIterationContext<'a, T: UserEvent> {
|
||||
pub webview_id_map: WebviewIdStore,
|
||||
pub windows: Arc<WindowsStore>,
|
||||
#[cfg(all(desktop, feature = "global-shortcut"))]
|
||||
pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
|
||||
pub global_shortcut_manager: Arc<Mutex<WryShortcutManager>>,
|
||||
#[cfg(all(desktop, feature = "global-shortcut"))]
|
||||
pub global_shortcut_manager_handle: &'a GlobalShortcutManagerHandle<T>,
|
||||
#[cfg(all(desktop, feature = "system-tray"))]
|
||||
@ -2363,7 +2366,7 @@ struct UserMessageContext {
|
||||
windows: Arc<WindowsStore>,
|
||||
webview_id_map: WebviewIdStore,
|
||||
#[cfg(all(desktop, feature = "global-shortcut"))]
|
||||
global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
|
||||
global_shortcut_manager: Arc<Mutex<WryShortcutManager>>,
|
||||
#[cfg(all(desktop, feature = "system-tray"))]
|
||||
system_tray_manager: SystemTrayManager,
|
||||
}
|
||||
@ -2703,16 +2706,17 @@ fn handle_user_message<T: UserEvent>(
|
||||
if let TrayMessage::Create(mut tray, tx) = tray_message {
|
||||
let mut listeners = Vec::new();
|
||||
if let Some(l) = tray.on_event.take() {
|
||||
listeners.push(Rc::new(l));
|
||||
#[allow(clippy::arc_with_non_send_sync)]
|
||||
listeners.push(Arc::new(l));
|
||||
}
|
||||
match create_tray(WryTrayId(tray_id), tray, event_loop) {
|
||||
Ok((tray, items)) => {
|
||||
trays.insert(
|
||||
tray_id,
|
||||
TrayContext {
|
||||
tray: Rc::new(RefCell::new(Some(tray))),
|
||||
listeners: Rc::new(RefCell::new(listeners)),
|
||||
items: Rc::new(RefCell::new(items)),
|
||||
tray: Arc::new(TrayCell(RefCell::new(Some(tray)))),
|
||||
listeners: Arc::new(TrayListenersCell(RefCell::new(listeners))),
|
||||
items: Arc::new(TrayItemsCell(RefCell::new(items))),
|
||||
},
|
||||
);
|
||||
|
||||
@ -2726,7 +2730,7 @@ fn handle_user_message<T: UserEvent>(
|
||||
} else if let Some(tray_context) = trays.get(&tray_id) {
|
||||
match tray_message {
|
||||
TrayMessage::UpdateItem(menu_id, update) => {
|
||||
let mut tray = tray_context.items.as_ref().borrow_mut();
|
||||
let mut tray = tray_context.items.as_ref().0.borrow_mut();
|
||||
let item = tray.get_mut(&menu_id).expect("menu item not found");
|
||||
match update {
|
||||
MenuUpdate::SetEnabled(enabled) => item.set_enabled(enabled),
|
||||
@ -2739,14 +2743,14 @@ fn handle_user_message<T: UserEvent>(
|
||||
}
|
||||
}
|
||||
TrayMessage::UpdateMenu(menu) => {
|
||||
if let Some(tray) = &mut *tray_context.tray.borrow_mut() {
|
||||
if let Some(tray) = &mut *tray_context.tray.0.borrow_mut() {
|
||||
let mut items = HashMap::new();
|
||||
tray.set_menu(&to_wry_context_menu(&mut items, menu));
|
||||
*tray_context.items.borrow_mut() = items;
|
||||
*tray_context.items.0.borrow_mut() = items;
|
||||
}
|
||||
}
|
||||
TrayMessage::UpdateIcon(icon) => {
|
||||
if let Some(tray) = &mut *tray_context.tray.borrow_mut() {
|
||||
if let Some(tray) = &mut *tray_context.tray.0.borrow_mut() {
|
||||
if let Ok(icon) = TrayIcon::try_from(icon) {
|
||||
tray.set_icon(icon.0);
|
||||
}
|
||||
@ -2754,18 +2758,18 @@ fn handle_user_message<T: UserEvent>(
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
TrayMessage::UpdateIconAsTemplate(is_template) => {
|
||||
if let Some(tray) = &mut *tray_context.tray.borrow_mut() {
|
||||
if let Some(tray) = &mut *tray_context.tray.0.borrow_mut() {
|
||||
tray.set_icon_as_template(is_template);
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
TrayMessage::UpdateTitle(title) => {
|
||||
if let Some(tray) = &mut *tray_context.tray.borrow_mut() {
|
||||
if let Some(tray) = &mut *tray_context.tray.0.borrow_mut() {
|
||||
tray.set_title(&title);
|
||||
}
|
||||
}
|
||||
TrayMessage::UpdateTooltip(tooltip) => {
|
||||
if let Some(tray) = &mut *tray_context.tray.borrow_mut() {
|
||||
if let Some(tray) = &mut *tray_context.tray.0.borrow_mut() {
|
||||
tray.set_tooltip(&tooltip);
|
||||
}
|
||||
}
|
||||
@ -2773,9 +2777,9 @@ fn handle_user_message<T: UserEvent>(
|
||||
// already handled
|
||||
}
|
||||
TrayMessage::Destroy(tx) => {
|
||||
*tray_context.tray.borrow_mut() = None;
|
||||
tray_context.listeners.borrow_mut().clear();
|
||||
tray_context.items.borrow_mut().clear();
|
||||
*tray_context.tray.0.borrow_mut() = None;
|
||||
tray_context.listeners.0.borrow_mut().clear();
|
||||
tray_context.items.0.borrow_mut().clear();
|
||||
tx.send(Ok(())).unwrap();
|
||||
}
|
||||
}
|
||||
@ -2905,11 +2909,11 @@ fn handle_event_loop<T: UserEvent>(
|
||||
let (mut listeners, mut tray_id) = (None, 0);
|
||||
for (id, tray_context) in trays_iter {
|
||||
let has_menu = {
|
||||
let items = tray_context.items.borrow();
|
||||
let items = tray_context.items.0.borrow();
|
||||
items.contains_key(&menu_id.0)
|
||||
};
|
||||
if has_menu {
|
||||
listeners.replace(tray_context.listeners.borrow().clone());
|
||||
listeners.replace(tray_context.listeners.0.borrow().clone());
|
||||
tray_id = *id;
|
||||
break;
|
||||
}
|
||||
@ -2948,7 +2952,7 @@ fn handle_event_loop<T: UserEvent>(
|
||||
};
|
||||
let trays = system_tray_manager.trays.lock().unwrap();
|
||||
if let Some(tray_context) = trays.get(&id.0) {
|
||||
let listeners = tray_context.listeners.borrow();
|
||||
let listeners = tray_context.listeners.0.borrow();
|
||||
let iter = listeners.iter();
|
||||
for handler in iter {
|
||||
handler(&event);
|
||||
|
@ -32,7 +32,6 @@ use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
fmt,
|
||||
rc::Rc,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
@ -40,12 +39,45 @@ pub type GlobalSystemTrayEventHandler = Box<dyn Fn(TrayId, &SystemTrayEvent) + S
|
||||
pub type GlobalSystemTrayEventListeners = Arc<Mutex<Vec<Arc<GlobalSystemTrayEventHandler>>>>;
|
||||
|
||||
pub type SystemTrayEventHandler = Box<dyn Fn(&SystemTrayEvent) + Send>;
|
||||
pub type SystemTrayEventListeners = Rc<RefCell<Vec<Rc<SystemTrayEventHandler>>>>;
|
||||
pub type SystemTrayItems = Rc<RefCell<HashMap<u16, WryCustomMenuItem>>>;
|
||||
pub type SystemTrayEventListeners = Arc<TrayListenersCell>;
|
||||
pub type SystemTrayItems = Arc<TrayItemsCell>;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TrayItemsCell(pub RefCell<HashMap<u16, WryCustomMenuItem>>);
|
||||
|
||||
// SAFETY: we ensure this type is only used on the main thread.
|
||||
#[allow(clippy::non_send_fields_in_send_ty)]
|
||||
unsafe impl Send for TrayItemsCell {}
|
||||
|
||||
// SAFETY: we ensure this type is only used on the main thread.
|
||||
#[allow(clippy::non_send_fields_in_send_ty)]
|
||||
unsafe impl Sync for TrayItemsCell {}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TrayCell(pub RefCell<Option<WrySystemTray>>);
|
||||
|
||||
// SAFETY: we ensure this type is only used on the main thread.
|
||||
#[allow(clippy::non_send_fields_in_send_ty)]
|
||||
unsafe impl Send for TrayCell {}
|
||||
|
||||
// SAFETY: we ensure this type is only used on the main thread.
|
||||
#[allow(clippy::non_send_fields_in_send_ty)]
|
||||
unsafe impl Sync for TrayCell {}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TrayListenersCell(pub RefCell<Vec<Arc<SystemTrayEventHandler>>>);
|
||||
|
||||
// SAFETY: we ensure this type is only used on the main thread.
|
||||
#[allow(clippy::non_send_fields_in_send_ty)]
|
||||
unsafe impl Send for TrayListenersCell {}
|
||||
|
||||
// SAFETY: we ensure this type is only used on the main thread.
|
||||
#[allow(clippy::non_send_fields_in_send_ty)]
|
||||
unsafe impl Sync for TrayListenersCell {}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct TrayContext {
|
||||
pub tray: Rc<RefCell<Option<WrySystemTray>>>,
|
||||
pub tray: Arc<TrayCell>,
|
||||
pub listeners: SystemTrayEventListeners,
|
||||
pub items: SystemTrayItems,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user