Skip to content

Commit

Permalink
fix(tray): build tray on main thread (#11583)
Browse files Browse the repository at this point in the history
  • Loading branch information
amrbashir authored Nov 5, 2024
1 parent f37e97d commit 4191a7a
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changes/tray-async-command.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tauri": "patch:bug"
---

Fix tray events not fired for tray icons created inside an async command.
9 changes: 9 additions & 0 deletions crates/tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,15 @@ pub(crate) mod sealed {
}
}

struct UnsafeSend<T>(T);
unsafe impl<T> Send for UnsafeSend<T> {}

impl<T> UnsafeSend<T> {
fn take(self) -> T {
self.0
}
}

#[allow(unused)]
macro_rules! run_main_thread {
($handle:ident, $ex:expr) => {{
Expand Down
7 changes: 2 additions & 5 deletions crates/tauri/src/menu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ macro_rules! gen_wrappers {
app_handle: $crate::AppHandle<R>,
}


/// # Safety
///
/// We make sure it always runs on the main thread.
Expand All @@ -96,11 +95,9 @@ macro_rules! gen_wrappers {

impl<R: Runtime> Drop for $inner<R> {
fn drop(&mut self) {
struct SafeSend<T>(T);
unsafe impl<T> Send for SafeSend<T> {}

let inner = self.inner.take();
let inner = SafeSend(inner);
// SAFETY: inner was created on main thread and is being dropped on main thread
let inner = $crate::UnsafeSend(inner);
let _ = self.app_handle.run_on_main_thread(move || {
drop(inner);
});
Expand Down
19 changes: 17 additions & 2 deletions crates/tauri/src/tray/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::app::{GlobalMenuEventListener, GlobalTrayIconEventListener};
use crate::menu::ContextMenu;
use crate::menu::MenuEvent;
use crate::resources::Resource;
use crate::UnsafeSend;
use crate::{
image::Image, menu::run_item_main_thread, AppHandle, Manager, PhysicalPosition, Rect, Runtime,
};
Expand Down Expand Up @@ -342,10 +343,24 @@ impl<R: Runtime> TrayIconBuilder<R> {
/// Builds and adds a new [`TrayIcon`] to the system tray.
pub fn build<M: Manager<R>>(self, manager: &M) -> crate::Result<TrayIcon<R>> {
let id = self.id().clone();
let inner = self.inner.build()?;

// SAFETY:
// the menu within this builder was created on main thread
// and will be accessed on the main thread
let unsafe_builder = UnsafeSend(self.inner);

let (tx, rx) = std::sync::mpsc::channel();
let unsafe_tray = manager
.app_handle()
.run_on_main_thread(move || {
// SAFETY: will only be accessed on main thread
let _ = tx.send(unsafe_builder.take().build().map(UnsafeSend));
})
.and_then(|_| rx.recv().map_err(|_| crate::Error::FailedToReceiveMessage))??;

let icon = TrayIcon {
id,
inner,
inner: unsafe_tray.take(),
app_handle: manager.app_handle().clone(),
};

Expand Down

0 comments on commit 4191a7a

Please sign in to comment.