From 0a4c10de34f7951f1233b71abcc6558802fc6ae7 Mon Sep 17 00:00:00 2001 From: xzeldon Date: Fri, 6 Sep 2024 02:06:53 +0300 Subject: [PATCH] refactor: improve tray icon/menu implementation. --- src/main.rs | 1 - src/tray.rs | 111 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 65 insertions(+), 47 deletions(-) diff --git a/src/main.rs b/src/main.rs index 49dac28..4b65c9d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,7 +27,6 @@ fn main() { // Hide the console window winuser::ShowWindow(wincon::GetConsoleWindow(), winuser::SW_HIDE); } - std::env::set_var("RUST_LOG", "trace"); pretty_env_logger::init(); diff --git a/src/tray.rs b/src/tray.rs index dfc2aa6..a94d348 100644 --- a/src/tray.rs +++ b/src/tray.rs @@ -12,7 +12,10 @@ use tray_icon::{ menu::{Menu, MenuEvent, MenuItem}, TrayIcon, TrayIconBuilder, }; -use winapi::um::{wincon::GetConsoleWindow, winuser::{self, ShowWindow, SW_SHOW}}; +use winapi::um::{ + wincon::GetConsoleWindow, + winuser::{self, ShowWindow, SW_SHOW}, +}; const BATTERY_UPDATE_INTERVAL: std::time::Duration = std::time::Duration::from_secs(60); const DEVICE_FETCH_INTERVAL: std::time::Duration = std::time::Duration::from_secs(5); @@ -39,12 +42,59 @@ impl MemoryDevice { } } +pub struct TrayInner { + tray_icon: Rc>>, + console_state: Arc>, + menu_items: Arc>>, +} + +impl TrayInner { + fn new() -> Self { + Self { + tray_icon: Rc::new(Mutex::new(None)), + console_state: Arc::new(Mutex::new(false)), + menu_items: Arc::new(Mutex::new(Vec::new())), + } + } + + fn create_menu(&self) -> Menu { + let tray_menu = Menu::new(); + + let show_console_item = MenuItem::new("Show Log Window", true, None); + let quit_item = MenuItem::new("Exit", true, None); + + let mut menu_items = self.menu_items.lock().unwrap(); + menu_items.push(show_console_item); + menu_items.push(quit_item); + + tray_menu + .append_items(&[&menu_items[0], &menu_items[1]]) + .unwrap(); + tray_menu + } + + fn build_tray( + tray_icon: &Rc>>, + tray_menu: &Menu, + icon: tray_icon::Icon, + ) { + let tray_builder = TrayIconBuilder::new() + .with_menu(Box::new(tray_menu.clone())) + .with_tooltip("Service is running") + .with_icon(icon) + .build(); + + match tray_builder { + Ok(tray) => *tray_icon.lock().unwrap() = Some(tray), + Err(err) => error!("Failed to create tray icon: {}", err), + } + } +} + pub struct TrayApp { device_manager: Arc>, devices: Arc>>, - tray_icon: Rc>>, - console_state: Arc>, - menu_items: Arc>> + tray_inner: TrayInner, } impl TrayApp { @@ -52,16 +102,14 @@ impl TrayApp { Self { device_manager: Arc::new(Mutex::new(DeviceManager::new())), devices: Arc::new(Mutex::new(HashMap::new())), - tray_icon: Rc::new(Mutex::new(None)), - console_state: Arc::new(Mutex::new(false)), - menu_items: Arc::new(Mutex::new(Vec::new())) + tray_inner: TrayInner::new(), } } pub fn run(&self) { let icon = Self::create_icon(); let event_loop = EventLoopBuilder::new().build(); - let tray_menu = self.create_menu(); + let tray_menu = self.tray_inner.create_menu(); let (sender, receiver) = mpsc::channel(); @@ -82,20 +130,6 @@ impl TrayApp { tray_icon::Icon::from_rgba(rgba, width, height).expect("Failed to create icon") } - fn create_menu(&self) -> Menu { - let tray_menu = Menu::new(); - - let show_console_item = MenuItem::new("Show Log Window", true, None); - let quit_item = MenuItem::new("Exit", true, None); - - let mut menu_items = self.menu_items.lock().unwrap(); - menu_items.push(show_console_item); - menu_items.push(quit_item); - - tray_menu.append_items(&[&menu_items[0], &menu_items[1]]).unwrap(); - tray_menu - } - fn spawn_device_fetch_thread(&self, tx: mpsc::Sender>) { let devices = Arc::clone(&self.devices); let device_manager = Arc::clone(&self.device_manager); @@ -125,7 +159,7 @@ impl TrayApp { } } } - + if !connected_devices.is_empty() { tx.send(connected_devices).unwrap(); } @@ -151,11 +185,11 @@ impl TrayApp { tray_menu: Menu, rx: mpsc::Receiver>, ) { - let tray_icon = Rc::clone(&self.tray_icon); let devices = Arc::clone(&self.devices); let device_manager = Arc::clone(&self.device_manager); - let console_state = Arc::clone(&self.console_state); - let menu_items = Arc::clone(&self.menu_items); + let tray_icon = Rc::clone(&self.tray_inner.tray_icon); + let console_state = Arc::clone(&self.tray_inner.console_state); + let menu_items = Arc::clone(&self.tray_inner.menu_items); let menu_channel = MenuEvent::receiver(); @@ -169,7 +203,9 @@ impl TrayApp { } if let tao::event::Event::NewEvents(tao::event::StartCause::Init) = event { - Self::build_tray(&tray_icon, &tray_menu, icon.clone()); + // We create the icon once the event loop is actually running + // to prevent issues like https://github.com/tauri-apps/tray-icon/issues/90 + TrayInner::build_tray(&tray_icon, &tray_menu, icon.clone()); } if let Ok(event) = menu_channel.try_recv() { @@ -182,12 +218,12 @@ impl TrayApp { let mut visible = console_state.lock().unwrap(); if *visible { - unsafe {ShowWindow(GetConsoleWindow(), winuser::SW_HIDE)}; + unsafe { ShowWindow(GetConsoleWindow(), winuser::SW_HIDE) }; show_console_item.set_text("Show Log Window"); trace!("hiding log window"); *visible = false; } else { - unsafe {ShowWindow(GetConsoleWindow(), SW_SHOW)}; + unsafe { ShowWindow(GetConsoleWindow(), SW_SHOW) }; show_console_item.set_text("Hide Log Window"); trace!("showing log window"); *visible = true @@ -201,23 +237,6 @@ impl TrayApp { }); } - fn build_tray( - tray_icon: &Rc>>, - tray_menu: &Menu, - icon: tray_icon::Icon, - ) { - let tray_builder = TrayIconBuilder::new() - .with_menu(Box::new(tray_menu.clone())) - .with_tooltip("Service is running") - .with_icon(icon) - .build(); - - match tray_builder { - Ok(tray) => *tray_icon.lock().unwrap() = Some(tray), - Err(err) => error!("Failed to create tray icon: {}", err), - } - } - fn update( devices: &Arc>>, manager: &Arc>,