Skip to main content

soma_tauri_shell/
tray.rs

1//! Tray icon setup helpers.
2//!
3//! Builds a tray icon with a caller-supplied menu and click behavior. This
4//! module owns the `tauri::tray` wiring boilerplate; the app supplies menu
5//! item labels/ids and what each event should do.
6
7use tauri::{
8    menu::{Menu, MenuItem},
9    tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
10    App, Wry,
11};
12
13/// One entry in a tray context menu.
14pub struct TrayMenuItemSpec {
15    pub id: &'static str,
16    pub label: String,
17    pub enabled: bool,
18}
19
20impl TrayMenuItemSpec {
21    #[must_use]
22    pub fn new(id: &'static str, label: impl Into<String>) -> Self {
23        Self {
24            id,
25            label: label.into(),
26            enabled: true,
27        }
28    }
29}
30
31/// Build a `tauri::menu::Menu` from a flat list of item specs.
32pub fn build_tray_menu(app: &App, items: &[TrayMenuItemSpec]) -> tauri::Result<Menu<Wry>> {
33    let mut menu_items = Vec::with_capacity(items.len());
34    for item in items {
35        menu_items.push(MenuItem::with_id(
36            app,
37            item.id,
38            &item.label,
39            item.enabled,
40            None::<&str>,
41        )?);
42    }
43    let refs: Vec<&dyn tauri::menu::IsMenuItem<tauri::Wry>> = menu_items
44        .iter()
45        .map(|item| item as &dyn tauri::menu::IsMenuItem<tauri::Wry>)
46        .collect();
47    Menu::with_items(app, &refs)
48}
49
50/// Install a tray icon using the app's default window icon, with `tooltip`,
51/// `menu`, and the two behaviors every launcher-style tray needs:
52/// `on_menu_item` fires with the clicked item's id; `on_left_click` fires on
53/// a tray-icon left click (mouse up).
54pub fn install_tray(
55    app: &App,
56    tooltip: &str,
57    menu: &Menu<Wry>,
58    on_menu_item: impl Fn(&tauri::AppHandle, &str) + Send + Sync + 'static,
59    on_left_click: impl Fn(&tauri::AppHandle) + Send + Sync + 'static,
60) -> tauri::Result<()> {
61    let icon = app.default_window_icon().cloned();
62    let mut tray = TrayIconBuilder::new()
63        .tooltip(tooltip)
64        .menu(menu)
65        .show_menu_on_left_click(false)
66        .on_menu_event(move |app, event| on_menu_item(app, event.id().as_ref()))
67        .on_tray_icon_event(move |tray, event| {
68            if let TrayIconEvent::Click {
69                button: MouseButton::Left,
70                button_state: MouseButtonState::Up,
71                ..
72            } = event
73            {
74                on_left_click(tray.app_handle());
75            }
76        });
77
78    if let Some(icon) = icon {
79        tray = tray.icon(icon);
80    }
81    tray.build(app)?;
82    Ok(())
83}