From c3b02a2bb0a3ef203d7c1db9128ab9c2efc76602 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sat, 24 Feb 2024 22:49:10 +1300 Subject: [PATCH] Fix the IPC --- asusd/src/daemon.rs | 2 - rog-aura/src/layouts.rs | 2 +- rog-control-center/src/lib.rs | 17 ++- rog-control-center/src/main.rs | 156 ++++++++----------------- rog-control-center/src/system_state.rs | 97 +++++++++++---- 5 files changed, 134 insertions(+), 140 deletions(-) diff --git a/asusd/src/daemon.rs b/asusd/src/daemon.rs index f7885f53..9e2aa81a 100644 --- a/asusd/src/daemon.rs +++ b/asusd/src/daemon.rs @@ -2,7 +2,6 @@ use std::env; use std::error::Error; use std::io::Write; use std::sync::Arc; -use std::time::Duration; use ::zbus::export::futures_util::lock::Mutex; use ::zbus::Connection; @@ -18,7 +17,6 @@ use asusd::{print_board_info, CtrlTask, Reloadable, ZbusRun, DBUS_NAME}; use config_traits::{StdConfig, StdConfigLoad2, StdConfigLoad3}; use log::{error, info, warn}; use rog_aura::aura_detection::LaptopLedData; -use tokio::time::sleep; use zbus::SignalContext; #[tokio::main] diff --git a/rog-aura/src/layouts.rs b/rog-aura/src/layouts.rs index d7900eba..086c68ba 100644 --- a/rog-aura/src/layouts.rs +++ b/rog-aura/src/layouts.rs @@ -189,7 +189,7 @@ pub struct KeyLayout { } impl KeyLayout { - pub fn from_file(path: &Path) -> Result { + fn from_file(path: &Path) -> Result { let buf: String = std::fs::read_to_string(path) .map_err(|e| Error::IoPath(path.to_string_lossy().to_string(), e))?; if buf.is_empty() { diff --git a/rog-control-center/src/lib.rs b/rog-control-center/src/lib.rs index 9e65cec0..c57c4617 100644 --- a/rog-control-center/src/lib.rs +++ b/rog-control-center/src/lib.rs @@ -32,6 +32,13 @@ use tempfile::TempDir; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +#[cfg(not(feature = "mocking"))] +const DATA_DIR: &str = "/usr/share/rog-gui/"; +#[cfg(feature = "mocking")] +const DATA_DIR: &str = env!("CARGO_MANIFEST_DIR"); +const BOARD_NAME: &str = "/sys/class/dmi/id/board_name"; +pub const APP_ICON_PATH: &str = "/usr/share/icons/hicolor/512x512/apps/rog-control-center.png"; + pub fn print_versions() { println!("App and daemon versions:"); println!(" rog-gui v{}", VERSION); @@ -59,7 +66,7 @@ pub enum Page { /// Either exit the process, or return with a refreshed tmp-dir pub fn on_tmp_dir_exists() -> Result { - let mut buf = [0u8; 4]; + let mut buf = [0u8; 2]; let path = std::env::temp_dir().join("rog-gui"); if path.read_dir()?.next().is_none() { @@ -77,15 +84,15 @@ pub fn on_tmp_dir_exists() -> Result { .open(path.join("ipc.pipe"))?; // If the app is running this ends up stacked on top of SHOWING_GUI - ipc_file.write_all(&[SHOW_GUI])?; + ipc_file.write_all(&[SHOW_GUI, 0])?; // tiny sleep to give the app a chance to respond - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(10)); ipc_file.read(&mut buf).ok(); // First entry is the actual state if buf[0] == SHOWING_GUI { - ipc_file.write_all(&[SHOWING_GUI])?; // Store state again as we drained the fifo - // Early exit is not an error and we don't want to pass back a dir + ipc_file.write_all(&[SHOWING_GUI, 0])?; // Store state again as we drained the fifo + // Early exit is not an error and we don't want to pass back a dir #[allow(clippy::exit)] exit(0); } else if buf[0] == SHOW_GUI { diff --git a/rog-control-center/src/main.rs b/rog-control-center/src/main.rs index 9125cb07..efc7475b 100644 --- a/rog-control-center/src/main.rs +++ b/rog-control-center/src/main.rs @@ -7,14 +7,12 @@ use std::thread::{self, sleep, spawn}; use std::time::Duration; use gumdrop::Options; -use log::{warn, LevelFilter}; -use rog_aura::aura_detection::{LaptopLedData, LedSupportFile}; -use rog_aura::layouts::KeyLayout; +use log::LevelFilter; use rog_control_center::cli_options::CliStart; use rog_control_center::config::Config; use rog_control_center::error::Result; use rog_control_center::slint::ComponentHandle; -use rog_control_center::system_state::SystemState; +use rog_control_center::system_state::{AuraCreation, SystemState}; use rog_control_center::tray::init_tray; use rog_control_center::update_and_notify::{start_notifications, EnabledNotifications}; use rog_control_center::{ @@ -25,15 +23,17 @@ use tokio::runtime::Runtime; // use winit::monitor::VideoMode; // use winit::window::{Fullscreen, WindowLevel}; -#[cfg(not(feature = "mocking"))] -const DATA_DIR: &str = "/usr/share/rog-gui/"; -#[cfg(feature = "mocking")] -const DATA_DIR: &str = env!("CARGO_MANIFEST_DIR"); -const BOARD_NAME: &str = "/sys/class/dmi/id/board_name"; -// const APP_ICON_PATH: &str = -// "/usr/share/icons/hicolor/512x512/apps/rog-control-center.png"; - fn main() -> Result<()> { + // tmp-dir must live to the end of program life + let _tmp_dir = match tempfile::Builder::new() + .prefix("rog-gui") + .rand_bytes(0) + .tempdir() + { + Ok(tmp) => tmp, + Err(_) => on_tmp_dir_exists().unwrap(), + }; + let args: Vec = args().skip(1).collect(); let cli_parsed = match CliStart::parse_args_default(&args) { @@ -81,110 +81,46 @@ fn main() -> Result<()> { config.run_in_background = true; let tmp = config.enabled_notifications.clone(); // ends up being a double clone, oh well. config.save(&tmp)?; + } else { + get_ipc_file().unwrap().write_all(&[SHOW_GUI, 0]).unwrap(); } + let enabled_notifications = EnabledNotifications::tokio_mutex(&config); + let aura_creation = AuraCreation::new(cli_parsed.board_name, cli_parsed.layout_viewing)?; - // Find and load a matching layout for laptop - let mut board_name = std::fs::read_to_string(BOARD_NAME).map_err(|e| { - println!("DOH! {BOARD_NAME}, {e}"); - e - })?; - - let mut led_support = LaptopLedData::get_data(); - - let mut path = PathBuf::from(DATA_DIR); - let mut layout_name = None; - let mut layouts = Vec::new(); - if cli_parsed.board_name.is_some() || cli_parsed.layout_viewing { - if cfg!(feature = "mocking") { - path.pop(); - path.push("rog-aura"); - path.push("data"); - } - layouts = KeyLayout::layout_files(path.clone()).unwrap(); - - if let Some(name) = &cli_parsed.board_name { - if let Some(modes) = LedSupportFile::load_from_supoprt_db() { - if let Some(data) = modes.matcher(name) { - led_support = data; - } - } - board_name = name.clone(); - for layout in &layouts { - if layout - .file_name() - .unwrap() - .to_string_lossy() - .contains(&led_support.layout_name.to_lowercase()) - { - layout_name = Some(layout.clone()); - } - } - } else { - board_name = "GQ401QM".to_owned(); - }; - - if cli_parsed.layout_viewing { - layout_name = Some(layouts[0].clone()); - board_name = layouts[0] - .file_name() - .unwrap() - .to_string_lossy() - .split_once('_') - .unwrap() - .0 - .to_owned(); - led_support.layout_name = board_name.clone(); - } - } - - let layout = KeyLayout::find_layout(led_support, path) - .map_err(|e| { - println!("DERP! , {e}"); - }) - .unwrap_or_else(|_| { - warn!("Did not find a keyboard layout matching {board_name}"); - KeyLayout::default_layout() - }); - - // tmp-dir must live to the end of program life - let _tmp_dir = match tempfile::Builder::new() - .prefix("rog-gui") - .rand_bytes(0) - .tempdir() - { - Ok(tmp) => tmp, - Err(_) => on_tmp_dir_exists().unwrap(), - }; - dbg!(); - - let states = setup_page_state_and_notifs( - layout_name, - layout, - layouts, - &enabled_notifications, - &config, - )?; + // TODO: config mutex to share config in various places + let states = setup_page_state_and_notifs(aura_creation, &enabled_notifications, &config)?; if config.enable_tray_icon { init_tray(supported_properties, states.clone()); } - dbg!(); thread_local! { pub static UI: std::cell::RefCell> = Default::default()}; i_slint_backend_selector::with_platform(|_| Ok(())).unwrap(); - dbg!(); + let mut do_once = !config.startup_in_background; thread::spawn(move || { let mut buf = [0u8; 2]; // blocks until it is read, typically the read will happen after a second // process writes to the IPC (so there is data to actually read) loop { - get_ipc_file().unwrap().read_exact(&mut buf).unwrap(); + if do_once { + buf[0] = SHOW_GUI; + do_once = false; + } else { + get_ipc_file().unwrap().read_exact(&mut buf).unwrap(); + } + if buf[0] == SHOW_GUI { println!("Should show window {buf:?}"); - let mut ipc_file = get_ipc_file().unwrap(); - ipc_file.write_all(&[SHOWING_GUI, 0]).unwrap(); + // There's a balancing act with read/write timing of IPC, there needs to be a + // small sleep after this to give any other process a chance to + // read the IPC before looping + get_ipc_file() + .unwrap() + .write_all(&[SHOWING_GUI, 0]) + .unwrap(); + sleep(Duration::from_millis(50)); let states = states.clone(); i_slint_core::api::invoke_from_event_loop(move || { @@ -193,8 +129,7 @@ fn main() -> Result<()> { if let Some(ui) = ui.as_mut() { ui.window().show().unwrap(); ui.window().on_close_requested(|| { - let mut ipc_file = get_ipc_file().unwrap(); - ipc_file.write_all(&[0, 0]).unwrap(); + get_ipc_file().unwrap().write_all(&[0, 0]).unwrap(); slint::CloseRequestResponse::HideWindow }); } else { @@ -202,8 +137,7 @@ fn main() -> Result<()> { newui.window().show().unwrap(); println!("New window should be showing now"); // but it isn't newui.window().on_close_requested(|| { - let mut ipc_file = get_ipc_file().unwrap(); - ipc_file.write_all(&[0, 0]).unwrap(); + get_ipc_file().unwrap().write_all(&[0, 0]).unwrap(); slint::CloseRequestResponse::HideWindow }); ui.replace(newui); @@ -214,6 +148,12 @@ fn main() -> Result<()> { } else if buf[1] == QUIT_APP { slint::quit_event_loop().unwrap(); } else if buf[0] != SHOWING_GUI { + Config::load().unwrap(); + if !config.run_in_background { + slint::quit_event_loop().unwrap(); + return; + } + println!("Should hide window {buf:?}"); i_slint_core::api::invoke_from_event_loop(move || { UI.with(|ui| { @@ -268,16 +208,12 @@ fn setup_window(_states: Arc>) -> MainWindow { } fn setup_page_state_and_notifs( - layout_testing: Option, - keyboard_layout: KeyLayout, - keyboard_layouts: Vec, + aura_creation: AuraCreation, enabled_notifications: &Arc>, config: &Config, ) -> Result>> { let page_states = Arc::new(Mutex::new(SystemState::new( - layout_testing, - keyboard_layout, - keyboard_layouts, + aura_creation, enabled_notifications.clone(), config.enable_tray_icon, config.run_in_background, @@ -288,8 +224,8 @@ fn setup_page_state_and_notifs( Ok(page_states) } -/// Bah.. the icon dosn't work on wayland anyway, but we'll leave it in for now. -// fn load_icon() -> IconData { +// /// Bah.. the icon dosn't work on wayland anyway, but we'll leave it in for +// now. fn load_icon() -> IconData { // let path = PathBuf::from(APP_ICON_PATH); // let mut rgba = Vec::new(); // let mut height = 512; diff --git a/rog-control-center/src/system_state.rs b/rog-control-center/src/system_state.rs index a85a9a7c..e4e1fa65 100644 --- a/rog-control-center/src/system_state.rs +++ b/rog-control-center/src/system_state.rs @@ -3,8 +3,9 @@ use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::time::SystemTime; -use log::error; +use log::{error, warn}; use rog_anime::{Animations, DeviceState}; +use rog_aura::aura_detection::{LaptopLedData, LedSupportFile}; use rog_aura::layouts::KeyLayout; use rog_aura::usb::AuraPowerDev; use rog_aura::{AuraEffect, AuraModeNum, LedBrightness}; @@ -19,7 +20,7 @@ use crate::error::Result; #[cfg(feature = "mocking")] use crate::mocking::DaemonProxyBlocking as GfxProxyBlocking; use crate::update_and_notify::EnabledNotifications; -use crate::RogDbusClientBlocking; +use crate::{RogDbusClientBlocking, BOARD_NAME, DATA_DIR}; #[derive(Clone, Debug, Default)] pub struct PlatformState { @@ -121,10 +122,7 @@ impl AuraState { pub fn new(layout: &KeyLayout, dbus: &RogDbusClientBlocking<'_>) -> Result { Ok(Self { current_mode: if !layout.basic_modes().is_empty() { - dbg!(); - let x = dbus.proxies().aura().led_mode().unwrap_or_default(); - dbg!(); - x + dbus.proxies().aura().led_mode().unwrap_or_default() } else { AuraModeNum::Static }, @@ -215,6 +213,7 @@ impl Default for GfxState { } } +/// The keyboard layout, used for such things as per-key and zones #[derive(Clone, Debug)] pub struct AuraCreation { /// Specifically for testing the development of keyboard layouts (combined @@ -228,18 +227,78 @@ pub struct AuraCreation { } impl AuraCreation { - pub fn new( - layout_testing: Option, - keyboard_layout: KeyLayout, - keyboard_layouts: Vec, - ) -> Self { - Self { + pub fn new(test_name: Option, view_layout: bool) -> Result { + let mut led_support = LaptopLedData::get_data(); + + let mut path = PathBuf::from(DATA_DIR); + let mut layout_testing = None; + let mut keyboard_layouts = Vec::new(); + + // Find and load a matching layout for laptop + let mut board_name = std::fs::read_to_string(BOARD_NAME).map_err(|e| { + println!("DOH! {BOARD_NAME}, {e}"); + e + })?; + + if test_name.is_some() || view_layout { + if cfg!(feature = "mocking") { + path.pop(); + path.push("rog-aura"); + path.push("data"); + } + keyboard_layouts = KeyLayout::layout_files(path.clone()).unwrap(); + + if let Some(name) = test_name { + if let Some(modes) = LedSupportFile::load_from_supoprt_db() { + if let Some(data) = modes.matcher(&name) { + led_support = data; + } + } + board_name = name; + for layout in &keyboard_layouts { + if layout + .file_name() + .unwrap() + .to_string_lossy() + .contains(&led_support.layout_name.to_lowercase()) + { + layout_testing = Some(layout.clone()); + } + } + } else { + board_name = "GQ401QM".to_owned(); + }; + + if view_layout { + layout_testing = Some(keyboard_layouts[0].clone()); + board_name = keyboard_layouts[0] + .file_name() + .unwrap() + .to_string_lossy() + .split_once('_') + .unwrap() + .0 + .to_owned(); + led_support.layout_name = board_name.clone(); + } + } + + let keyboard_layout = KeyLayout::find_layout(led_support, path) + .map_err(|e| { + println!("DERP! , {e}"); + }) + .unwrap_or_else(|_| { + warn!("Did not find a keyboard layout matching {board_name}"); + KeyLayout::default_layout() + }); + + Ok(Self { layout_testing, layout_last_modified: SystemTime::now(), keyboard_layout, keyboard_layouts, keyboard_layout_index: 0, - } + }) } } @@ -271,31 +330,25 @@ impl SystemState { /// Creates self, including the relevant dbus connections and proixies for /// internal use pub fn new( - layout_testing: Option, - keyboard_layout: KeyLayout, - keyboard_layouts: Vec, + aura_creation: AuraCreation, enabled_notifications: Arc>, tray_enabled: bool, run_in_bg: bool, ) -> Result { - dbg!(); let (asus_dbus, conn) = RogDbusClientBlocking::new()?; - dbg!(); - let aura = AuraState::new(&keyboard_layout, &asus_dbus) + let aura = AuraState::new(&aura_creation.keyboard_layout, &asus_dbus) .map_err(|e| { let e = format!("Could not get AuraState state: {e}"); error!("{e}"); }) .unwrap_or_default(); - dbg!(); let gfx_dbus = GfxProxyBlocking::builder(&conn) .destination(":org.supergfxctl.Daemon")? .build() .expect("Couldn't connect to supergfxd"); - dbg!(); Ok(Self { - aura_creation: AuraCreation::new(layout_testing, keyboard_layout, keyboard_layouts), + aura_creation, enabled_notifications, bios: PlatformState::new(&asus_dbus) .map_err(|e| {