#[macro_use] mod err; mod pack; pub use err::*; use libappindicator::*; use gtk::prelude::*; use pack::*; use std::cell::RefCell; use std::time::{Duration, Instant}; use sysinfo::*; use include_dir::{include_dir, Dir}; static EMBEDDED_RES: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/res"); thread_local! { static SYSTEM: RefCell = RefCell::new(System::new_all()); } fn update_frame_time() -> Duration { return SYSTEM.with(|system| { let mut system = system.borrow_mut(); system.refresh_cpu_specifics(CpuRefreshKind::new().with_cpu_usage()); let num_cpus = system.cpus().len(); let load: f32 = system.cpus().iter() .map(|cpu| cpu.cpu_usage() / num_cpus as f32) .sum(); return Duration::from_millis(10 + 2 * load as u64); // min 10 (~100Hz), max 210 (~5Hz) }) } fn init_indicator(icon_pack: &IconPack) -> AppIndicator { let mut indicator = AppIndicator::new("parrotd", ""); indicator.set_icon_theme_path(icon_pack.pack_path()); indicator.set_status(AppIndicatorStatus::Active); let mut m = gtk::Menu::new(); let mi = gtk::CheckMenuItem::with_label("Exit"); mi.connect_activate(|_| { gtk::main_quit(); }); m.append(&mi); let mi = gtk::CheckMenuItem::with_label("Parrotd by PeterCxy"); m.append(&mi); indicator.set_menu(&mut m); m.show_all(); return indicator; } fn main() { gtk::init().unwrap(); let tmp_dir = tempfile::tempdir(); let _tmp_dir = tmp_dir.as_ref(); let res_dir = std::env::var("PARROTD_RESOURCE_DIR").unwrap_or_else(|_| { let tmp_dir = _tmp_dir.expect("Cannot create temporary directory"); EMBEDDED_RES.extract(tmp_dir.path()).unwrap(); tmp_dir.path().to_str().unwrap().to_string() }); let pack_name = std::env::var("PARROTD_ICON_PACK").unwrap_or("parrot".to_owned()); let variant = PackVariant::parse( &std::env::var("PARROTD_VARIANT").unwrap_or("dark".to_owned())).expect("Invalid variant name"); let mut icon_pack = IconPack::new(res_dir, &pack_name, variant).unwrap(); let mut indicator = init_indicator(&icon_pack); // Animation task let mut last_update = Instant::now(); let mut last_update_frame_time = Instant::now(); let mut frame_time = update_frame_time(); glib::timeout_add_local(Duration::from_millis(1) /* we need granularity */, move || { let now = Instant::now(); if now - last_update_frame_time >= Duration::from_millis(100) { // Update frame time frame_time = update_frame_time(); last_update_frame_time = now; } if now - last_update >= frame_time { // Update animation indicator.set_icon(icon_pack.next_icon_path()); last_update = now; } Continue(true) }); gtk::main(); if let Ok(tmp_dir) = tmp_dir { tmp_dir.close().unwrap(); } }