diff --git a/CHANGELOG.md b/CHANGELOG.md index 66866193..b96d239e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [v4.5.4] +### Changed +- ROGCC:: Allow ROGCC to run without supergfxd +- ROGCC: Tray/notifs now reads dGPU status directly via supergfx crate (supergfxd not required) +- Add rust-toolchain to force minimum rust version + ## [v4.5.3] ### Changed - Adjust how fan graph in ROGCC works, deny incorrect graphs diff --git a/Cargo.lock b/Cargo.lock index d636f18d..bcdd9119 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,7 +149,7 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "asusctl" -version = "4.5.3" +version = "4.5.4" dependencies = [ "daemon", "gif", @@ -727,7 +727,7 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "daemon" -version = "4.5.3" +version = "4.5.4" dependencies = [ "async-trait", "concat-idents", @@ -750,7 +750,7 @@ dependencies = [ [[package]] name = "daemon-user" -version = "4.5.3" +version = "4.5.4" dependencies = [ "dirs", "rog_anime", @@ -2593,7 +2593,7 @@ dependencies = [ [[package]] name = "rog-control-center" -version = "4.5.3" +version = "4.5.4" dependencies = [ "daemon", "dirs", @@ -2624,7 +2624,7 @@ dependencies = [ [[package]] name = "rog_anime" -version = "4.5.3" +version = "4.5.4" dependencies = [ "gif", "glam", @@ -2639,7 +2639,7 @@ dependencies = [ [[package]] name = "rog_aura" -version = "4.5.3" +version = "4.5.4" dependencies = [ "serde", "serde_derive", @@ -2650,7 +2650,7 @@ dependencies = [ [[package]] name = "rog_dbus" -version = "4.5.3" +version = "4.5.4" dependencies = [ "rog_anime", "rog_aura", @@ -2661,7 +2661,7 @@ dependencies = [ [[package]] name = "rog_platform" -version = "4.5.3" +version = "4.5.4" dependencies = [ "concat-idents", "inotify", @@ -2677,7 +2677,7 @@ dependencies = [ [[package]] name = "rog_profiles" -version = "4.5.3" +version = "4.5.4" dependencies = [ "serde", "serde_derive", diff --git a/Cargo.toml b/Cargo.toml index 05f5b24e..ce6d7889 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ members = ["asusctl", "daemon", "daemon-user", "rog-platform", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles", "rog-control-center"] [workspace.package] -version = "4.5.3" +version = "4.5.4" [workspace.dependencies] async-trait = "^0.1" diff --git a/rog-control-center/src/config.rs b/rog-control-center/src/config.rs index 568dd081..98614856 100644 --- a/rog-control-center/src/config.rs +++ b/rog-control-center/src/config.rs @@ -6,7 +6,7 @@ use std::{ }; //use log::{error, info, warn}; -use crate::{error::Error, notify::EnabledNotifications}; +use crate::{error::Error, update_and_notify::EnabledNotifications}; const CFG_DIR: &str = "rog"; const CFG_FILE_NAME: &str = "rog-control-center.cfg"; diff --git a/rog-control-center/src/lib.rs b/rog-control-center/src/lib.rs index b705a6b6..799a9d26 100644 --- a/rog-control-center/src/lib.rs +++ b/rog-control-center/src/lib.rs @@ -13,11 +13,11 @@ pub mod config; pub mod error; #[cfg(feature = "mocking")] pub mod mocking; -pub mod notify; pub mod pages; pub mod startup_error; pub mod system_state; pub mod tray; +pub mod update_and_notify; pub mod widgets; #[cfg(feature = "mocking")] diff --git a/rog-control-center/src/main.rs b/rog-control-center/src/main.rs index 414f5aea..5b90e6d5 100644 --- a/rog-control-center/src/main.rs +++ b/rog-control-center/src/main.rs @@ -1,12 +1,12 @@ use eframe::{IconData, NativeOptions}; use log::{error, info, LevelFilter}; use rog_aura::layouts::KeyLayout; -use rog_control_center::notify::EnabledNotifications; use rog_control_center::tray::init_tray; +use rog_control_center::update_and_notify::EnabledNotifications; use rog_control_center::{ - config::Config, error::Result, get_ipc_file, notify::start_notifications, on_tmp_dir_exists, - print_versions, startup_error::AppErrorShow, system_state::SystemState, RogApp, - RogDbusClientBlocking, SHOWING_GUI, SHOW_GUI, + config::Config, error::Result, get_ipc_file, on_tmp_dir_exists, print_versions, + startup_error::AppErrorShow, system_state::SystemState, update_and_notify::start_notifications, + RogApp, RogDbusClientBlocking, SHOWING_GUI, SHOW_GUI, }; use rog_platform::supported::SupportedFunctions; use std::sync::Mutex; diff --git a/rog-control-center/src/notify.rs b/rog-control-center/src/notify.rs deleted file mode 100644 index 5e6500f6..00000000 --- a/rog-control-center/src/notify.rs +++ /dev/null @@ -1,461 +0,0 @@ -use crate::{config::Config, error::Result, system_state::SystemState}; -use log::{error, info, trace}; -use notify_rust::{Hint, Notification, NotificationHandle, Urgency}; -use rog_dbus::{ - zbus_anime::AnimeProxy, zbus_led::LedProxy, zbus_platform::RogBiosProxy, - zbus_power::PowerProxy, zbus_profile::ProfileProxy, -}; -use rog_platform::platform::GpuMode; -use rog_profiles::Profile; -use serde::{Deserialize, Serialize}; -use std::{ - fmt::Display, - process::Command, - sync::{Arc, Mutex}, -}; -use supergfxctl::{pci_device::GfxPower, zbus_proxy::DaemonProxy as SuperProxy}; -use zbus::export::futures_util::{future, StreamExt}; - -const NOTIF_HEADER: &str = "ROG Control"; - -#[derive(Debug, Clone, Deserialize, Serialize)] -#[serde(default)] -pub struct EnabledNotifications { - pub receive_notify_post_boot_sound: bool, - pub receive_notify_panel_od: bool, - pub receive_notify_dgpu_disable: bool, - pub receive_notify_egpu_enable: bool, - pub receive_notify_gpu_mux_mode: bool, - pub receive_notify_charge_control_end_threshold: bool, - pub receive_notify_mains_online: bool, - pub receive_notify_profile: bool, - pub receive_notify_led: bool, - /// Anime - pub receive_power_states: bool, - pub receive_notify_gfx: bool, - pub receive_notify_gfx_status: bool, - pub all_enabled: bool, -} - -impl Default for EnabledNotifications { - fn default() -> Self { - Self { - receive_notify_post_boot_sound: false, - receive_notify_panel_od: true, - receive_notify_dgpu_disable: true, - receive_notify_egpu_enable: true, - receive_notify_gpu_mux_mode: true, - receive_notify_charge_control_end_threshold: true, - receive_notify_mains_online: false, - receive_notify_profile: true, - receive_notify_led: false, - receive_power_states: false, - receive_notify_gfx: false, - receive_notify_gfx_status: false, - all_enabled: false, - } - } -} - -impl EnabledNotifications { - pub fn tokio_mutex(config: &Config) -> Arc> { - Arc::new(Mutex::new(config.enabled_notifications.clone())) - } -} - -macro_rules! notify { - ($notifier:expr, $last_notif:ident) => { - if let Some(notif) = $last_notif.take() { - notif.close(); - } - if let Ok(x) = $notifier { - $last_notif.replace(x); - } - }; -} - -// TODO: drop the macro and use generics plus closure -macro_rules! recv_notif { - ($proxy:ident, - $signal:ident, - $last_notif:ident, - $notif_enabled:ident, - $page_states:ident, - ($($args: tt)*), - ($($out_arg:tt)+), - $msg:literal, - $notifier:ident) => { - - let last_notif = $last_notif.clone(); - let notifs_enabled1 = $notif_enabled.clone(); - let page_states1 = $page_states.clone(); - - tokio::spawn(async move { - let conn = zbus::Connection::system().await.map_err(|e| { - log::error!("zbus signal: {}: {e}", stringify!($signal)); - e - }).unwrap(); - let proxy = $proxy::new(&conn).await.map_err(|e| { - log::error!("zbus signal: {}: {e}", stringify!($signal)); - e - }).unwrap(); - if let Ok(mut p) = proxy.$signal().await { - info!("Started zbus signal thread: {}", stringify!($signal)); - while let Some(e) = p.next().await { - if let Ok(out) = e.args() { - if let Ok(config) = notifs_enabled1.lock() { - if config.all_enabled && config.$signal { - if let Ok(ref mut lock) = last_notif.lock() { - trace!("zbus signal {} locked last_notif", stringify!($signal)); - notify!($notifier($msg, &out.$($out_arg)+()), lock); - } - } - } - if let Ok(mut lock) = page_states1.lock() { - lock.$($args)+ = *out.$($out_arg)+(); - lock.set_notified(); - } - } - } - }; - }); - }; -} - -type SharedHandle = Arc>>; - -pub fn start_notifications( - page_states: Arc>, - enabled_notifications: Arc>, -) -> Result<()> { - let last_notification: SharedHandle = Arc::new(Mutex::new(None)); - - // BIOS notif - recv_notif!( - RogBiosProxy, - receive_notify_post_boot_sound, - last_notification, - enabled_notifications, - page_states, - (bios.post_sound), - (on), - "BIOS Post sound", - do_notification - ); - - recv_notif!( - RogBiosProxy, - receive_notify_panel_od, - last_notification, - enabled_notifications, - page_states, - (bios.panel_overdrive), - (overdrive), - "Panel Overdrive enabled:", - do_notification - ); - - recv_notif!( - RogBiosProxy, - receive_notify_dgpu_disable, - last_notification, - enabled_notifications, - page_states, - (bios.dgpu_disable), - (disable), - "BIOS dGPU disabled", - do_notification - ); - - recv_notif!( - RogBiosProxy, - receive_notify_egpu_enable, - last_notification, - enabled_notifications, - page_states, - (bios.egpu_enable), - (enable), - "BIOS eGPU enabled", - do_notification - ); - - recv_notif!( - RogBiosProxy, - receive_notify_gpu_mux_mode, - last_notification, - enabled_notifications, - page_states, - (bios.dedicated_gfx), - (mode), - "Reboot required. BIOS GPU MUX mode set to", - do_mux_notification - ); - - // Charge notif - recv_notif!( - PowerProxy, - receive_notify_charge_control_end_threshold, - last_notification, - enabled_notifications, - page_states, - (power_state.charge_limit), - (limit), - "Battery charge limit changed to", - do_notification - ); - - recv_notif!( - PowerProxy, - receive_notify_mains_online, - last_notification, - enabled_notifications, - page_states, - (power_state.ac_power), - (on), - "AC Power power is", - ac_power_notification - ); - - // Profile notif - recv_notif!( - ProfileProxy, - receive_notify_profile, - last_notification, - enabled_notifications, - page_states, - (profiles.current), - (profile), - "Profile changed to", - do_thermal_notif - ); - // notify!(do_thermal_notif(&out.profile), lock); - - // LED notif - recv_notif!( - LedProxy, - receive_notify_led, - last_notification, - enabled_notifications, - page_states, - (aura.current_mode), - (data.mode), - "Keyboard LED mode changed to", - do_notification - ); - - let page_states1 = page_states.clone(); - tokio::spawn(async move { - let conn = zbus::Connection::system() - .await - .map_err(|e| { - error!("zbus signal: receive_power_states: {e}"); - e - }) - .unwrap(); - let proxy = AnimeProxy::new(&conn) - .await - .map_err(|e| { - error!("zbus signal: receive_power_states: {e}"); - e - }) - .unwrap(); - if let Ok(p) = proxy.receive_power_states().await { - info!("Started zbus signal thread: receive_power_states"); - p.for_each(|_| { - if let Ok(_lock) = page_states1.lock() { - // TODO: lock.anime. - } - future::ready(()) - }) - .await; - }; - }); - - recv_notif!( - SuperProxy, - receive_notify_gfx, - last_notification, - enabled_notifications, - page_states, - (gfx_state.mode), - (mode), - "Gfx mode changed to", - do_notification - ); - - // recv_notif!( - // SuperProxy, - // receive_notify_action, - // bios_notified, - // last_gfx_action_notif, - // enabled_notifications, - // [action], - // "Gfx mode change requires", - // do_gfx_action_notif - // ); - - tokio::spawn(async move { - let conn = zbus::Connection::system() - .await - .map_err(|e| { - error!("zbus signal: receive_notify_action: {e}"); - e - }) - .unwrap(); - let proxy = SuperProxy::new(&conn) - .await - .map_err(|e| { - error!("zbus signal: receive_notify_action: {e}"); - e - }) - .unwrap(); - if let Ok(mut p) = proxy.receive_notify_action().await { - info!("Started zbus signal thread: receive_notify_action"); - while let Some(e) = p.next().await { - if let Ok(out) = e.args() { - let action = out.action(); - do_gfx_action_notif("Gfx mode change requires", &format!("{action:?}",)) - .map_err(|e| { - error!("zbus signal: do_gfx_action_notif: {e}"); - e - }) - .unwrap(); - } - } - }; - }); - - let notifs_enabled1 = enabled_notifications; - let last_notif = last_notification; - tokio::spawn(async move { - let conn = zbus::Connection::system() - .await - .map_err(|e| { - error!("zbus signal: receive_notify_gfx_status: {e}"); - e - }) - .unwrap(); - let proxy = SuperProxy::new(&conn) - .await - .map_err(|e| { - error!("zbus signal: receive_notify_gfx_status: {e}"); - e - }) - .unwrap(); - if let Ok(mut p) = proxy.receive_notify_gfx_status().await { - info!("Started zbus signal thread: receive_notify_gfx_status"); - while let Some(e) = p.next().await { - if let Ok(out) = e.args() { - let status = out.status; - if status != GfxPower::Unknown { - if let Ok(config) = notifs_enabled1.lock() { - if config.all_enabled && config.receive_notify_gfx_status { - // Required check because status cycles through active/unknown/suspended - if let Ok(ref mut lock) = last_notif.lock() { - notify!( - do_gpu_status_notif("dGPU status changed:", &status), - lock - ); - } - } - } - if let Ok(mut lock) = page_states.lock() { - lock.gfx_state.power_status = status; - lock.set_notified(); - } - } - } - } - }; - }); - - Ok(()) -} - -fn base_notification(message: &str, data: &T) -> Notification -where - T: Display, -{ - let mut notif = Notification::new(); - - notif - .summary(NOTIF_HEADER) - .body(&format!("{message} {data}")) - .timeout(2000) - //.hint(Hint::Resident(true)) - .hint(Hint::Category("device".into())); - - notif -} - -fn do_notification(message: &str, data: &T) -> Result -where - T: Display, -{ - Ok(base_notification(message, data).show()?) -} - -fn ac_power_notification(message: &str, on: &bool) -> Result { - let data = if *on { - "plugged".to_owned() - } else { - "unplugged".to_owned() - }; - Ok(base_notification(message, &data).show()?) -} - -fn do_thermal_notif(message: &str, profile: &Profile) -> Result { - let icon = match profile { - Profile::Balanced => "asus_notif_yellow", - Profile::Performance => "asus_notif_red", - Profile::Quiet => "asus_notif_green", - }; - let profile: &str = (*profile).into(); - let mut notif = base_notification(message, &profile.to_uppercase()); - Ok(notif.icon(icon).show()?) -} - -fn do_gpu_status_notif(message: &str, data: &GfxPower) -> Result { - // eww - let mut notif = base_notification(message, &<&str>::from(data).to_owned()); - let icon = match data { - GfxPower::Suspended => "asus_notif_blue", - GfxPower::Off => "asus_notif_green", - GfxPower::AsusDisabled => "asus_notif_white", - GfxPower::AsusMuxDiscreet | GfxPower::Active => "asus_notif_red", - GfxPower::Unknown => "gpu-integrated", - }; - notif.icon(icon); - Ok(Notification::show(¬if)?) -} - -fn do_gfx_action_notif(message: &str, data: &T) -> Result<()> -where - T: Display, -{ - let mut notif = base_notification(message, data); - notif.action("gnome-session-quit", "Logout"); - notif.urgency(Urgency::Critical); - notif.timeout(3000); - notif.icon("dialog-warning"); - notif.hint(Hint::Transient(true)); - let handle = notif.show()?; - handle.wait_for_action(|id| { - if id == "gnome-session-quit" { - let mut cmd = Command::new("gnome-session-quit"); - cmd.spawn().ok(); - } else if id == "__closed" { - // TODO: cancel the switching - } - }); - Ok(()) -} - -/// Actual `GpuMode` unused as data is never correct until switched by reboot -fn do_mux_notification(message: &str, _: &GpuMode) -> Result { - let mut notif = base_notification(message, &""); - notif.urgency(Urgency::Critical); - notif.icon("system-reboot-symbolic"); - notif.hint(Hint::Transient(true)); - Ok(notif.show()?) -} diff --git a/rog-control-center/src/system_state.rs b/rog-control-center/src/system_state.rs index ef9d7aea..5f2e1787 100644 --- a/rog-control-center/src/system_state.rs +++ b/rog-control-center/src/system_state.rs @@ -12,7 +12,7 @@ use supergfxctl::{ zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking, }; -use crate::{error::Result, notify::EnabledNotifications, RogDbusClientBlocking}; +use crate::{error::Result, update_and_notify::EnabledNotifications, RogDbusClientBlocking}; use log::error; #[derive(Clone, Debug, Default)] @@ -219,6 +219,7 @@ impl AnimeState { #[derive(Clone, Debug)] pub struct GfxState { + pub has_supergfx: bool, pub mode: GfxMode, pub power_status: GfxPower, } @@ -226,8 +227,9 @@ pub struct GfxState { impl GfxState { pub fn new(_supported: &SupportedFunctions, dbus: &GfxProxyBlocking<'_>) -> Result { Ok(Self { - mode: dbus.mode()?, - power_status: dbus.power()?, + has_supergfx: dbus.mode().is_ok(), + mode: dbus.mode().unwrap_or_default(), + power_status: dbus.power().unwrap_or_default(), }) } } @@ -235,6 +237,7 @@ impl GfxState { impl Default for GfxState { fn default() -> Self { Self { + has_supergfx: false, mode: GfxMode::None, power_status: GfxPower::Unknown, } @@ -401,6 +404,7 @@ impl Default for SystemState { drag_delta: Default::default(), }, gfx_state: GfxState { + has_supergfx: false, mode: GfxMode::None, power_status: GfxPower::Unknown, }, diff --git a/rog-control-center/src/tray.rs b/rog-control-center/src/tray.rs index 73d785db..0ebc5ce1 100644 --- a/rog-control-center/src/tray.rs +++ b/rog-control-center/src/tray.rs @@ -351,6 +351,7 @@ impl ROGTray { fn rebuild_and_update( &mut self, supported: &SupportedFunctions, + has_supergfx: bool, current_gfx_mode: GfxMode, charge_limit: u8, panel_od: bool, @@ -359,7 +360,9 @@ impl ROGTray { self.menu_add_base(); self.menu_add_charge_limit(supported, charge_limit); self.menu_add_panel_od(supported, panel_od); - self.menu_add_gpu(supported, current_gfx_mode); + if has_supergfx { + self.menu_add_gpu(supported, current_gfx_mode); + } self.menu_update(); } } @@ -371,6 +374,12 @@ pub fn init_tray( let (send, recv) = channel(); let _send = Arc::new(Mutex::new(send)); + let has_supergfx = if let Ok(lock) = states.try_lock() { + lock.gfx_state.has_supergfx + } else { + false + }; + std::thread::spawn(move || { if gtk::init() .map_err(|e| { @@ -396,7 +405,7 @@ pub fn init_tray( return; } }; - tray.rebuild_and_update(&supported, GfxMode::Hybrid, 100, false); + tray.rebuild_and_update(&supported, has_supergfx, GfxMode::Hybrid, 100, false); tray.set_icon(TRAY_APP_ICON); info!("Started ROGTray"); @@ -405,6 +414,7 @@ pub fn init_tray( if lock.tray_should_update { tray.rebuild_and_update( &supported, + has_supergfx, lock.gfx_state.mode, lock.power_state.charge_limit, lock.bios.panel_overdrive, @@ -419,7 +429,13 @@ pub fn init_tray( GfxPower::AsusMuxDiscreet | GfxPower::Active => { tray.set_icon("asus_notif_red"); } - GfxPower::Unknown => tray.set_icon("gpu-integrated"), + GfxPower::Unknown => { + if has_supergfx { + tray.set_icon("gpu-integrated"); + } else { + tray.set_icon("asus_notif_red"); + } + } }; } }