Rust コードでシステムトレイを操作する

Recipe ID: rust-018

Tauri v2 では、システムトレイ(Windows のタスクトレイ、macOS のメニューバー)のアイコンを Rust 側から柔軟に制御できます。
アプリをバックグラウンドで常駐させる場合などに便利です。

Cargo.toml の設定

src-tauri/Cargo.tomltauri 依存関係に tray-icon 機能を追加する必要があります。

[dependencies]
tauri = { version = "2", features = ["tray-icon"] }

1. トレイアイコンとメニューの作成

基本的には lib.rssetup フック内で作成します。
TrayIconBuilder を使用します。

use tauri::{
    menu::{Menu, MenuItem},
    tray::{MouseButton, TrayIconBuilder, TrayIconEvent},
    Manager,
};

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .setup(|app| {
            // 1. メニュー項目の作成
            // "quit" というIDで終了メニューを作成
            let quit_i = MenuItem::with_id(app, "quit", "終了", true, None::<&str>)?;
            // "show" というIDでウィンドウ表示メニューを作成
            let show_i = MenuItem::with_id(app, "show", "ウィンドウを表示", true, None::<&str>)?;
            
            // メニュー項目のリストからメニューを作成
            let menu = Menu::with_items(app, &[&show_i, &quit_i])?;

            // 2. トレイアイコンのビルド
            let _tray = TrayIconBuilder::with_id("main")
                // アイコン画像の設定(ここではアプリのデフォルトアイコンを流用)
                .icon(app.default_window_icon().unwrap().clone())
                .menu(&menu)
                .show_menu_on_left_click(false) // 左クリックでメニューを出すかどうか
                .on_menu_event(|app, event| {
                    // メニュー項目がクリックされた時の処理
                    match event.id().as_ref() {
                        "quit" => app.exit(0),
                        "show" => {
                            if let Some(window) = app.get_webview_window("main") {
                                let _ = window.show();
                                let _ = window.set_focus();
                            }
                        }
                        _ => {}
                    }
                })
                .on_tray_icon_event(|tray, event| {
                    // アイコン自体がクリックされた時の処理
                    if let TrayIconEvent::Click { button: MouseButton::Left, .. } = event {
                        println!("左クリックされました");
                        let app = tray.app_handle();
                        if let Some(window) = app.get_webview_window("main") {
                            // ウィンドウを表示して前に出す
                            let _ = window.show();
                            let _ = window.set_focus();
                        }
                    }
                })
                .build(app)?; // ビルド実行

            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

2. 実行中のアイコン操作

作成したトレイアイコンは、ID を指定して後から取得したり操作したりできます。

ツールチップの変更

#[tauri::command]
fn set_tray_tooltip(app: tauri::AppHandle, text: String) {
    // ID "main" で作成したトレイアイコンを取得
    if let Some(tray) = app.tray_by_id("main") {
         let _ = tray.set_tooltip(Some(text));
    }
}

補足

  • アイコンファイル: tauri::image::Image 型が必要です。パスからロードしたり、リソース埋め込み (include_bytes!) から生成できます。
  • Linux: libappindicator などのシステムライブラリが必要になる場合があります。
  • マルチプラットフォーム: macOS と Windows ではクリックの挙動やガイドラインが異なるため、実機での確認をおすすめします。