tray-icon
tray-icon copied to clipboard
Crash on macOS
Error info
➜ iced-demo git:(master) /Users/xyz/.vscode/extensions/vadimcn.vscode-lldb-1.11.5/adapter/codelldb terminal-agent --connect=52222
Assertion failed: (CGAtomicGet(&is_initialized)), function CGSConnectionByID, file CGSConnection.mm, line 419.
The call stack is
__pthread_kill (@__pthread_kill:6)
pthread_kill (@pthread_kill:65)
abort (@abort:40)
__assert_rtn (@err:3)
CGSConnectionByID (@CGSConnectionByID:132)
SLSRegisterConnectionNotifyProc (@SLSRegisterConnectionNotifyProc:19)
+[NSCGSStatusItem addNavigationChangedNotificationHandler:] (@+[NSCGSStatusItem addNavigationChangedNotificationHandler:]:32)
__53+[NSStatusItem _registerNotificationHandlersIfNeeded]_block_invoke (@__53+[NSStatusItem _registerNotificationHandlersIfNeeded]_block_invoke:12)
_dispatch_client_callout (@_dispatch_client_callout:8)
_dispatch_once_callout (@_dispatch_once_callout:11)
-[NSStatusItem _initWithStatusBar:length:priority:systemInsertOrder:] (@-[NSStatusItem _initWithStatusBar:length:priority:systemInsertOrder:]:27)
-[NSStatusBar _statusItemWithLength:withPriority:] (@-[NSStatusBar _statusItemWithLength:withPriority:]:22)
<(A,) as objc2::encode::EncodeArguments>::__invoke (/Users/xyz/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/objc2-0.6.2/src/encode.rs:433)
objc2::runtime::message_receiver::msg_send_primitive::send (/Users/xyz/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/objc2-0.6.2/src/runtime/message_receiver.rs:172)
objc2::runtime::message_receiver::MessageReceiver::send_message (/Users/xyz/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/objc2-0.6.2/src/runtime/message_receiver.rs:432)
<MethodFamily as objc2::__macro_helpers::msg_send_retained::MsgSend<Receiver,Return>>::send_message (/Users/xyz/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/objc2-0.6.2/src/__macro_helpers/msg_send_retained.rs:35)
objc2_app_kit::generated::__NSStatusBar::NSStatusBar::statusItemWithLength (/Users/xyz/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/objc2-0.6.2/src/macros/extern_methods.rs:238)
tray_icon::platform_impl::platform::TrayIcon::create (/Users/xyz/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tray-icon-0.21.1/src/platform_impl/macos/mod.rs:55)
tray_icon::platform_impl::platform::TrayIcon::new (/Users/xyz/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tray-icon-0.21.1/src/platform_impl/macos/mod.rs:36)
tray_icon::TrayIcon::new (/Users/xyz/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tray-icon-0.21.1/src/lib.rs:341)
iced_demo::main::{{closure}} (/Users/xyz/Desktop/iced-demo/src/main.rs:133)
iced_demo::main (/Users/xyz/Desktop/iced-demo/src/main.rs:138)
core::ops::function::FnOnce::call_once (/Users/xyz/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250)
std::sys::backtrace::__rust_begin_short_backtrace (/Users/xyz/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/sys/backtrace.rs:152)
std::rt::lang_start::{{closure}} (/Users/xyz/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/rt.rs:206)
core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once (@std::rt::lang_start_internal:219)
std::panicking::catch_unwind::do_call (@std::rt::lang_start_internal:217)
std::panicking::catch_unwind (@std::rt::lang_start_internal:217)
std::panic::catch_unwind (@std::rt::lang_start_internal:217)
std::rt::lang_start_internal::{{closure}} (@std::rt::lang_start_internal:217)
std::panicking::catch_unwind::do_call (@std::rt::lang_start_internal:14)
std::panicking::catch_unwind (@std::rt::lang_start_internal:14)
std::panic::catch_unwind (@std::rt::lang_start_internal:14)
std::rt::lang_start_internal (@std::rt::lang_start_internal:14)
std::rt::lang_start (/Users/xyz/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/std/src/rt.rs:205)
main (@main:10)
start (@start:439)
Thanks for the report, which macOS version are you running?
➜ iced-demo git:(master) uname -a
Darwin 23.3.0 Darwin Kernel Version 23.3.0: Wed Dec 20 21:28:58 PST 2023; root:xnu-10002.81.5~7/RELEASE_X86_64 x86_64
Now I make this changes
diff --git a/src/lib.rs b/src/lib.rs
index 5865a3c..c12b257 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -121,9 +121,8 @@
//! [tao]: https://docs.rs/tao
use std::{
- cell::RefCell,
path::{Path, PathBuf},
- rc::Rc,
+ sync::{Arc, Mutex},
};
use counter::Counter;
@@ -325,9 +324,12 @@ impl TrayIconBuilder {
#[derive(Clone)]
pub struct TrayIcon {
id: TrayIconId,
- tray: Rc<RefCell<platform_impl::TrayIcon>>,
+ tray: std::sync::Arc<std::sync::Mutex<platform_impl::TrayIcon>>,
}
+unsafe impl Send for TrayIcon {}
+unsafe impl Sync for TrayIcon {}
+
impl TrayIcon {
/// Builds and adds a new tray icon to the system tray.
///
@@ -338,10 +340,7 @@ impl TrayIcon {
pub fn new(attrs: TrayIconAttributes) -> Result<Self> {
let id = TrayIconId(COUNTER.next().to_string());
Ok(Self {
- tray: Rc::new(RefCell::new(platform_impl::TrayIcon::new(
- id.clone(),
- attrs,
- )?)),
+ tray: Arc::new(Mutex::new(platform_impl::TrayIcon::new(id.clone(), attrs)?)),
id,
})
}
@@ -352,10 +351,7 @@ impl TrayIcon {
pub fn with_id<I: Into<TrayIconId>>(id: I, attrs: TrayIconAttributes) -> Result<Self> {
let id = id.into();
Ok(Self {
- tray: Rc::new(RefCell::new(platform_impl::TrayIcon::new(
- id.clone(),
- attrs,
- )?)),
+ tray: Arc::new(Mutex::new(platform_impl::TrayIcon::new(id.clone(), attrs)?)),
id,
})
}
@@ -367,7 +363,7 @@ impl TrayIcon {
/// Set new tray icon. If `None` is provided, it will remove the icon.
pub fn set_icon(&self, icon: Option<Icon>) -> Result<()> {
- self.tray.borrow_mut().set_icon(icon)
+ self.tray.lock().unwrap().set_icon(icon)
}
/// Set new tray menu.
@@ -376,7 +372,7 @@ impl TrayIcon {
///
/// - **Linux**: once a menu is set it cannot be removed so `None` has no effect
pub fn set_menu(&self, menu: Option<Box<dyn menu::ContextMenu>>) {
- self.tray.borrow_mut().set_menu(menu)
+ self.tray.lock().unwrap().set_menu(menu);
}
/// Sets the tooltip for this tray icon.
@@ -385,7 +381,7 @@ impl TrayIcon {
///
/// - **Linux:** Unsupported
pub fn set_tooltip<S: AsRef<str>>(&self, tooltip: Option<S>) -> Result<()> {
- self.tray.borrow_mut().set_tooltip(tooltip)
+ self.tray.lock().unwrap().set_tooltip(tooltip)
}
/// Sets the tooltip for this tray icon.
@@ -399,12 +395,12 @@ impl TrayIcon {
/// on the user's panel. This may not be shown in all visualizations.
/// - **Windows:** Unsupported
pub fn set_title<S: AsRef<str>>(&self, title: Option<S>) {
- self.tray.borrow_mut().set_title(title)
+ self.tray.lock().unwrap().set_title(title)
}
/// Show or hide this tray icon
pub fn set_visible(&self, visible: bool) -> Result<()> {
- self.tray.borrow_mut().set_visible(visible)
+ self.tray.lock().unwrap().set_visible(visible)
}
/// Sets the tray icon temp dir path. **Linux only**.
@@ -413,7 +409,7 @@ impl TrayIcon {
/// be `$XDG_RUNTIME_DIR/tray-icon` or `$TEMP/tray-icon`.
pub fn set_temp_dir_path<P: AsRef<Path>>(&self, path: Option<P>) {
#[cfg(target_os = "linux")]
- self.tray.borrow_mut().set_temp_dir_path(path);
+ self.tray.lock().unwrap().set_temp_dir_path(path);
#[cfg(not(target_os = "linux"))]
let _ = path;
}
@@ -421,7 +417,7 @@ impl TrayIcon {
/// Set the current icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only**.
pub fn set_icon_as_template(&self, is_template: bool) {
#[cfg(target_os = "macos")]
- self.tray.borrow_mut().set_icon_as_template(is_template);
+ self.tray.lock().unwrap().set_icon_as_template(is_template);
#[cfg(not(target_os = "macos"))]
let _ = is_template;
}
@@ -430,7 +426,8 @@ impl TrayIcon {
#[cfg(target_os = "macos")]
return self
.tray
- .borrow_mut()
+ .lock()
+ .unwrap()
.set_icon_with_as_template(icon, is_template);
#[cfg(not(target_os = "macos"))]
{
@@ -447,7 +444,10 @@ impl TrayIcon {
/// - **Linux:** Unsupported.
pub fn set_show_menu_on_left_click(&self, enable: bool) {
#[cfg(any(target_os = "macos", target_os = "windows"))]
- self.tray.borrow_mut().set_show_menu_on_left_click(enable);
+ self.tray
+ .lock()
+ .unwrap()
+ .set_show_menu_on_left_click(enable);
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
let _ = enable;
}
@@ -458,7 +458,7 @@ impl TrayIcon {
///
/// - **Linux**: Unsupported.
pub fn rect(&self) -> Option<Rect> {
- self.tray.borrow().rect()
+ self.tray.lock().unwrap().rect()
}
/// Get the tray icon's underlying [window handle](windows_sys::Win32::Foundation::HWND) **Windows only**.
@@ -466,7 +466,7 @@ impl TrayIcon {
/// This window handle is valid as long as the tray icon.
#[cfg(windows)]
pub fn window_handle(&self) -> windows_sys::Win32::Foundation::HWND {
- self.tray.borrow().hwnd()
+ self.tray.lock().unwrap().window_handle()
}
/// Get the tray icon's underlying [NSStatusItem](objc2_app_kit::NSStatusItem) **macOS only**.
@@ -474,7 +474,7 @@ impl TrayIcon {
/// Returns `None` if the status item is not available.
#[cfg(target_os = "macos")]
pub fn ns_status_item(&self) -> Option<objc2::rc::Retained<objc2_app_kit::NSStatusItem>> {
- self.tray.borrow().ns_status_item().cloned()
+ self.tray.lock().unwrap().ns_status_item().cloned()
}
/// Get the tray icon's underlying [AppIndicator](libappindicator::AppIndicator) **Linux only**.
@@ -484,7 +484,7 @@ impl TrayIcon {
/// The returned pointer is valid as long as the `TrayIcon` is.
#[cfg(all(unix, not(target_os = "macos")))]
pub unsafe fn app_indicator(&self) -> *const libappindicator::AppIndicator {
- self.tray.borrow().app_indicator() as *const _
+ self.tray.lock().unwrap().app_indicator() as *const _
}
}
There may be a lifecycle or initialization race between the iced::application run loop and the tray-icon's NSStatusItem.
I try deferring the creation of the tray_icon to the iced::application update or view function (initializing it only once). This ensures that iced has initialized the GUI environment on the main thread.
And I call it like this. now it work fine for me.
static TRAY_ICON_HANDLE: std::sync::OnceLock<Arc<Mutex<tray_icon::TrayIcon>>> = std::sync::OnceLock::new();
fn update(state: &mut AppState, message: Message) {
TRAY_ICON_HANDLE.get_or_init(|| {
let tray_icon = tray_icon::TrayIcon::new(attrs).expect("Failed to create tray icon");
Arc::new(Mutex::new(tray_icon))
});
// ...
}