diff --git a/rog-control-center/src/tray.rs b/rog-control-center/src/tray.rs new file mode 100644 index 00000000..2d218b2d --- /dev/null +++ b/rog-control-center/src/tray.rs @@ -0,0 +1,75 @@ +//! A seld-contained tray icon with menus. The control of app<->tray is done via +//! commands over an MPSC channel. + +use std::{ + sync::{ + mpsc::{channel, Receiver}, + Arc, Mutex, + }, + time::Duration, + io::Write, +}; + +use supergfxctl::pci_device::GfxPower; +use tray_item::TrayItem; +use crate::{SHOW_GUI, get_ipc_file}; + +pub enum AppToTray { + DgpuStatus(GfxPower), +} + +pub enum TrayToApp { + Open, + Quit, +} + +pub fn init_tray(recv_command: Receiver) -> Receiver { + let (send, recv) = channel(); + let send = Arc::new(Mutex::new(send)); + + std::thread::spawn(move || { + gtk::init().unwrap(); // Make this the main thread for gtk + + let mut tray = TrayItem::new("ROG Control Center", "rog-control-center").unwrap(); + + tray.add_menu_item("Open app", move || { + get_ipc_file().unwrap().write_all(&[SHOW_GUI]).ok(); + }) + .ok(); + + let s1 = send.clone(); + tray.add_menu_item("Quit", move || { + let lock = s1.lock().unwrap(); + lock.send(TrayToApp::Quit).ok(); + }) + .ok(); + + loop { + if let Ok(command) = recv_command.try_recv() { + match command { + AppToTray::DgpuStatus(s) => { + match s { + GfxPower::Active => tray.set_icon("gpu-nvidia"), + GfxPower::Suspended => tray.set_icon("gpu-integrated"), + GfxPower::Off => tray.set_icon("rog-control-center"), + GfxPower::AsusDisabled => tray.set_icon("gpu-integrated"), + GfxPower::AsusMuxDiscreet => tray.set_icon("gpu-nvidia"), + GfxPower::Unknown => tray.set_icon("gpu-integrated"), + } + .ok(); + } + } + } + + if gtk::events_pending() { + // This is blocking until any events are available + gtk::main_iteration(); + } else { + // Don't spool at max speed if no gtk events + std::thread::sleep(Duration::from_millis(300)); + } + } + }); + + recv +}