diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index 89f14f49..7805b917 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -21,6 +21,7 @@ tauri = { version = "2.0.0-beta", features = [ "devtools", "macos-private-api", "protocol-asset", + "tray-icon", ] } tauri-plugin-dialog = "2.0.0-beta" tauri-plugin-http = "2.0.0-beta" diff --git a/packages/desktop/src/main.rs b/packages/desktop/src/main.rs index deb11857..da101372 100644 --- a/packages/desktop/src/main.rs +++ b/packages/desktop/src/main.rs @@ -1,9 +1,6 @@ use std::{collections::HashMap, env, sync::Arc}; use clap::Parser; -use cli::{Cli, CliCommand}; -use monitors::get_monitors_str; -use providers::{config::ProviderConfig, manager::ProviderManager}; use serde::Serialize; use tauri::{ AppHandle, Manager, State, WebviewUrl, WebviewWindowBuilder, Window, @@ -20,10 +17,17 @@ use tracing_subscriber::EnvFilter; #[cfg(target_os = "macos")] use crate::util::window_ext::WindowExt; +use crate::{ + cli::{Cli, CliCommand}, + monitors::get_monitors_str, + providers::{config::ProviderConfig, manager::ProviderManager}, + sys_tray::setup_sys_tray, +}; mod cli; mod monitors; mod providers; +mod sys_tray; mod user_config; mod util; @@ -110,7 +114,7 @@ async fn main() { tauri::async_runtime::set(tokio::runtime::Handle::current()); - let app = tauri::Builder::default() + tauri::Builder::default() .setup(|app| { let cli = Cli::parse(); @@ -146,6 +150,9 @@ async fn main() { app.handle().plugin(tauri_plugin_http::init())?; app.handle().plugin(tauri_plugin_dialog::init())?; + // Add application icon to system tray. + setup_sys_tray(app)?; + providers::manager::init(app)?; let args_map = OpenWindowArgsMap(Default::default()); diff --git a/packages/desktop/src/sys_tray.rs b/packages/desktop/src/sys_tray.rs new file mode 100644 index 00000000..36612ab7 --- /dev/null +++ b/packages/desktop/src/sys_tray.rs @@ -0,0 +1,43 @@ +use anyhow::Context; +use tauri::{ + menu::MenuBuilder, + tray::{TrayIcon, TrayIconBuilder}, +}; +use tracing::{error, info}; + +use crate::user_config::open_config_dir; + +pub fn setup_sys_tray(app: &mut tauri::App) -> anyhow::Result { + let icon_image = app + .default_window_icon() + .context("No icon defined in Tauri config.")?; + + let tray_menu = MenuBuilder::new(app) + .text("show_config_folder", "Show config folder") + .separator() + .text("exit", "Exit") + .build()?; + + let tray_icon = TrayIconBuilder::with_id("tray") + .icon(icon_image.clone()) + .menu(&tray_menu) + .tooltip(format!("Zebar v{}", env!("VERSION_NUMBER"))) + .on_menu_event(move |app, event| match event.id().as_ref() { + "show_config_folder" => { + info!("Opening config folder from system tray."); + if let Err(err) = open_config_dir(app) { + error!("Failed to open config folder: {}", err); + } + } + "exit" => { + info!("Exiting through system tray."); + app.exit(0) + } + other => { + error!("Unknown menu event: {}", other); + } + }) + .build(app)?; + + Ok(tray_icon) +} diff --git a/packages/desktop/src/user_config.rs b/packages/desktop/src/user_config.rs index 71108f69..291f618b 100644 --- a/packages/desktop/src/user_config.rs +++ b/packages/desktop/src/user_config.rs @@ -53,23 +53,24 @@ fn create_from_sample( Ok(()) } -pub fn open_config_dir(app_handle: AppHandle) -> anyhow::Result<()> { - let config_dir_path = app_handle +pub fn open_config_dir(app_handle: &AppHandle) -> anyhow::Result<()> { + let dir_path = app_handle .path() .resolve(".glzr/zebar", BaseDirectory::Home) - .context("Unable to get home directory.")?; + .context("Unable to get home directory.")? + .canonicalize()?; #[cfg(target_os = "windows")] { std::process::Command::new("explorer") - .arg(config_dir_path) + .arg(dir_path) .spawn()?; } #[cfg(target_os = "macos")] { std::process::Command::new("open") - .arg(config_dir_path) + .arg(dir_path) .arg("-R") .spawn()?; } @@ -77,7 +78,7 @@ pub fn open_config_dir(app_handle: AppHandle) -> anyhow::Result<()> { #[cfg(target_os = "linux")] { std::process::Command::new("xdg-open") - .arg(config_dir_path) + .arg(dir_path) .spawn()?; }