Skip to content

Commit 4191a7a

Browse files
authored
fix(tray): build tray on main thread (#11583)
1 parent f37e97d commit 4191a7a

File tree

4 files changed

+33
-7
lines changed

4 files changed

+33
-7
lines changed

.changes/tray-async-command.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": "patch:bug"
3+
---
4+
5+
Fix tray events not fired for tray icons created inside an async command.

crates/tauri/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,15 @@ pub(crate) mod sealed {
10111011
}
10121012
}
10131013

1014+
struct UnsafeSend<T>(T);
1015+
unsafe impl<T> Send for UnsafeSend<T> {}
1016+
1017+
impl<T> UnsafeSend<T> {
1018+
fn take(self) -> T {
1019+
self.0
1020+
}
1021+
}
1022+
10141023
#[allow(unused)]
10151024
macro_rules! run_main_thread {
10161025
($handle:ident, $ex:expr) => {{

crates/tauri/src/menu/mod.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ macro_rules! gen_wrappers {
7575
app_handle: $crate::AppHandle<R>,
7676
}
7777

78-
7978
/// # Safety
8079
///
8180
/// We make sure it always runs on the main thread.
@@ -96,11 +95,9 @@ macro_rules! gen_wrappers {
9695

9796
impl<R: Runtime> Drop for $inner<R> {
9897
fn drop(&mut self) {
99-
struct SafeSend<T>(T);
100-
unsafe impl<T> Send for SafeSend<T> {}
101-
10298
let inner = self.inner.take();
103-
let inner = SafeSend(inner);
99+
// SAFETY: inner was created on main thread and is being dropped on main thread
100+
let inner = $crate::UnsafeSend(inner);
104101
let _ = self.app_handle.run_on_main_thread(move || {
105102
drop(inner);
106103
});

crates/tauri/src/tray/mod.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::app::{GlobalMenuEventListener, GlobalTrayIconEventListener};
1010
use crate::menu::ContextMenu;
1111
use crate::menu::MenuEvent;
1212
use crate::resources::Resource;
13+
use crate::UnsafeSend;
1314
use crate::{
1415
image::Image, menu::run_item_main_thread, AppHandle, Manager, PhysicalPosition, Rect, Runtime,
1516
};
@@ -342,10 +343,24 @@ impl<R: Runtime> TrayIconBuilder<R> {
342343
/// Builds and adds a new [`TrayIcon`] to the system tray.
343344
pub fn build<M: Manager<R>>(self, manager: &M) -> crate::Result<TrayIcon<R>> {
344345
let id = self.id().clone();
345-
let inner = self.inner.build()?;
346+
347+
// SAFETY:
348+
// the menu within this builder was created on main thread
349+
// and will be accessed on the main thread
350+
let unsafe_builder = UnsafeSend(self.inner);
351+
352+
let (tx, rx) = std::sync::mpsc::channel();
353+
let unsafe_tray = manager
354+
.app_handle()
355+
.run_on_main_thread(move || {
356+
// SAFETY: will only be accessed on main thread
357+
let _ = tx.send(unsafe_builder.take().build().map(UnsafeSend));
358+
})
359+
.and_then(|_| rx.recv().map_err(|_| crate::Error::FailedToReceiveMessage))??;
360+
346361
let icon = TrayIcon {
347362
id,
348-
inner,
363+
inner: unsafe_tray.take(),
349364
app_handle: manager.app_handle().clone(),
350365
};
351366

0 commit comments

Comments
 (0)