Compare commits

..

7 Commits

Author SHA1 Message Date
Luke D. Jones aad4dc909e Bump version 2022-11-16 20:33:23 +13:00
Luke D. Jones ad79adcbfa ROGCC: splatter log messages everywhere. Rename state control 2022-11-16 20:32:11 +13:00
Luke D. Jones 73b1a7050a ROGCC: Make zbus notifications fully manage pagestates 2022-11-15 22:26:17 +13:00
Luke D. Jones 762bfea102 ROGCC: share PageState so tray can use it. zbus notifs update this 2022-11-15 11:12:41 +13:00
Luke D. Jones b41fdf5cfe ROGCC: add status for dgpu, charge ctl, panel-od to systray 2022-11-14 11:05:52 +13:00
Luke D. Jones bf13ebebd3 Set tray icon after init 2022-11-13 21:00:33 +13:00
Luke D. Jones 3a73e3a526 Try to prevent tray loop stalling 2022-11-13 12:52:52 +13:00
29 changed files with 655 additions and 531 deletions
+3 -1
View File
@@ -5,13 +5,15 @@ 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.1- RC1]
## [v4.5.1]
### Added
- Support for FA506IE LED modes (Author: Herohtar)
### Changed
- Add a basic system tray with dGPU status and gpu mode switch actions
- Fixup some notifications in ROGCC
- Add config options for notifications for ROGCC
- Share states with tray process in ROGCC
- Share tates with tray process in ROGCC
## [v4.5.0]
### Added
Generated
+9 -9
View File
@@ -83,7 +83,7 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "asusctl"
version = "4.5.1-RC1"
version = "4.5.1"
dependencies = [
"daemon",
"gif",
@@ -662,7 +662,7 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
[[package]]
name = "daemon"
version = "4.5.1-RC1"
version = "4.5.1"
dependencies = [
"async-trait",
"concat-idents",
@@ -686,7 +686,7 @@ dependencies = [
[[package]]
name = "daemon-user"
version = "4.5.1-RC1"
version = "4.5.1"
dependencies = [
"dirs",
"rog_anime",
@@ -2398,7 +2398,7 @@ dependencies = [
[[package]]
name = "rog-control-center"
version = "4.5.1-RC1"
version = "4.5.1"
dependencies = [
"daemon",
"dirs",
@@ -2428,7 +2428,7 @@ dependencies = [
[[package]]
name = "rog_anime"
version = "4.5.1-RC1"
version = "4.5.1"
dependencies = [
"gif",
"glam",
@@ -2444,7 +2444,7 @@ dependencies = [
[[package]]
name = "rog_aura"
version = "4.5.1-RC1"
version = "4.5.1"
dependencies = [
"serde",
"serde_derive",
@@ -2455,7 +2455,7 @@ dependencies = [
[[package]]
name = "rog_dbus"
version = "4.5.1-RC1"
version = "4.5.1"
dependencies = [
"rog_anime",
"rog_aura",
@@ -2468,7 +2468,7 @@ dependencies = [
[[package]]
name = "rog_platform"
version = "4.5.1-RC1"
version = "4.5.1"
dependencies = [
"concat-idents",
"inotify",
@@ -2485,7 +2485,7 @@ dependencies = [
[[package]]
name = "rog_profiles"
version = "4.5.1-RC1"
version = "4.5.1"
dependencies = [
"serde",
"serde_derive",
+1 -1
View File
@@ -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.1-RC1"
version = "4.5.1"
[workspace.dependencies]
async-trait = "^0.1"
-1
View File
@@ -539,7 +539,6 @@ fn handle_led_power_1_do_tuf(
x19b6: vec![],
tuf: enabled,
};
dbg!(&data);
dbus.proxies().led().set_leds_power(data, true)?;
let data = AuraPowerDev {
+2 -2
View File
@@ -145,7 +145,7 @@ impl AnimeConfig {
.read(true)
.write(true)
.create(true)
.open(&ANIME_CONFIG_PATH)
.open(ANIME_CONFIG_PATH)
.unwrap_or_else(|_| {
panic!(
"The file {} or directory /etc/asusd/ is missing",
@@ -249,7 +249,7 @@ impl AnimeConfig {
pub fn read(&mut self) {
let mut file = OpenOptions::new()
.read(true)
.open(&ANIME_CONFIG_PATH)
.open(ANIME_CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", ANIME_CONFIG_PATH, err));
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
+2 -2
View File
@@ -192,7 +192,7 @@ impl AuraConfig {
.read(true)
.write(true)
.create(true)
.open(&AURA_CONFIG_PATH)
.open(AURA_CONFIG_PATH)
.unwrap_or_else(|_| {
panic!(
"The file {} or directory /etc/asusd/ is missing",
@@ -264,7 +264,7 @@ impl AuraConfig {
pub fn read(&mut self) {
let mut file = OpenOptions::new()
.read(true)
.open(&AURA_CONFIG_PATH)
.open(AURA_CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", AURA_CONFIG_PATH, err));
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
-1
View File
@@ -64,7 +64,6 @@ macro_rules! task_watch_item {
let mut buffer = [0; 32];
watch.event_stream(&mut buffer).unwrap().for_each(|_| async {
let value = ctrl.$name();
dbg!(&value);
concat_idents::concat_idents!(notif_fn = notify_, $name {
Self::notif_fn(&signal_ctxt, value).await.ok();
});
+7 -1
View File
@@ -5,7 +5,7 @@ pub const LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
use serde_derive::{Deserialize, Serialize};
use std::str::FromStr;
use std::{fmt::Display, str::FromStr};
#[cfg(feature = "dbus")]
use zvariant::Type;
@@ -171,6 +171,12 @@ pub enum AuraModeNum {
Flash = 12,
}
impl Display for AuraModeNum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", <&str>::from(self))
}
}
impl From<AuraModeNum> for String {
fn from(mode: AuraModeNum) -> Self {
match mode {
+52 -72
View File
@@ -1,10 +1,8 @@
use std::{
f64::consts::PI,
io::Write,
sync::{
atomic::{AtomicBool, AtomicU8, Ordering},
mpsc::Receiver,
Arc,
Arc, Mutex,
},
time::{Duration, Instant},
};
@@ -13,17 +11,15 @@ use egui::{Button, RichText};
use rog_platform::supported::SupportedFunctions;
use crate::{
config::Config, error::Result, get_ipc_file, page_states::PageDataStates, tray::TrayToApp,
Page, RogDbusClientBlocking, SHOW_GUI,
config::Config, error::Result, system_state::SystemState, Page, RogDbusClientBlocking,
};
pub struct RogApp<'a> {
pub struct RogApp {
pub page: Page,
pub states: PageDataStates,
pub states: Arc<Mutex<SystemState>>,
pub supported: SupportedFunctions,
// TODO: can probably just open and read whenever
pub config: Config,
pub asus_dbus: RogDbusClientBlocking<'a>,
/// Oscillator in percentage
pub oscillator1: Arc<AtomicU8>,
pub oscillator2: Arc<AtomicU8>,
@@ -32,15 +28,13 @@ pub struct RogApp<'a> {
pub oscillator_freq: Arc<AtomicU8>,
/// A toggle that toggles true/false when the oscillator reaches 0
pub oscillator_toggle: Arc<AtomicBool>,
pub app_cmd: Arc<Receiver<TrayToApp>>,
}
impl<'a> RogApp<'a> {
impl RogApp {
/// Called once before the first frame.
pub fn new(
config: Config,
states: PageDataStates,
app_cmd: Arc<Receiver<TrayToApp>>,
states: Arc<Mutex<SystemState>>,
_cc: &eframe::CreationContext<'_>,
) -> Result<Self> {
let (dbus, _) = RogDbusClientBlocking::new()?;
@@ -60,6 +54,7 @@ impl<'a> RogApp<'a> {
let oscillator_freq1 = oscillator_freq.clone();
let oscillator_toggle = Arc::new(AtomicBool::new(false));
let oscillator_toggle1 = oscillator_toggle.clone();
std::thread::spawn(move || {
let started = Instant::now();
let mut toggled = false;
@@ -88,6 +83,7 @@ impl<'a> RogApp<'a> {
oscillator1_1.store(tmp1, Ordering::SeqCst);
oscillator1_2.store(tmp2, Ordering::SeqCst);
oscillator1_3.store(tmp3, Ordering::SeqCst);
std::thread::sleep(Duration::from_millis(33));
}
});
@@ -97,88 +93,72 @@ impl<'a> RogApp<'a> {
states,
page: Page::System,
config,
asus_dbus: dbus,
oscillator1,
oscillator2,
oscillator3,
oscillator_toggle,
oscillator_freq,
app_cmd,
})
}
fn check_app_cmds(&mut self, _ctx: &egui::Context, _frame: &mut eframe::Frame) {
let Self { app_cmd, .. } = self;
if let Ok(cmd) = app_cmd.try_recv() {
match cmd {
TrayToApp::Open => {
dbg!();
get_ipc_file().unwrap().write_all(&[SHOW_GUI]).ok();
}
TrayToApp::Quit => _frame.close(),
}
}
}
}
impl<'a> eframe::App for RogApp<'a> {
impl eframe::App for RogApp {
/// Called each time the UI needs repainting, which may be many times per second.
/// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`.
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
self.check_app_cmds(ctx, frame);
let states = self.states.clone();
let Self {
supported,
asus_dbus: dbus,
states,
..
} = self;
states
.refresh_if_notfied(supported, dbus)
.map(|repaint| {
if repaint {
ctx.request_repaint();
}
})
.map_err(|e| self.states.error = Some(e.to_string()))
.ok();
if let Ok(mut states) = states.try_lock() {
if states.app_should_update {
states.app_should_update = false;
ctx.request_repaint();
}
}
let page = self.page;
self.top_bar(ctx, frame);
self.side_panel(ctx);
if let Some(err) = self.states.error.clone() {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading(RichText::new("Error!").size(28.0));
let mut was_error = false;
ui.centered_and_justified(|ui| {
ui.label(RichText::new(format!("The error was: {:?}", err)).size(22.0));
});
});
egui::TopBottomPanel::bottom("error_bar")
.default_height(26.0)
.show(ctx, |ui| {
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
if ui
.add(Button::new(RichText::new("Okay").size(20.0)))
.clicked()
{
self.states.error = None;
}
if let Ok(mut states) = states.try_lock() {
if let Some(err) = states.error.clone() {
was_error = true;
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading(RichText::new("Error!").size(28.0));
ui.centered_and_justified(|ui| {
ui.label(RichText::new(format!("The error was: {:?}", err)).size(22.0));
});
});
} else if page == Page::System {
self.system_page(ctx);
} else if page == Page::AuraEffects {
self.aura_page(ctx);
// TODO: Anime page is not complete
// } else if page == Page::AnimeMatrix {
// self.anime_page(ctx);
} else if page == Page::FanCurves {
self.fan_curve_page(ctx);
egui::TopBottomPanel::bottom("error_bar")
.default_height(26.0)
.show(ctx, |ui| {
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
if ui
.add(Button::new(RichText::new("Okay").size(20.0)))
.clicked()
{
states.error = None;
}
});
});
}
}
if !was_error {
if let Ok(mut states) = states.try_lock() {
if page == Page::System {
self.system_page(&mut states, ctx);
} else if page == Page::AuraEffects {
self.aura_page(&mut states, ctx);
// TODO: Anime page is not complete
// } else if page == Page::AnimeMatrix {
// self.anime_page(ctx);
} else if page == Page::FanCurves {
self.fan_curve_page(&mut states, ctx);
}
}
}
}
}
+9 -2
View File
@@ -1,9 +1,9 @@
use log::{error, info, warn};
use serde_derive::{Deserialize, Serialize};
use std::{
fs::{create_dir, OpenOptions},
io::{Read, Write},
};
use serde_derive::{Deserialize, Serialize};
//use log::{error, info, warn};
use crate::{error::Error, notify::EnabledNotifications};
@@ -34,14 +34,17 @@ impl Default for Config {
impl Config {
pub fn load() -> Result<Config, Error> {
let mut path = if let Some(dir) = dirs::config_dir() {
info!("Found XDG config dir {dir:?}");
dir
} else {
error!("Could not get XDG config dir");
return Err(Error::XdgVars);
};
path.push(CFG_DIR);
if !path.exists() {
create_dir(path.clone())?;
info!("Created {path:?}");
}
path.push(CFG_FILE_NAME);
@@ -56,11 +59,13 @@ impl Config {
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 {
warn!("Zero len read of Config file");
let default = Config::default();
let t = toml::to_string_pretty(&default).unwrap();
file.write_all(t.as_bytes())?;
return Ok(default);
} else if let Ok(data) = toml::from_str::<Config>(&buf) {
info!("Loaded config file {path:?}");
return Ok(data);
}
}
@@ -77,6 +82,7 @@ impl Config {
path.push(CFG_DIR);
if !path.exists() {
create_dir(path.clone())?;
info!("Created {path:?}");
}
path.push(CFG_FILE_NAME);
@@ -90,6 +96,7 @@ impl Config {
self.enabled_notifications = enabled_notifications.clone();
let t = toml::to_string_pretty(&self).unwrap();
file.write_all(t.as_bytes())?;
info!("Saved config file {path:?}");
Ok(())
}
}
+1 -1
View File
@@ -14,9 +14,9 @@ pub mod error;
#[cfg(feature = "mocking")]
pub mod mocking;
pub mod notify;
pub mod page_states;
pub mod pages;
pub mod startup_error;
pub mod system_state;
pub mod tray;
pub mod widgets;
+24 -64
View File
@@ -1,21 +1,20 @@
use eframe::{IconData, NativeOptions};
use log::{error, LevelFilter};
use log::{error, info, LevelFilter};
use rog_aura::layouts::KeyLayout;
use rog_control_center::notify::EnabledNotifications;
use rog_control_center::tray::{AppToTray, TrayToApp};
use rog_control_center::tray::init_tray;
use rog_control_center::{
config::Config, error::Result, get_ipc_file, notify::start_notifications, on_tmp_dir_exists,
page_states::PageDataStates, print_versions, startup_error::AppErrorShow, tray::init_tray,
RogApp, RogDbusClientBlocking, SHOWING_GUI, SHOW_GUI,
print_versions, startup_error::AppErrorShow, system_state::SystemState, RogApp,
RogDbusClientBlocking, SHOWING_GUI, SHOW_GUI,
};
use rog_platform::supported::SupportedFunctions;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Mutex;
use std::{
fs::OpenOptions,
io::{Read, Write},
path::PathBuf,
sync::{atomic::AtomicBool, Arc},
sync::Arc,
};
use tokio::runtime::Runtime;
@@ -73,10 +72,6 @@ fn main() -> Result<()> {
}
};
let (send, recv) = channel();
let update_tray = Arc::new(Mutex::new(send));
let app_cmd = Arc::new(init_tray(supported.clone(), recv));
// Startup
let mut config = Config::load()?;
let mut start_closed = config.startup_in_background;
@@ -123,21 +118,16 @@ fn main() -> Result<()> {
Err(_) => on_tmp_dir_exists().unwrap(),
};
let states = setup_page_state_and_notifs(
layout,
&dbus,
enabled_notifications,
update_tray,
&supported,
)
.unwrap();
let states = setup_page_state_and_notifs(layout, enabled_notifications, &supported)?;
init_tray(supported, states.clone());
loop {
if !start_closed {
start_app(states.clone(), native_options.clone(), app_cmd.clone())?;
start_app(states.clone(), native_options.clone())?;
}
let config = Config::load().unwrap();
let config = Config::load()?;
if !config.run_in_background {
break;
}
@@ -146,7 +136,7 @@ fn main() -> Result<()> {
let mut buf = [0u8; 4];
// 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)
if get_ipc_file().unwrap().read(&mut buf).is_ok() && buf[0] == SHOW_GUI {
if get_ipc_file()?.read(&mut buf).is_ok() && buf[0] == SHOW_GUI {
start_closed = false;
continue;
}
@@ -162,58 +152,27 @@ fn main() -> Result<()> {
fn setup_page_state_and_notifs(
keyboard_layout: KeyLayout,
dbus: &RogDbusClientBlocking,
enabled_notifications: Arc<Mutex<EnabledNotifications>>,
update_tray: Arc<Mutex<Sender<AppToTray>>>,
supported: &SupportedFunctions,
) -> Result<PageDataStates> {
// Cheap method to alert to notifications rather than spinning a thread for each
// This is quite different when done in a retained mode app
let charge_notified = Arc::new(AtomicBool::new(false));
let bios_notified = Arc::new(AtomicBool::new(false));
let aura_notified = Arc::new(AtomicBool::new(false));
let anime_notified = Arc::new(AtomicBool::new(false));
let profiles_notified = Arc::new(AtomicBool::new(false));
let fans_notified = Arc::new(AtomicBool::new(false));
start_notifications(
charge_notified.clone(),
bios_notified.clone(),
aura_notified.clone(),
anime_notified.clone(),
profiles_notified.clone(),
fans_notified.clone(),
enabled_notifications.clone(),
update_tray,
)?;
PageDataStates::new(
) -> Result<Arc<Mutex<SystemState>>> {
let page_states = Arc::new(Mutex::new(SystemState::new(
keyboard_layout,
enabled_notifications,
charge_notified,
bios_notified,
aura_notified,
anime_notified,
profiles_notified,
fans_notified,
enabled_notifications.clone(),
supported,
dbus,
)
)?));
start_notifications(page_states.clone(), enabled_notifications)?;
Ok(page_states)
}
fn start_app(
states: PageDataStates,
native_options: NativeOptions,
app_cmd: Arc<Receiver<TrayToApp>>,
) -> Result<()> {
let mut ipc_file = get_ipc_file().unwrap();
ipc_file.write_all(&[SHOWING_GUI]).unwrap();
fn start_app(states: Arc<Mutex<SystemState>>, native_options: NativeOptions) -> Result<()> {
let mut ipc_file = get_ipc_file()?;
ipc_file.write_all(&[SHOWING_GUI])?;
eframe::run_native(
"ROG Control Center",
native_options,
Box::new(move |cc| {
Box::new(RogApp::new(Config::load().unwrap(), states, app_cmd, cc).unwrap())
}),
Box::new(move |cc| Box::new(RogApp::new(Config::load().unwrap(), states, cc).unwrap())),
);
Ok(())
}
@@ -243,6 +202,7 @@ fn load_icon() -> IconData {
rgba = ras.as_u8_slice().to_vec();
width = ras.width();
height = ras.height();
info!("Loaded app icon. Not actually supported in Wayland yet");
}
}
} else {
+116 -70
View File
@@ -1,4 +1,5 @@
use crate::{config::Config, error::Result, tray::AppToTray};
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,
@@ -10,11 +11,7 @@ use serde::{Deserialize, Serialize};
use std::{
fmt::Display,
process::Command,
sync::{
atomic::{AtomicBool, Ordering},
mpsc::Sender,
Arc, Mutex,
},
sync::{Arc, Mutex},
};
use supergfxctl::{pci_device::GfxPower, zbus_proxy::DaemonProxy as SuperProxy};
use zbus::export::futures_util::{future, StreamExt};
@@ -77,33 +74,47 @@ macro_rules! notify {
};
}
// TODO: drop the macro and use generics plus closure
macro_rules! recv_notif {
($proxy:ident,
$signal:ident,
$was_notified:ident,
$last_notif:ident,
$notif_enabled:ident,
[$($out_arg: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 notified = $was_notified.clone();
// TODO: make a macro or generic function or something...
let page_states1 = $page_states.clone();
tokio::spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = $proxy::new(&conn).await.unwrap();
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.try_lock() {
notify!($notifier($msg, &out$(.$out_arg)+()), lock);
if let Ok(ref mut lock) = last_notif.lock() {
trace!("zbus signal {} locked last_notif", stringify!($signal));
notify!($notifier($msg, &out.$($out_arg)+()), lock);
}
notified.store(true, Ordering::SeqCst);
}
}
if let Ok(mut lock) = page_states1.lock() {
lock.$($args)+ = *out.$($out_arg)+();
lock.set_notified();
}
}
}
};
@@ -114,14 +125,8 @@ macro_rules! recv_notif {
type SharedHandle = Arc<Mutex<Option<NotificationHandle>>>;
pub fn start_notifications(
charge_notified: Arc<AtomicBool>,
bios_notified: Arc<AtomicBool>,
aura_notified: Arc<AtomicBool>,
anime_notified: Arc<AtomicBool>,
profiles_notified: Arc<AtomicBool>,
_fans_notified: Arc<AtomicBool>,
page_states: Arc<Mutex<SystemState>>,
enabled_notifications: Arc<Mutex<EnabledNotifications>>,
update_tray: Arc<std::sync::Mutex<Sender<AppToTray>>>,
) -> Result<()> {
let last_notification: SharedHandle = Arc::new(Mutex::new(None));
@@ -129,10 +134,11 @@ pub fn start_notifications(
recv_notif!(
RogBiosProxy,
receive_notify_post_boot_sound,
bios_notified,
last_notification,
enabled_notifications,
[on],
page_states,
(bios.post_sound),
(on),
"BIOS Post sound",
do_notification
);
@@ -140,10 +146,11 @@ pub fn start_notifications(
recv_notif!(
RogBiosProxy,
receive_notify_panel_od,
bios_notified,
last_notification,
enabled_notifications,
[overdrive],
page_states,
(bios.panel_overdrive),
(overdrive),
"Panel Overdrive enabled:",
do_notification
);
@@ -151,10 +158,11 @@ pub fn start_notifications(
recv_notif!(
RogBiosProxy,
receive_notify_dgpu_disable,
bios_notified,
last_notification,
enabled_notifications,
[disable],
page_states,
(bios.dgpu_disable),
(disable),
"BIOS dGPU disabled",
do_notification
);
@@ -162,10 +170,11 @@ pub fn start_notifications(
recv_notif!(
RogBiosProxy,
receive_notify_egpu_enable,
bios_notified,
last_notification,
enabled_notifications,
[enable],
page_states,
(bios.egpu_enable),
(enable),
"BIOS eGPU enabled",
do_notification
);
@@ -173,10 +182,11 @@ pub fn start_notifications(
recv_notif!(
RogBiosProxy,
receive_notify_gpu_mux_mode,
bios_notified,
last_notification,
enabled_notifications,
[mode],
page_states,
(bios.dedicated_gfx),
(mode),
"Reboot required. BIOS GPU MUX mode set to",
do_mux_notification
);
@@ -185,10 +195,11 @@ pub fn start_notifications(
recv_notif!(
PowerProxy,
receive_notify_charge_control_end_threshold,
charge_notified,
last_notification,
enabled_notifications,
[limit],
page_states,
(power_state.charge_limit),
(limit),
"Battery charge limit changed to",
do_notification
);
@@ -196,10 +207,11 @@ pub fn start_notifications(
recv_notif!(
PowerProxy,
receive_notify_mains_online,
bios_notified,
last_notification,
enabled_notifications,
[on],
page_states,
(power_state.ac_power),
(on),
"AC Power power is",
ac_power_notification
);
@@ -208,10 +220,11 @@ pub fn start_notifications(
recv_notif!(
ProfileProxy,
receive_notify_profile,
profiles_notified,
last_notification,
enabled_notifications,
[profile],
page_states,
(profiles.current),
(profile),
"Profile changed to",
do_thermal_notif
);
@@ -221,32 +234,37 @@ pub fn start_notifications(
recv_notif!(
LedProxy,
receive_notify_led,
aura_notified,
last_notification,
enabled_notifications,
[data mode_name],
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.unwrap();
let proxy = LedProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_all_signals().await {
p.for_each(|_| {
aura_notified.store(true, Ordering::SeqCst);
future::ready(())
let conn = zbus::Connection::system()
.await
.map_err(|e| {
error!("zbus signal: receive_power_states: {e}");
e
})
.await;
};
});
tokio::spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = AnimeProxy::new(&conn).await.unwrap();
.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(|_| {
anime_notified.store(true, Ordering::SeqCst);
if let Ok(_lock) = page_states1.lock() {
// TODO: lock.anime.
}
future::ready(())
})
.await;
@@ -256,10 +274,11 @@ pub fn start_notifications(
recv_notif!(
SuperProxy,
receive_notify_gfx,
bios_notified,
last_notification,
enabled_notifications,
[mode],
page_states,
(gfx_state.mode),
(mode),
"Gfx mode changed to",
do_notification
);
@@ -275,51 +294,78 @@ pub fn start_notifications(
// do_gfx_action_notif
// );
let bios_notified1 = bios_notified.clone();
tokio::spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = SuperProxy::new(&conn).await.unwrap();
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();
}
}
bios_notified1.store(true, Ordering::SeqCst);
};
});
let notifs_enabled1 = enabled_notifications;
let last_notif = last_notification;
let bios_notified1 = bios_notified;
tokio::spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = SuperProxy::new(&conn).await.unwrap();
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 {
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.try_lock() {
if let Ok(ref mut lock) = last_notif.lock() {
notify!(
do_gpu_status_notif("dGPU status changed:", status),
do_gpu_status_notif("dGPU status changed:", &status),
lock
);
}
}
}
if let Ok(lock) = update_tray.try_lock() {
lock.send(AppToTray::DgpuStatus(*status)).ok();
if let Ok(mut lock) = page_states.lock() {
lock.gfx_state.power_status = status;
lock.set_notified();
}
}
}
}
bios_notified1.store(true, Ordering::SeqCst);
};
});
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::RogApp;
impl<'a> RogApp<'a> {
impl RogApp {
pub fn anime_page(&mut self, ctx: &egui::Context) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.label("In progress");
+4 -6
View File
@@ -4,16 +4,15 @@ use egui::Color32;
use rog_aura::{AuraEffect, AuraModeNum};
use crate::{
system_state::SystemState,
widgets::{aura_modes_group, keyboard},
RogApp,
};
impl<'a> RogApp<'a> {
pub fn aura_page(&mut self, ctx: &egui::Context) {
impl RogApp {
pub fn aura_page(&mut self, states: &mut SystemState, ctx: &egui::Context) {
let Self {
supported,
states,
asus_dbus: dbus,
oscillator1,
oscillator2,
oscillator3,
@@ -26,7 +25,6 @@ impl<'a> RogApp<'a> {
let blue = oscillator3.load(Ordering::SeqCst) as u32;
states.aura.nudge_wave(red as u8, green as u8, blue as u8);
// let osc = c.0 * 255 / osc;
// dbg!(osc);
let c1 = states
.aura
.modes
@@ -72,7 +70,7 @@ impl<'a> RogApp<'a> {
// TODO: animation of colour changes/periods/blending
egui::CentralPanel::default().show(ctx, |ui| {
aura_modes_group(supported, states, oscillator_freq, dbus, ui);
aura_modes_group(supported, states, oscillator_freq, ui);
keyboard(ui, &states.keyboard_layout, &mut states.aura, colour);
});
+7 -13
View File
@@ -1,5 +1,5 @@
use crate::{
page_states::{FanCurvesState, ProfilesState},
system_state::{FanCurvesState, ProfilesState, SystemState},
widgets::fan_graphs,
RogApp, RogDbusClientBlocking,
};
@@ -7,14 +7,9 @@ use egui::Ui;
use rog_platform::supported::SupportedFunctions;
use rog_profiles::Profile;
impl<'a> RogApp<'a> {
pub fn fan_curve_page(&mut self, ctx: &egui::Context) {
let Self {
supported,
states,
asus_dbus: dbus,
..
} = self;
impl RogApp {
pub fn fan_curve_page(&mut self, states: &mut SystemState, ctx: &egui::Context) {
let Self { supported, .. } = self;
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Custom fan curves");
@@ -23,11 +18,11 @@ impl<'a> RogApp<'a> {
supported,
&mut states.profiles,
&mut states.fan_curves,
dbus, &mut states.error,
&states.asus_dbus, &mut states.error,
ui,
);
fan_graphs(supported, &mut states.profiles, &mut states.fan_curves, dbus, &mut states.error, ui);
fan_graphs(supported, &mut states.profiles, &mut states.fan_curves, &states.asus_dbus, &mut states.error, ui);
});
}
@@ -76,8 +71,7 @@ impl<'a> RogApp<'a> {
let selected_profile = curves.show_curve;
let selected_pu = curves.show_graph;
let notif = curves.was_notified.clone();
match FanCurvesState::new(notif, supported, dbus) {
match FanCurvesState::new(supported, dbus) {
Ok(f) => *curves = f,
Err(e) => *do_error = Some(e.to_string()),
}
+8 -11
View File
@@ -1,18 +1,15 @@
use crate::{
system_state::SystemState,
widgets::{
anime_power_group, app_settings, aura_power_group, platform_profile, rog_bios_group,
},
RogApp,
};
impl<'a> RogApp<'a> {
pub fn system_page(&mut self, ctx: &egui::Context) {
impl RogApp {
pub fn system_page(&mut self, states: &mut SystemState, ctx: &egui::Context) {
let Self {
config,
supported,
states,
asus_dbus: dbus,
..
config, supported, ..
} = self;
egui::CentralPanel::default().show(ctx, |ui| {
@@ -28,12 +25,12 @@ impl<'a> RogApp<'a> {
ui.vertical(|ui| {
ui.separator();
if supported.platform_profile.platform_profile {
platform_profile(states, dbus, ui);
platform_profile(states, ui);
}
});
ui.vertical(|ui| {
ui.separator();
aura_power_group(supported, states, dbus, ui);
aura_power_group(supported, states, ui);
});
ui.end_row();
@@ -44,7 +41,7 @@ impl<'a> RogApp<'a> {
});
ui.vertical(|ui| {
ui.separator();
rog_bios_group(supported, states, dbus, ui);
rog_bios_group(supported, states, ui);
});
ui.end_row();
@@ -52,7 +49,7 @@ impl<'a> RogApp<'a> {
ui.vertical(|ui| {
ui.separator();
if supported.anime_ctrl.0 {
anime_power_group(supported, states, dbus, ui);
anime_power_group(supported, states, ui);
}
});
ui.vertical(|ui| {
@@ -1,15 +1,16 @@
use std::{
collections::{BTreeMap, HashSet},
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
},
sync::{Arc, Mutex},
};
use egui::Vec2;
use rog_aura::{layouts::KeyLayout, usb::AuraPowerDev, AuraEffect, AuraModeNum};
use rog_platform::{platform::GpuMode, supported::SupportedFunctions};
use rog_profiles::{fan_curve_set::FanCurveSet, FanCurvePU, Profile};
use supergfxctl::{
pci_device::{GfxMode, GfxPower},
zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking,
};
use crate::{error::Result, notify::EnabledNotifications, RogDbusClientBlocking};
@@ -18,7 +19,6 @@ pub struct BiosState {
/// To be shared to a thread that checks notifications.
/// It's a bit general in that it won't provide *what* was
/// updated, so the full state needs refresh
pub was_notified: Arc<AtomicBool>,
pub post_sound: bool,
pub dedicated_gfx: GpuMode,
pub panel_overdrive: bool,
@@ -27,13 +27,8 @@ pub struct BiosState {
}
impl BiosState {
pub fn new(
was_notified: Arc<AtomicBool>,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> {
pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking) -> Result<Self> {
Ok(Self {
was_notified,
post_sound: if supported.rog_bios_ctrl.post_sound {
dbus.proxies().rog_bios().post_boot_sound()? != 0
} else {
@@ -58,19 +53,13 @@ impl BiosState {
#[derive(Clone, Debug)]
pub struct ProfilesState {
pub was_notified: Arc<AtomicBool>,
pub list: Vec<Profile>,
pub current: Profile,
}
impl ProfilesState {
pub fn new(
was_notified: Arc<AtomicBool>,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> {
pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking) -> Result<Self> {
Ok(Self {
was_notified,
list: if supported.platform_profile.platform_profile {
let mut list = dbus.proxies().profile().profiles()?;
list.sort();
@@ -89,7 +78,6 @@ impl ProfilesState {
#[derive(Clone, Debug)]
pub struct FanCurvesState {
pub was_notified: Arc<AtomicBool>,
pub show_curve: Profile,
pub show_graph: FanCurvePU,
pub enabled: HashSet<Profile>,
@@ -98,11 +86,7 @@ pub struct FanCurvesState {
}
impl FanCurvesState {
pub fn new(
was_notified: Arc<AtomicBool>,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> {
pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking) -> Result<Self> {
let profiles = if supported.platform_profile.platform_profile {
dbus.proxies().profile().profiles()?
} else {
@@ -143,7 +127,6 @@ impl FanCurvesState {
};
Ok(Self {
was_notified,
show_curve,
show_graph: FanCurvePU::CPU,
enabled,
@@ -155,7 +138,6 @@ impl FanCurvesState {
#[derive(Clone, Debug)]
pub struct AuraState {
pub was_notified: Arc<AtomicBool>,
pub current_mode: AuraModeNum,
pub modes: BTreeMap<AuraModeNum, AuraEffect>,
pub enabled: AuraPowerDev,
@@ -167,13 +149,8 @@ pub struct AuraState {
}
impl AuraState {
pub fn new(
was_notified: Arc<AtomicBool>,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> {
pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking) -> Result<Self> {
Ok(Self {
was_notified,
current_mode: if !supported.keyboard_led.stock_led_modes.is_empty() {
dbus.proxies().led().led_mode().unwrap_or_default()
} else {
@@ -214,7 +191,6 @@ impl AuraState {
#[derive(Clone, Debug)]
pub struct AnimeState {
pub was_notified: Arc<AtomicBool>,
pub bright: u8,
pub boot: bool,
pub awake: bool,
@@ -222,13 +198,8 @@ pub struct AnimeState {
}
impl AnimeState {
pub fn new(
was_notified: Arc<AtomicBool>,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> {
pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking) -> Result<Self> {
Ok(Self {
was_notified,
boot: if supported.anime_ctrl.0 {
dbus.proxies().anime().boot_enabled()?
} else {
@@ -246,11 +217,41 @@ impl AnimeState {
}
}
#[derive(Debug, Clone)]
pub struct PageDataStates {
#[derive(Clone, Debug)]
pub struct GfxState {
pub mode: GfxMode,
pub power_status: GfxPower,
}
impl GfxState {
pub fn new(_supported: &SupportedFunctions, dbus: &GfxProxyBlocking) -> Result<Self> {
Ok(Self {
mode: dbus.mode()?,
power_status: dbus.power()?,
})
}
}
#[derive(Clone, Debug)]
pub struct PowerState {
pub charge_limit: u8,
pub ac_power: bool,
}
impl PowerState {
pub fn new(_supported: &SupportedFunctions, dbus: &RogDbusClientBlocking) -> Result<Self> {
Ok(Self {
charge_limit: dbus.proxies().charge().charge_control_end_threshold()?,
ac_power: dbus.proxies().charge().mains_online()?,
})
}
}
/// State stored from system daemons. This is shared with: tray, zbus notifications thread
/// and the GUI app thread.
pub struct SystemState {
pub keyboard_layout: KeyLayout,
pub enabled_notifications: Arc<Mutex<EnabledNotifications>>,
pub was_notified: Arc<AtomicBool>,
/// Because much of the app state here is the same as `RogBiosSupportedFunctions`
/// we can re-use that structure.
pub bios: BiosState,
@@ -258,87 +259,59 @@ pub struct PageDataStates {
pub anime: AnimeState,
pub profiles: ProfilesState,
pub fan_curves: FanCurvesState,
pub charge_limit: u8,
pub gfx_state: GfxState,
pub power_state: PowerState,
pub error: Option<String>,
/// Specific field for the tray only so that we can know when it does need update.
/// The tray should set this to false when done.
pub tray_should_update: bool,
pub app_should_update: bool,
pub asus_dbus: RogDbusClientBlocking<'static>,
pub gfx_dbus: GfxProxyBlocking<'static>,
}
#[allow(clippy::too_many_arguments)]
impl PageDataStates {
impl SystemState {
/// Creates self, including the relevant dbus connections and proixies for internal use
pub fn new(
keyboard_layout: KeyLayout,
enabled_notifications: Arc<Mutex<EnabledNotifications>>,
charge_notified: Arc<AtomicBool>,
bios_notified: Arc<AtomicBool>,
aura_notified: Arc<AtomicBool>,
anime_notified: Arc<AtomicBool>,
profiles_notified: Arc<AtomicBool>,
fans_notified: Arc<AtomicBool>,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> {
let (asus_dbus, conn) = RogDbusClientBlocking::new().unwrap();
let gfx_dbus = GfxProxyBlocking::new(&conn).unwrap();
Ok(Self {
keyboard_layout,
enabled_notifications,
was_notified: charge_notified,
charge_limit: dbus.proxies().charge().charge_control_end_threshold()?,
bios: BiosState::new(bios_notified, supported, dbus)?,
aura: AuraState::new(aura_notified, supported, dbus)?,
anime: AnimeState::new(anime_notified, supported, dbus)?,
profiles: ProfilesState::new(profiles_notified, supported, dbus)?,
fan_curves: FanCurvesState::new(fans_notified, supported, dbus)?,
power_state: PowerState::new(supported, &asus_dbus)?,
bios: BiosState::new(supported, &asus_dbus)?,
aura: AuraState::new(supported, &asus_dbus)?,
anime: AnimeState::new(supported, &asus_dbus)?,
profiles: ProfilesState::new(supported, &asus_dbus)?,
fan_curves: FanCurvesState::new(supported, &asus_dbus)?,
gfx_state: GfxState::new(supported, &gfx_dbus)?,
error: None,
tray_should_update: true,
app_should_update: true,
asus_dbus,
gfx_dbus,
})
}
pub fn refresh_if_notfied(
&mut self,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<bool> {
let mut notified = false;
if self.was_notified.load(Ordering::SeqCst) {
self.charge_limit = dbus.proxies().charge().charge_control_end_threshold()?;
self.was_notified.store(false, Ordering::SeqCst);
notified = true;
}
if self.aura.was_notified.load(Ordering::SeqCst) {
self.aura = AuraState::new(self.aura.was_notified.clone(), supported, dbus)?;
self.aura.was_notified.store(false, Ordering::SeqCst);
notified = true;
}
if self.bios.was_notified.load(Ordering::SeqCst) {
self.bios = BiosState::new(self.bios.was_notified.clone(), supported, dbus)?;
self.bios.was_notified.store(false, Ordering::SeqCst);
notified = true;
}
if self.profiles.was_notified.load(Ordering::SeqCst) {
self.profiles =
ProfilesState::new(self.profiles.was_notified.clone(), supported, dbus)?;
self.profiles.was_notified.store(false, Ordering::SeqCst);
notified = true;
}
if self.fan_curves.was_notified.load(Ordering::SeqCst) {
self.fan_curves =
FanCurvesState::new(self.fan_curves.was_notified.clone(), supported, dbus)?;
self.fan_curves.was_notified.store(false, Ordering::SeqCst);
notified = true;
}
Ok(notified)
pub fn set_notified(&mut self) {
self.tray_should_update = true;
self.app_should_update = true;
}
}
impl Default for PageDataStates {
impl Default for SystemState {
fn default() -> Self {
let (asus_dbus, conn) = RogDbusClientBlocking::new().unwrap();
let gfx_dbus = GfxProxyBlocking::new(&conn).unwrap();
Self {
keyboard_layout: KeyLayout::ga401_layout(),
enabled_notifications: Default::default(),
was_notified: Default::default(),
bios: BiosState {
was_notified: Default::default(),
post_sound: Default::default(),
dedicated_gfx: GpuMode::NotSupported,
panel_overdrive: Default::default(),
@@ -346,7 +319,6 @@ impl Default for PageDataStates {
egpu_enable: Default::default(),
},
aura: AuraState {
was_notified: Default::default(),
current_mode: AuraModeNum::Static,
modes: Default::default(),
enabled: AuraPowerDev {
@@ -360,27 +332,35 @@ impl Default for PageDataStates {
wave_blue: Default::default(),
},
anime: AnimeState {
was_notified: Default::default(),
bright: Default::default(),
boot: Default::default(),
awake: Default::default(),
sleep: Default::default(),
},
profiles: ProfilesState {
was_notified: Default::default(),
list: Default::default(),
current: Default::default(),
},
fan_curves: FanCurvesState {
was_notified: Default::default(),
show_curve: Default::default(),
show_graph: Default::default(),
enabled: Default::default(),
curves: Default::default(),
drag_delta: Default::default(),
},
charge_limit: Default::default(),
gfx_state: GfxState {
mode: GfxMode::None,
power_status: GfxPower::Unknown,
},
power_state: PowerState {
charge_limit: 99,
ac_power: false,
},
error: Default::default(),
tray_should_update: true,
app_should_update: true,
asus_dbus,
gfx_dbus,
}
}
}
+265 -100
View File
@@ -10,12 +10,18 @@ use std::{
time::Duration,
};
use gtk::{gio::Icon, prelude::*, MenuItem};
use gtk::{gio::Icon, prelude::*};
use rog_dbus::zbus_platform::RogBiosProxyBlocking;
use rog_platform::{platform::GpuMode, supported::SupportedFunctions};
use crate::{error::Result, get_ipc_file, SHOW_GUI};
use crate::{error::Result, get_ipc_file, system_state::SystemState, SHOW_GUI};
use libappindicator::{AppIndicator, AppIndicatorStatus};
use supergfxctl::pci_device::{GfxMode, GfxPower};
use supergfxctl::{
pci_device::{GfxMode, GfxPower},
zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking,
};
use log::{debug, error, info, trace};
const TRAY_APP_ICON: &str = "rog-control-center";
const TRAY_LABEL: &str = "ROG Control Center";
@@ -73,29 +79,36 @@ impl RadioGroup {
pub struct ROGTray {
tray: AppIndicator,
menu: gtk::Menu,
items: Vec<MenuItem>,
icon: &'static str,
bios_proxy: RogBiosProxyBlocking<'static>,
gfx_proxy: GfxProxyBlocking<'static>,
}
impl ROGTray {
pub fn new() -> Result<Self> {
let mut rog_tray = Self {
let conn = zbus::blocking::Connection::system().map_err(|e| {
error!("ROGTray: {e}");
e
})?;
let rog_tray = Self {
tray: AppIndicator::new(TRAY_LABEL, TRAY_APP_ICON),
menu: gtk::Menu::new(),
items: Vec::new(),
icon: TRAY_APP_ICON,
bios_proxy: RogBiosProxyBlocking::new(&conn).map_err(|e| {
error!("ROGTray: {e}");
e
})?,
gfx_proxy: GfxProxyBlocking::new(&conn).map_err(|e| {
error!("ROGTray: {e}");
e
})?,
};
// rog_tray.set_icon(TRAY_APP_ICON);
rog_tray.add_icon_menu_item("Open app", "asus_notif_red", move || {
get_ipc_file().unwrap().write_all(&[SHOW_GUI]).ok();
});
rog_tray.add_inactive_label("----");
Ok(rog_tray)
}
pub fn set_icon(&mut self, icon: &str) {
self.tray.set_icon(icon);
pub fn set_icon(&mut self, icon: &'static str) {
self.icon = icon;
self.tray.set_icon(self.icon);
self.tray.set_status(AppIndicatorStatus::Active);
}
@@ -105,7 +118,14 @@ impl ROGTray {
item.set_sensitive(false);
self.menu.append(&item);
self.menu.show_all();
self.tray.set_menu(&mut self.menu);
}
/// Add a separator
fn add_separator(&mut self) {
let item = gtk::SeparatorMenuItem::new();
item.set_sensitive(false);
self.menu.append(&item);
self.menu.show_all();
}
fn add_radio_sub_menu(&mut self, header_label: &str, active_label: &str, sub_menu: RadioGroup) {
@@ -115,7 +135,11 @@ impl ROGTray {
let menu = gtk::Menu::new();
for item in sub_menu.0.iter() {
item.set_active(item.label().unwrap() == active_label);
if let Some(label) = item.label() {
item.set_active(label == active_label);
} else {
item.set_active(false);
}
item.set_no_show_all(false);
item.show_all();
menu.add(item);
@@ -124,19 +148,29 @@ impl ROGTray {
header_item.set_submenu(Some(&menu));
}
fn add_menu_item<F>(&mut self, label: &str, cb: F)
fn _add_menu_item<F>(&mut self, label: &str, cb: F)
where
F: Fn() + Send + 'static,
{
let item = gtk::MenuItem::with_label(label);
self.items.push(item);
let item = self.items.last().unwrap();
item.connect_activate(move |_| {
cb();
});
self.menu.append(item);
self.menu.append(&item);
self.menu.show_all();
}
fn add_check_menu_item<F>(&mut self, label: &str, is_active: bool, cb: F)
where
F: Fn(&gtk::CheckMenuItem) + Send + 'static,
{
let item = gtk::CheckMenuItem::with_label(label);
item.set_active(is_active);
item.connect_activate(move |this| {
cb(this);
});
self.menu.append(&item);
self.menu.show_all();
self.tray.set_menu(&mut self.menu);
}
/// Add a menu item with an icon to the right
@@ -147,120 +181,251 @@ impl ROGTray {
let g_box = gtk::Box::new(gtk::Orientation::Horizontal, 6);
let icon = gtk::Image::from_gicon(&Icon::for_string(icon).unwrap(), gtk::IconSize::Menu);
let label = gtk::Label::new(Some(label));
let menu_item = gtk::MenuItem::new();
let item = gtk::MenuItem::new();
g_box.add(&icon);
g_box.add(&label);
menu_item.add(&g_box);
menu_item.show_all();
item.add(&g_box);
item.show_all();
self.items.push(menu_item);
let item = self.items.last().unwrap();
item.connect_activate(move |_| {
cb();
});
self.menu.append(item);
self.menu.append(&item);
self.menu.show_all();
self.tray.set_menu(&mut self.menu);
}
fn set_status(&mut self, status: AppIndicatorStatus) {
fn _set_status(&mut self, status: AppIndicatorStatus) {
self.tray.set_status(status)
}
}
fn init_gpu_menu(supported: &SupportedFunctions, tray: &mut ROGTray) {
let conn = zbus::blocking::Connection::system().unwrap();
let gfx_dbus = supergfxctl::zbus_proxy::DaemonProxyBlocking::new(&conn).unwrap();
let mode = gfx_dbus.mode().unwrap();
let mut gpu_menu = RadioGroup::new("Integrated", move |_| {
let mode = gfx_dbus.mode().unwrap();
if mode != GfxMode::Integrated {
gfx_dbus.set_mode(&GfxMode::Integrated).unwrap();
}
});
let gfx_dbus = supergfxctl::zbus_proxy::DaemonProxyBlocking::new(&conn).unwrap();
gpu_menu.add("Hybrid", move |_| {
let mode = gfx_dbus.mode().unwrap();
if mode != GfxMode::Hybrid {
gfx_dbus.set_mode(&GfxMode::Hybrid).unwrap();
}
});
if supported.rog_bios_ctrl.gpu_mux {
let gfx_dbus = rog_dbus::zbus_platform::RogBiosProxyBlocking::new(&conn).unwrap();
gpu_menu.add("Ultimate (Reboot required)", move |_| {
let mode = gfx_dbus.gpu_mux_mode().unwrap();
if mode != GpuMode::Discrete {
gfx_dbus.set_gpu_mux_mode(GpuMode::Discrete).unwrap();
}
});
}
if supported.rog_bios_ctrl.egpu_enable {
let gfx_dbus = supergfxctl::zbus_proxy::DaemonProxyBlocking::new(&conn).unwrap();
gpu_menu.add("eGPU", move |_| {
let mode = gfx_dbus.mode().unwrap();
if mode != GfxMode::Egpu {
gfx_dbus.set_mode(&GfxMode::Egpu).unwrap();
fn menu_add_base(&mut self) {
self.add_icon_menu_item("Open app", "asus_notif_red", move || {
if let Ok(mut ipc) = get_ipc_file().map_err(|e| {
error!("ROGTray: get_ipc_file: {}", e);
}) {
ipc.write_all(&[SHOW_GUI]).ok();
}
});
self.add_separator();
debug!("ROGTray: built base menu");
}
let active = match mode {
GfxMode::AsusMuxDiscreet => "Discreet".to_string(),
_ => mode.to_string(),
};
tray.add_radio_sub_menu("GPU Mode", active.as_str(), gpu_menu);
fn menu_add_charge_limit(&mut self, supported: &SupportedFunctions, limit: u8) {
if supported.charge_ctrl.charge_level_set {
self.add_inactive_label(&format!("Charge limit: {limit}"));
debug!("ROGTray: appended charge limit menu");
}
}
fn menu_add_panel_od(&mut self, supported: &SupportedFunctions, panel_od: bool) {
if supported.rog_bios_ctrl.panel_overdrive {
let bios = self.bios_proxy.clone();
self.add_check_menu_item("Panel Overdrive", panel_od, move |this| {
bios.set_panel_od(this.is_active())
.map_err(|e| {
error!("ROGTray: set_panel_od: {e}");
e
})
.ok();
});
debug!("ROGTray: appended panel overdrive menu");
}
}
fn menu_add_gpu(&mut self, supported: &SupportedFunctions, current_mode: GfxMode) {
let gfx_dbus = self.gfx_proxy.clone();
let mut gpu_menu = RadioGroup::new("Integrated", move |_| {
let mode = gfx_dbus
.mode()
.map_err(|e| {
error!("ROGTray: mode: {e}");
e
})
.unwrap_or(GfxMode::None);
if mode != GfxMode::Integrated {
gfx_dbus
.set_mode(&GfxMode::Integrated)
.map_err(|e| {
error!("ROGTray: srt_mode: {e}");
e
})
.ok();
}
});
let gfx_dbus = self.gfx_proxy.clone();
gpu_menu.add("Hybrid", move |_| {
let mode = gfx_dbus
.mode()
.map_err(|e| {
error!("ROGTray: mode: {e}");
e
})
.unwrap_or(GfxMode::None);
if mode != GfxMode::Hybrid {
gfx_dbus
.set_mode(&GfxMode::Hybrid)
.map_err(|e| {
error!("ROGTray: set_mode: {e}");
e
})
.ok();
}
});
if supported.rog_bios_ctrl.gpu_mux {
let gfx_dbus = self.bios_proxy.clone();
gpu_menu.add("Ultimate (Reboot required)", move |_| {
let mode = gfx_dbus
.gpu_mux_mode()
.map_err(|e| {
error!("ROGTray: mode: {e}");
e
})
.unwrap_or(GpuMode::Error);
if mode != GpuMode::Discrete {
gfx_dbus
.set_gpu_mux_mode(GpuMode::Discrete)
.map_err(|e| {
error!("ROGTray: set_mode: {e}");
e
})
.ok();
}
});
}
if supported.rog_bios_ctrl.egpu_enable {
let gfx_dbus = self.gfx_proxy.clone();
gpu_menu.add("eGPU", move |_| {
let mode = gfx_dbus
.mode()
.map_err(|e| {
error!("ROGTray: mode: {e}");
e
})
.unwrap_or(GfxMode::None);
if mode != GfxMode::Egpu {
gfx_dbus
.set_mode(&GfxMode::Egpu)
.map_err(|e| {
error!("ROGTray: set_mode: {e}");
e
})
.ok();
}
});
}
let active = match current_mode {
GfxMode::AsusMuxDiscreet => "Discreet".to_string(),
_ => current_mode.to_string(),
};
self.add_radio_sub_menu(
&format!("GPU Mode: {current_mode}"),
active.as_str(),
gpu_menu,
);
debug!("ROGTray: appended gpu menu");
}
fn menu_clear(&mut self) {
self.menu = gtk::Menu::new();
debug!("ROGTray: cleared self");
}
/// Reset GTK menu to internal state, this can be called after clearing and rebuilding the menu too.
fn menu_update(&mut self) {
self.tray.set_menu(&mut self.menu);
self.set_icon(self.icon);
}
/// Do a flush, build, and update of the tray menu
fn rebuild_and_update(
&mut self,
supported: &SupportedFunctions,
current_gfx_mode: GfxMode,
charge_limit: u8,
panel_od: bool,
) {
self.menu_clear();
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);
self.menu_update();
}
}
pub fn init_tray(
supported: SupportedFunctions,
recv_command: Receiver<AppToTray>,
states: Arc<Mutex<SystemState>>,
) -> Receiver<TrayToApp> {
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
if gtk::init()
.map_err(|e| {
error!("ROGTray: gtk init {e}");
e
})
.is_err()
{
return;
} // Make this the main thread for gtk
debug!("init_tray gtk");
let mut tray = ROGTray::new().unwrap();
init_gpu_menu(&supported, &mut tray);
// let s1 = send.clone();
// tray.add_menu_item("Quit", move || {
// let lock = s1.lock().unwrap();
// lock.send(TrayToApp::Quit).ok();
// })
// .ok();
//***********************************
// finally do
tray.tray.set_menu(&mut tray.menu);
//***********************************
let mut tray = match ROGTray::new() {
Ok(t) => {
info!("init_tray: built menus");
t
}
Err(e) => {
error!("ROGTray: tray init {e}");
if let Ok(mut states) = states.lock() {
states.error = Some(format!("Could not start tray: {e}"));
}
return;
}
};
tray.rebuild_and_update(&supported, GfxMode::Hybrid, 100, false);
tray.set_icon(TRAY_APP_ICON);
info!("Started ROGTray");
loop {
if let Ok(command) = recv_command.try_recv() {
match command {
AppToTray::DgpuStatus(s) => {
match s {
GfxPower::Active => tray.set_icon("asus_notif_red"),
GfxPower::Suspended => tray.set_icon("asus_notif_blue"),
GfxPower::Off => tray.set_icon("asus_notif_green"),
GfxPower::AsusDisabled => tray.set_icon("asus_notif_white"),
GfxPower::AsusMuxDiscreet => tray.set_icon("asus_notif_red"),
GfxPower::Unknown => tray.set_icon("gpu-integrated"),
};
}
if let Ok(mut lock) = states.lock() {
if lock.tray_should_update {
tray.rebuild_and_update(
&supported,
lock.gfx_state.mode,
lock.power_state.charge_limit,
lock.bios.panel_overdrive,
);
lock.tray_should_update = false;
debug!("ROGTray: rebuilt menus due to state change");
match lock.gfx_state.power_status {
GfxPower::Active => tray.set_icon("asus_notif_red"),
GfxPower::Suspended => tray.set_icon("asus_notif_blue"),
GfxPower::Off => tray.set_icon("asus_notif_green"),
GfxPower::AsusDisabled => tray.set_icon("asus_notif_white"),
GfxPower::AsusMuxDiscreet => tray.set_icon("asus_notif_red"),
GfxPower::Unknown => tray.set_icon("gpu-integrated"),
};
}
}
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));
continue;
}
// Don't spool at max speed if no gtk events
std::thread::sleep(Duration::from_millis(300));
trace!("Tray loop ticked");
}
});
@@ -1,14 +1,9 @@
use egui::{RichText, Ui};
use rog_platform::supported::SupportedFunctions;
use crate::{page_states::PageDataStates, RogDbusClientBlocking};
use crate::system_state::SystemState;
pub fn anime_power_group(
_supported: &SupportedFunctions,
states: &mut PageDataStates,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui,
) {
pub fn anime_power_group(_supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) {
ui.heading("AniMe Matrix Settings");
ui.label("Options are incomplete. Awake + Boot should work");
@@ -43,7 +38,9 @@ pub fn anime_power_group(
});
ui.horizontal_wrapped(|ui| {
if ui.checkbox(&mut states.anime.boot, "Enable").changed() {
dbus.proxies()
states
.asus_dbus
.proxies()
.anime()
.set_boot_on_off(states.anime.boot)
.map_err(|err| {
@@ -54,7 +51,9 @@ pub fn anime_power_group(
});
ui.horizontal_wrapped(|ui| {
if ui.checkbox(&mut states.anime.awake, "Enable").changed() {
dbus.proxies()
states
.asus_dbus
.proxies()
.anime()
.set_on_off(states.anime.awake)
.map_err(|err| {
@@ -1,8 +1,8 @@
use egui::Ui;
use crate::{config::Config, page_states::PageDataStates};
use crate::{config::Config, system_state::SystemState};
pub fn app_settings(config: &mut Config, states: &mut PageDataStates, ui: &mut Ui) {
pub fn app_settings(config: &mut Config, states: &mut SystemState, ui: &mut Ui) {
ui.heading("ROG GUI Settings");
// ui.label("Options are incomplete. Awake + Boot should work");
+6 -9
View File
@@ -7,16 +7,12 @@ use egui::{RichText, Ui};
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour, Speed};
use rog_platform::supported::SupportedFunctions;
use crate::{
page_states::{AuraState, PageDataStates},
RogDbusClientBlocking,
};
use crate::system_state::{AuraState, SystemState};
pub fn aura_modes_group(
supported: &SupportedFunctions,
states: &mut PageDataStates,
states: &mut SystemState,
freq: &mut Arc<AtomicU8>,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui,
) {
let mut changed = false;
@@ -172,8 +168,7 @@ pub fn aura_modes_group(
ui.separator();
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
if ui.add(egui::Button::new("Cancel")).clicked() {
let notif = states.aura.was_notified.clone();
match AuraState::new(notif, supported, dbus) {
match AuraState::new(supported, &states.asus_dbus) {
Ok(a) => states.aura.modes = a.modes,
Err(e) => states.error = Some(e.to_string()),
}
@@ -202,7 +197,9 @@ pub fn aura_modes_group(
if changed {
states.aura.current_mode = selected;
dbus.proxies()
states
.asus_dbus
.proxies()
.led()
.set_led_mode(states.aura.modes.get(&selected).unwrap())
.map_err(|err| {
+16 -25
View File
@@ -5,32 +5,22 @@ use rog_aura::{
};
use rog_platform::supported::SupportedFunctions;
use crate::{page_states::PageDataStates, RogDbusClientBlocking};
use crate::system_state::SystemState;
pub fn aura_power_group(
supported: &SupportedFunctions,
states: &mut PageDataStates,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui,
) {
pub fn aura_power_group(supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) {
ui.heading("LED settings");
match supported.keyboard_led.prod_id {
AuraDevice::X1854 | AuraDevice::X1869 | AuraDevice::X1866 => {
aura_power1(supported, states, dbus, ui)
aura_power1(supported, states, ui)
}
AuraDevice::X19B6 => aura_power2(supported, states, dbus, ui),
AuraDevice::Tuf => aura_power1(supported, states, dbus, ui),
AuraDevice::X19B6 => aura_power2(supported, states, ui),
AuraDevice::Tuf => aura_power1(supported, states, ui),
AuraDevice::Unknown => {}
}
}
fn aura_power1(
supported: &SupportedFunctions,
states: &mut PageDataStates,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui,
) {
fn aura_power1(supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) {
let enabled_states = &mut states.aura.enabled;
let mut boot = enabled_states.x1866.contains(&AuraDev1866::Boot);
let mut sleep = enabled_states.x1866.contains(&AuraDev1866::Sleep);
@@ -144,7 +134,9 @@ fn aura_power1(
x19b6: vec![],
};
// build data to send
dbus.proxies()
states
.asus_dbus
.proxies()
.led()
.set_leds_power(options, enable)
.map_err(|err| {
@@ -193,7 +185,9 @@ fn aura_power1(
x19b6: vec![],
};
// build data to send
dbus.proxies()
states
.asus_dbus
.proxies()
.led()
.set_leds_power(options, enable)
.map_err(|err| {
@@ -207,12 +201,7 @@ fn aura_power1(
}
}
fn aura_power2(
supported: &SupportedFunctions,
states: &mut PageDataStates,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui,
) {
fn aura_power2(supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) {
let enabled_states = &mut states.aura.enabled;
let has_logo = supported
.keyboard_led
@@ -331,7 +320,9 @@ fn aura_power2(
x19b6: data,
};
// build data to send
dbus.proxies()
states
.asus_dbus
.proxies()
.led()
.set_leds_power(options, enable)
.map_err(|err| {
+2 -3
View File
@@ -3,7 +3,7 @@ use rog_platform::supported::SupportedFunctions;
use rog_profiles::{FanCurvePU, Profile};
use crate::{
page_states::{FanCurvesState, ProfilesState},
system_state::{FanCurvesState, ProfilesState},
RogDbusClientBlocking,
};
@@ -136,8 +136,7 @@ pub fn fan_graphs(
})
.ok();
let notif = curves.was_notified.clone();
match FanCurvesState::new(notif, supported, dbus) {
match FanCurvesState::new(supported, dbus) {
Ok(f) => *curves = f,
Err(e) => *do_error = Some(e.to_string()),
}
@@ -1,7 +1,7 @@
use egui::{Align, Color32, Vec2};
use rog_aura::{keys::KeyShape, layouts::KeyLayout, AuraModeNum};
use crate::page_states::AuraState;
use crate::system_state::AuraState;
pub fn keyboard(
ui: &mut egui::Ui,
+20 -15
View File
@@ -1,9 +1,9 @@
use crate::{page_states::PageDataStates, RogDbusClientBlocking};
use crate::system_state::SystemState;
use egui::Ui;
use rog_platform::{platform::GpuMode, supported::SupportedFunctions};
use rog_profiles::Profile;
pub fn platform_profile(states: &mut PageDataStates, dbus: &RogDbusClientBlocking, ui: &mut Ui) {
pub fn platform_profile(states: &mut SystemState, ui: &mut Ui) {
ui.heading("Platform profile");
let mut changed = false;
@@ -23,7 +23,9 @@ pub fn platform_profile(states: &mut PageDataStates, dbus: &RogDbusClientBlockin
});
if changed {
dbus.proxies()
states
.asus_dbus
.proxies()
.profile()
.set_active_profile(states.profiles.current)
.map_err(|err| {
@@ -33,21 +35,18 @@ pub fn platform_profile(states: &mut PageDataStates, dbus: &RogDbusClientBlockin
};
}
pub fn rog_bios_group(
supported: &SupportedFunctions,
states: &mut PageDataStates,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui,
) {
pub fn rog_bios_group(supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) {
ui.heading("Bios options");
let slider = egui::Slider::new(&mut states.charge_limit, 20..=100)
let slider = egui::Slider::new(&mut states.power_state.charge_limit, 20..=100)
.text("Charging limit")
.step_by(1.0);
if ui.add(slider).drag_released() {
dbus.proxies()
states
.asus_dbus
.proxies()
.charge()
.set_charge_control_end_threshold(states.charge_limit as u8)
.set_charge_control_end_threshold(states.power_state.charge_limit as u8)
.map_err(|err| {
states.error = Some(err.to_string());
})
@@ -62,7 +61,9 @@ pub fn rog_bios_group(
))
.changed()
{
dbus.proxies()
states
.asus_dbus
.proxies()
.rog_bios()
.set_post_boot_sound(states.bios.post_sound)
.map_err(|err| {
@@ -79,7 +80,9 @@ pub fn rog_bios_group(
))
.changed()
{
dbus.proxies()
states
.asus_dbus
.proxies()
.rog_bios()
.set_panel_od(states.bios.panel_overdrive)
.map_err(|err| {
@@ -114,7 +117,9 @@ pub fn rog_bios_group(
});
if changed {
dbus.proxies()
states
.asus_dbus
.proxies()
.rog_bios()
.set_gpu_mux_mode(states.bios.dedicated_gfx)
.map_err(|err| {
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::{Page, RogApp};
impl<'a> RogApp<'a> {
impl RogApp {
pub fn side_panel(&mut self, ctx: &egui::Context) {
egui::SidePanel::left("side_panel")
.resizable(false)
+1 -1
View File
@@ -2,7 +2,7 @@ use egui::{vec2, Align2, FontId, Id, Sense};
use crate::{RogApp, VERSION};
impl<'a> RogApp<'a> {
impl RogApp {
pub fn top_bar(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
// The top panel is often a good place for a menu bar:
+2 -2
View File
@@ -52,7 +52,7 @@ impl Profile {
}
pub fn get_active_profile() -> Result<Profile, ProfileError> {
let mut file = OpenOptions::new().read(true).open(&PLATFORM_PROFILE)?;
let mut file = OpenOptions::new().read(true).open(PLATFORM_PROFILE)?;
let mut buf = String::new();
file.read_to_string(&mut buf)?;
@@ -60,7 +60,7 @@ impl Profile {
}
pub fn get_profile_names() -> Result<Vec<Profile>, ProfileError> {
let mut file = OpenOptions::new().read(true).open(&PLATFORM_PROFILES)?;
let mut file = OpenOptions::new().read(true).open(PLATFORM_PROFILES)?;
let mut buf = String::new();
file.read_to_string(&mut buf)?;