Compare commits

...

16 Commits

Author SHA1 Message Date
Luke D. Jones bdb6c5b2ff Prep 4.5.6 release 2022-12-10 21:08:52 +13:00
Luke D. Jones a318fbceec asusd: check if nvidia-powerd enabled before toggling 2022-12-10 21:05:27 +13:00
Luke D. Jones 8feacf863a asusd: Very basic support for running a command on AC/Battery switching 2022-12-10 20:51:00 +13:00
Luke D. Jones 0c62582515 ROGCC: Very basic support for running a command on AC/Battery switching 2022-12-10 20:17:45 +13:00
Luke D. Jones 3c575e4d2a ROGCC: Minor correction to tray menu 2022-12-10 19:37:20 +13:00
Luke D. Jones dbfd73da5e ROGCC: Better handle the use of GPU MUX without supergfxd 2022-12-10 19:30:30 +13:00
Luke D. Jones b1ee449b97 Adjust profile task to help TUF laptops notify 2022-12-09 10:03:45 +13:00
Luke D. Jones 245c035dc9 Fix tasks not always running correctly on boot/sleep/wake/shutdown 2022-12-08 20:12:55 +13:00
Luke D. Jones 07daa0df61 Fix: ROGCC: show option for LED notifications 2022-12-08 16:27:00 +13:00
Luke D. Jones c7893b16f9 Fix: ROGCC: Remove unwrap causing panic on main thread
Closes #293
2022-12-08 11:14:01 +13:00
Luke Jones 8e8681c190 Merge branch 'main' into 'main'
add led modes for FX506HC

See merge request asus-linux/asusctl!144
2022-12-07 20:29:23 +00:00
HerrWinfried b26c6a55f0 add led modes for FX506HC 2022-12-07 11:41:49 +00:00
Luke D. Jones 93d472fe74 Use correct defaults for GfxMode and GfxPower 2022-12-07 12:31:52 +13:00
Luke D. Jones 5469c73f11 Adjust gitlab pipeline to ignore checks for tags 2022-12-07 11:55:09 +13:00
Luke D. Jones ad95765954 Add missing files 2022-12-07 11:50:17 +13:00
Luke D. Jones e42a5bc3e9 ROGCC: don't require supergfxd to be running
Prep fixes for new tag and release
2022-12-07 11:47:27 +13:00
27 changed files with 729 additions and 270 deletions
+1
View File
@@ -2,6 +2,7 @@
vendor.tar.xz vendor.tar.xz
cargo-config cargo-config
.idea .idea
vendor
vendor-* vendor-*
vendor_* vendor_*
.vscode-ctags .vscode-ctags
+7 -2
View File
@@ -17,7 +17,7 @@ cache:
- target/release/.cargo-lock - target/release/.cargo-lock
before_script: before_script:
- apt-get update -qq && apt-get install -y -qq libudev-dev libgtk-3-dev - apt-get update -qq && apt-get install -y -qq libudev-dev libgtk-3-dev grep
stages: stages:
- format - format
@@ -26,13 +26,16 @@ stages:
- release - release
format: format:
image: rust:latest except:
- tags
script: script:
- echo "nightly" > rust-toolchain - echo "nightly" > rust-toolchain
- rustup component add rustfmt - rustup component add rustfmt
- cargo fmt --check - cargo fmt --check
check: check:
except:
- tags
script: script:
- rustup component add clippy - rustup component add clippy
- cargo check - cargo check
@@ -41,6 +44,8 @@ check:
- cargo install cargo-cranky && cargo cranky - cargo install cargo-cranky && cargo cranky
test: test:
except:
- tags
script: script:
- cargo test - cargo test
+26
View File
@@ -5,6 +5,32 @@ 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased]
## [v4.5.6]
### Changed
- Fix tasks not always running correctly on boot/sleep/wake/shutdown by finishing the move to async
- Change how the profile/fan change task monitors changes due to TUF laptops behaving slightly different
- ROGCC: Better handle the use of GPU MUX without supergfxd
- ROGCC: Track if reboot required when not using supergfxd
- Add env var for logging levels to daemon and gui (`RUST_LOG=<error|warn|info|debug|trace>`)
- ROGCC: Very basic support for running a command on AC/Battery switching, this is in config at `~/.config/rog/rog-control-center.cfg`, and for now must be edited by hand and ROGCC restarted (run ROGCC in BG to use effectively)
+ Run ROGCC from terminal to see errors of the AC/Battery command
+ Support for editing via ROGCC GUI will come in future
+ This is ideal for userspace tasks
- asusd: Very basic support for running a command on AC/Battery switching, this is in config at `/etc/asusd/asusd.conf`. A restart of asusd is not required if edited.
+ This is ideal for tasks that require root access (BE SAFE!)
- The above AC/Battery commands are probably best set to run a script for more complex tasks
- asusd: check if nvidia-powerd enabled before toggling
## [v4.5.5]
### Changed
- remove an unwrap() causing panic on main ROGCC thread
## [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] ## [v4.5.3]
### Changed ### Changed
- Adjust how fan graph in ROGCC works, deny incorrect graphs - Adjust how fan graph in ROGCC works, deny incorrect graphs
Generated
+40 -32
View File
@@ -149,7 +149,7 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
[[package]] [[package]]
name = "asusctl" name = "asusctl"
version = "4.5.3" version = "4.5.6"
dependencies = [ dependencies = [
"daemon", "daemon",
"gif", "gif",
@@ -727,7 +727,7 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
[[package]] [[package]]
name = "daemon" name = "daemon"
version = "4.5.3" version = "4.5.6"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"concat-idents", "concat-idents",
@@ -750,7 +750,7 @@ dependencies = [
[[package]] [[package]]
name = "daemon-user" name = "daemon-user"
version = "4.5.3" version = "4.5.6"
dependencies = [ dependencies = [
"dirs", "dirs",
"rog_anime", "rog_anime",
@@ -930,10 +930,18 @@ dependencies = [
"wio", "wio",
] ]
[[package]]
name = "ecolor"
version = "0.20.0"
source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#056fd4bd1ed8c48c035e6b75111cfa8087634934"
dependencies = [
"bytemuck",
]
[[package]] [[package]]
name = "eframe" name = "eframe"
version = "0.19.0" version = "0.20.0"
source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#bb2cb764e48829f865312c5934efdab2169737ae" source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#056fd4bd1ed8c48c035e6b75111cfa8087634934"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"egui", "egui",
@@ -953,8 +961,8 @@ dependencies = [
[[package]] [[package]]
name = "egui" name = "egui"
version = "0.19.0" version = "0.20.0"
source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#bb2cb764e48829f865312c5934efdab2169737ae" source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#056fd4bd1ed8c48c035e6b75111cfa8087634934"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"ahash", "ahash",
@@ -965,8 +973,8 @@ dependencies = [
[[package]] [[package]]
name = "egui-winit" name = "egui-winit"
version = "0.19.0" version = "0.20.0"
source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#bb2cb764e48829f865312c5934efdab2169737ae" source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#056fd4bd1ed8c48c035e6b75111cfa8087634934"
dependencies = [ dependencies = [
"accesskit_winit", "accesskit_winit",
"arboard", "arboard",
@@ -980,8 +988,8 @@ dependencies = [
[[package]] [[package]]
name = "egui_glow" name = "egui_glow"
version = "0.19.0" version = "0.20.0"
source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#bb2cb764e48829f865312c5934efdab2169737ae" source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#056fd4bd1ed8c48c035e6b75111cfa8087634934"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"egui", "egui",
@@ -994,8 +1002,8 @@ dependencies = [
[[package]] [[package]]
name = "emath" name = "emath"
version = "0.19.0" version = "0.20.0"
source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#bb2cb764e48829f865312c5934efdab2169737ae" source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#056fd4bd1ed8c48c035e6b75111cfa8087634934"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
] ]
@@ -1080,13 +1088,14 @@ dependencies = [
[[package]] [[package]]
name = "epaint" name = "epaint"
version = "0.19.0" version = "0.20.0"
source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#bb2cb764e48829f865312c5934efdab2169737ae" source = "git+https://github.com/flukejones/egui?branch=wayland_dark_theme#056fd4bd1ed8c48c035e6b75111cfa8087634934"
dependencies = [ dependencies = [
"ab_glyph", "ab_glyph",
"ahash", "ahash",
"atomic_refcell", "atomic_refcell",
"bytemuck", "bytemuck",
"ecolor",
"emath", "emath",
"nohash-hasher", "nohash-hasher",
"parking_lot", "parking_lot",
@@ -1538,9 +1547,9 @@ dependencies = [
[[package]] [[package]]
name = "glutin" name = "glutin"
version = "0.30.2" version = "0.30.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0282c380a3adb52ae095e5847cc575c6bf79d296dcbf333e00be4a3fca07235e" checksum = "524d807cd49a0c56a53ef9a6738cd15e7c8c4e9d37a3b7fdb3c250c1cd5bf7a3"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg_aliases", "cfg_aliases",
@@ -1554,7 +1563,7 @@ dependencies = [
"objc", "objc",
"once_cell", "once_cell",
"raw-window-handle 0.5.0", "raw-window-handle 0.5.0",
"wayland-sys 0.30.0", "wayland-sys 0.30.1",
"windows-sys 0.36.1", "windows-sys 0.36.1",
"x11-dl", "x11-dl",
] ]
@@ -2593,7 +2602,7 @@ dependencies = [
[[package]] [[package]]
name = "rog-control-center" name = "rog-control-center"
version = "4.5.3" version = "4.5.6"
dependencies = [ dependencies = [
"daemon", "daemon",
"dirs", "dirs",
@@ -2605,7 +2614,6 @@ dependencies = [
"log", "log",
"nix 0.26.1", "nix 0.26.1",
"notify-rust", "notify-rust",
"once_cell",
"png_pong", "png_pong",
"rog_anime", "rog_anime",
"rog_aura", "rog_aura",
@@ -2624,7 +2632,7 @@ dependencies = [
[[package]] [[package]]
name = "rog_anime" name = "rog_anime"
version = "4.5.3" version = "4.5.6"
dependencies = [ dependencies = [
"gif", "gif",
"glam", "glam",
@@ -2639,7 +2647,7 @@ dependencies = [
[[package]] [[package]]
name = "rog_aura" name = "rog_aura"
version = "4.5.3" version = "4.5.6"
dependencies = [ dependencies = [
"serde", "serde",
"serde_derive", "serde_derive",
@@ -2650,7 +2658,7 @@ dependencies = [
[[package]] [[package]]
name = "rog_dbus" name = "rog_dbus"
version = "4.5.3" version = "4.5.6"
dependencies = [ dependencies = [
"rog_anime", "rog_anime",
"rog_aura", "rog_aura",
@@ -2661,7 +2669,7 @@ dependencies = [
[[package]] [[package]]
name = "rog_platform" name = "rog_platform"
version = "4.5.3" version = "4.5.6"
dependencies = [ dependencies = [
"concat-idents", "concat-idents",
"inotify", "inotify",
@@ -2677,7 +2685,7 @@ dependencies = [
[[package]] [[package]]
name = "rog_profiles" name = "rog_profiles"
version = "4.5.3" version = "4.5.6"
dependencies = [ dependencies = [
"serde", "serde",
"serde_derive", "serde_derive",
@@ -2999,7 +3007,7 @@ dependencies = [
[[package]] [[package]]
name = "supergfxctl" name = "supergfxctl"
version = "5.0.2" version = "5.0.2"
source = "git+https://gitlab.com/asus-linux/supergfxctl.git#fa022efb54b752a3672a64c640bd7aebeb842e05" source = "git+https://gitlab.com/asus-linux/supergfxctl.git#387e115a0f338662be313627308201405039d116"
dependencies = [ dependencies = [
"log", "log",
"logind-zbus", "logind-zbus",
@@ -3509,9 +3517,9 @@ dependencies = [
[[package]] [[package]]
name = "wayland-sys" name = "wayland-sys"
version = "0.30.0" version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bcdbc325d8a78a9f49dcb77b39e92656e93b3f69eb4d60245f2116ec4bb0a97" checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06"
dependencies = [ dependencies = [
"dlib", "dlib",
"lazy_static", "lazy_static",
@@ -3868,9 +3876,9 @@ checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
[[package]] [[package]]
name = "zbus" name = "zbus"
version = "3.6.1" version = "3.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbaaf011914a4f69a9ec6361225d8440be69673bda9c888275da99c6e8aad03f" checksum = "938ea6da98c75c2c37a86007bd17fd8e208cbec24e086108c87ece98e9edec0d"
dependencies = [ dependencies = [
"async-broadcast", "async-broadcast",
"async-channel", "async-channel",
@@ -3907,9 +3915,9 @@ dependencies = [
[[package]] [[package]]
name = "zbus_macros" name = "zbus_macros"
version = "3.6.1" version = "3.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a64de32c103d3a845f37adf0f46397d6346c8d48028e218db44dcde981733880" checksum = "45066039ebf3330820e495e854f8b312abb68f0a39e97972d092bd72e8bb3e8e"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
+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"] members = ["asusctl", "daemon", "daemon-user", "rog-platform", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles", "rog-control-center"]
[workspace.package] [workspace.package]
version = "4.5.3" version = "4.5.6"
[workspace.dependencies] [workspace.dependencies]
async-trait = "^0.1" async-trait = "^0.1"
+25 -1
View File
@@ -7,11 +7,12 @@ use std::path::PathBuf;
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf"; pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
#[derive(Deserialize, Serialize, Default)] #[derive(Deserialize, Serialize, Default)]
#[serde(default)]
pub struct Config { pub struct Config {
/// Save charge limit for restoring on boot /// Save charge limit for restoring on boot
pub bat_charge_limit: u8, pub bat_charge_limit: u8,
pub panel_od: bool, pub panel_od: bool,
pub ac_command: String,
pub bat_command: String,
} }
impl Config { impl Config {
@@ -19,6 +20,8 @@ impl Config {
Config { Config {
bat_charge_limit: 100, bat_charge_limit: 100,
panel_od: false, panel_od: false,
ac_command: String::new(),
bat_command: String::new(),
} }
} }
@@ -37,6 +40,8 @@ impl Config {
config = Self::new(); config = Self::new();
} else if let Ok(data) = serde_json::from_str(&buf) { } else if let Ok(data) = serde_json::from_str(&buf) {
config = data; config = data;
} else if let Ok(data) = serde_json::from_str::<Config455>(&buf) {
config = data.into();
} else { } else {
warn!( warn!(
"Could not deserialise {}.\nWill rename to {}-old and recreate config", "Could not deserialise {}.\nWill rename to {}-old and recreate config",
@@ -81,3 +86,22 @@ impl Config {
.unwrap_or_else(|err| error!("Could not write config: {}", err)); .unwrap_or_else(|err| error!("Could not write config: {}", err));
} }
} }
#[derive(Deserialize, Serialize, Default)]
#[serde(default)]
pub struct Config455 {
/// Save charge limit for restoring on boot
pub bat_charge_limit: u8,
pub panel_od: bool,
}
impl From<Config455> for Config {
fn from(c: Config455) -> Self {
Self {
bat_charge_limit: c.bat_charge_limit,
panel_od: c.panel_od,
ac_command: String::new(),
bat_command: String::new(),
}
}
}
+18 -14
View File
@@ -166,28 +166,32 @@ impl crate::CtrlTask for CtrlAnimeZbus {
self.create_sys_event_tasks( self.create_sys_event_tasks(
// Loop is required to try an attempt to get the mutex *without* blocking // Loop is required to try an attempt to get the mutex *without* blocking
// other threads - it is possible to end up with deadlocks otherwise. // other threads - it is possible to end up with deadlocks otherwise.
move || loop { move || {
if let Some(lock) = inner1.try_lock() { let inner1 = inner1.clone();
async move {
let lock = inner1.lock().await;
run_action(true, lock, inner1.clone()); run_action(true, lock, inner1.clone());
break;
} }
}, },
move || loop { move || {
if let Some(lock) = inner2.try_lock() { let inner2 = inner2.clone();
run_action(false, lock, inner2.clone()); async move {
break; let lock = inner2.lock().await;
run_action(true, lock, inner2.clone());
} }
}, },
move || loop { move || {
if let Some(lock) = inner3.try_lock() { let inner3 = inner3.clone();
async move {
let lock = inner3.lock().await;
run_action(true, lock, inner3.clone()); run_action(true, lock, inner3.clone());
break;
} }
}, },
move || loop { move || {
if let Some(lock) = inner4.try_lock() { let inner4 = inner4.clone();
run_action(false, lock, inner4.clone()); async move {
break; let lock = inner4.lock().await;
run_action(true, lock, inner4.clone());
} }
}, },
) )
+19 -15
View File
@@ -262,28 +262,32 @@ impl CtrlTask for CtrlKbdLedZbus {
self.create_sys_event_tasks( self.create_sys_event_tasks(
// Loop so that we do aquire the lock but also don't block other // Loop so that we do aquire the lock but also don't block other
// threads (prevents potential deadlocks) // threads (prevents potential deadlocks)
move || loop { move || {
if let Some(lock) = inner1.try_lock() { let inner1 = inner1.clone();
async move {
let lock = inner1.lock().await;
load_save(true, lock); load_save(true, lock);
break;
} }
}, },
move || loop { move || {
if let Some(lock) = inner2.try_lock() { let inner2 = inner2.clone();
async move {
let lock = inner2.lock().await;
load_save(false, lock); load_save(false, lock);
break;
} }
}, },
move || loop { move || {
if let Some(lock) = inner3.try_lock() { let inner3 = inner3.clone();
load_save(true, lock); async move {
break; let lock = inner3.lock().await;
} load_save(false, lock);
}, }
move || loop { },
if let Some(lock) = inner4.try_lock() { move || {
let inner4 = inner4.clone();
async move {
let lock = inner4.lock().await;
load_save(false, lock); load_save(false, lock);
break;
} }
}, },
) )
+15 -8
View File
@@ -319,7 +319,8 @@ impl CtrlPlatform {
task_watch_item!(panel_od platform); task_watch_item!(panel_od platform);
task_watch_item!(dgpu_disable platform); task_watch_item!(dgpu_disable platform);
task_watch_item!(egpu_enable platform); task_watch_item!(egpu_enable platform);
task_watch_item!(gpu_mux_mode platform); // NOTE: see note further below
//task_watch_item!(gpu_mux_mode platform);
} }
#[async_trait] #[async_trait]
@@ -332,10 +333,12 @@ impl CtrlTask for CtrlPlatform {
let platform1 = self.clone(); let platform1 = self.clone();
let platform2 = self.clone(); let platform2 = self.clone();
self.create_sys_event_tasks( self.create_sys_event_tasks(
move || {}, move || async { {} },
move || { move || {
info!("CtrlRogBios reloading panel_od"); let platform1 = platform1.clone();
if let Some(lock) = platform1.config.try_lock() { async move {
info!("CtrlRogBios reloading panel_od");
let lock = platform1.config.lock().await;
if platform1.platform.has_panel_od() { if platform1.platform.has_panel_od() {
platform1 platform1
.set_panel_overdrive(lock.panel_od) .set_panel_overdrive(lock.panel_od)
@@ -347,10 +350,12 @@ impl CtrlTask for CtrlPlatform {
} }
} }
}, },
move || {}, move || async { {} },
move || { move || {
info!("CtrlRogBios reloading panel_od"); let platform2 = platform2.clone();
if let Some(lock) = platform2.config.try_lock() { async move {
info!("CtrlRogBios reloading panel_od");
let lock = platform2.config.lock().await;
if platform2.platform.has_panel_od() { if platform2.platform.has_panel_od() {
platform2 platform2
.set_panel_overdrive(lock.panel_od) .set_panel_overdrive(lock.panel_od)
@@ -368,7 +373,9 @@ impl CtrlTask for CtrlPlatform {
self.watch_panel_od(signal_ctxt.clone()).await?; self.watch_panel_od(signal_ctxt.clone()).await?;
self.watch_dgpu_disable(signal_ctxt.clone()).await?; self.watch_dgpu_disable(signal_ctxt.clone()).await?;
self.watch_egpu_enable(signal_ctxt.clone()).await?; self.watch_egpu_enable(signal_ctxt.clone()).await?;
self.watch_gpu_mux_mode(signal_ctxt.clone()).await?; // NOTE: Can't have this as a watch because on a write to it, it reverts back to booted-with value
// as it does not actually change until reboot.
//self.watch_gpu_mux_mode(signal_ctxt.clone()).await?;
Ok(()) Ok(())
} }
+62 -34
View File
@@ -1,10 +1,13 @@
use crate::systemd::{do_systemd_unit_action, SystemdUnitAction}; use crate::systemd::{
do_systemd_unit_action, is_systemd_unit_enabled, SystemdUnitAction, SystemdUnitState,
};
use crate::{config::Config, error::RogError, GetSupported}; use crate::{config::Config, error::RogError, GetSupported};
use crate::{task_watch_item, CtrlTask}; use crate::{task_watch_item, CtrlTask};
use async_trait::async_trait; use async_trait::async_trait;
use log::{info, warn}; use log::{error, info, warn};
use rog_platform::power::AsusPower; use rog_platform::power::AsusPower;
use rog_platform::supported::ChargeSupportedFunctions; use rog_platform::supported::ChargeSupportedFunctions;
use std::process::Command;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use tokio::time::sleep; use tokio::time::sleep;
@@ -155,10 +158,12 @@ impl CtrlTask for CtrlPower {
let power1 = self.clone(); let power1 = self.clone();
let power2 = self.clone(); let power2 = self.clone();
self.create_sys_event_tasks( self.create_sys_event_tasks(
move || {}, move || async {},
move || { move || {
info!("CtrlCharge reloading charge limit"); let power1 = power1.clone();
if let Some(lock) = power1.config.try_lock() { async move {
info!("CtrlCharge reloading charge limit");
let lock = power1.config.lock().await;
power1 power1
.set(lock.bat_charge_limit) .set(lock.bat_charge_limit)
.map_err(|err| { .map_err(|err| {
@@ -166,22 +171,18 @@ impl CtrlTask for CtrlPower {
err err
}) })
.ok(); .ok();
}
if let Ok(value) = power1.power.get_online() { if let Ok(value) = power1.power.get_online() {
let action = if value == 1 { do_nvidia_powerd_action(value == 1);
SystemdUnitAction::Restart
} else {
SystemdUnitAction::Stop
};
if do_systemd_unit_action(action, NVIDIA_POWERD).is_ok() {
info!("CtrlPower task: did {action:?} on {NVIDIA_POWERD}");
} }
} }
}, },
move || {}, move || async {},
move || { move || {
info!("CtrlCharge reloading charge limit"); let power2 = power2.clone();
if let Some(lock) = power2.config.try_lock() { async move {
info!("CtrlCharge reloading charge limit");
let lock = power2.config.lock().await;
power2 power2
.set(lock.bat_charge_limit) .set(lock.bat_charge_limit)
.map_err(|err| { .map_err(|err| {
@@ -189,21 +190,16 @@ impl CtrlTask for CtrlPower {
err err
}) })
.ok(); .ok();
}
if let Ok(value) = power2.power.get_online() { if let Ok(value) = power2.power.get_online() {
let action = if value == 1 { do_nvidia_powerd_action(value == 1);
SystemdUnitAction::Restart
} else {
SystemdUnitAction::Stop
};
if do_systemd_unit_action(action, NVIDIA_POWERD).is_ok() {
info!("CtrlPower task: did {action:?} on {NVIDIA_POWERD}");
} }
} }
}, },
) )
.await; .await;
let config = self.config.clone();
self.watch_charge_control_end_threshold(signal_ctxt.clone()) self.watch_charge_control_end_threshold(signal_ctxt.clone())
.await?; .await?;
@@ -214,18 +210,36 @@ impl CtrlTask for CtrlPower {
if let Ok(value) = ctrl.power.get_online() { if let Ok(value) = ctrl.power.get_online() {
if online != value { if online != value {
online = value; online = value;
let action = if value == 1 { do_nvidia_powerd_action(value == 1);
SystemdUnitAction::Restart
} else {
SystemdUnitAction::Stop
};
if do_systemd_unit_action(action, NVIDIA_POWERD).is_ok() {
info!("CtrlPower task: did {action:?} on {NVIDIA_POWERD}");
}
Self::notify_mains_online(&signal_ctxt, value == 1) Self::notify_mains_online(&signal_ctxt, value == 1)
.await .await
.unwrap(); .unwrap();
let mut config = config.lock().await;
config.read();
let mut prog: Vec<&str> = Vec::new();
if value == 1 {
// AC ONLINE
prog = config.ac_command.split_whitespace().collect();
} else if value == 0 {
// BATTERY
prog = config.bat_command.split_whitespace().collect();
}
if prog.len() > 1 {
let mut cmd = Command::new(prog[0]);
for arg in prog.iter().skip(1) {
cmd.arg(*arg);
}
if let Err(e) = cmd.spawn() {
if value == 1 {
error!("AC power command error: {e}");
} else {
error!("Battery power command error: {e}");
}
}
}
} }
} }
// The inotify doesn't pick up events when the kernel changes internal value // The inotify doesn't pick up events when the kernel changes internal value
@@ -237,3 +251,17 @@ impl CtrlTask for CtrlPower {
Ok(()) Ok(())
} }
} }
fn do_nvidia_powerd_action(ac_on: bool) {
let action = if ac_on {
SystemdUnitAction::Restart
} else {
SystemdUnitAction::Stop
};
if let Ok(res) = is_systemd_unit_enabled(SystemdUnitState::Enabled, NVIDIA_POWERD) {
if res && do_systemd_unit_action(action, NVIDIA_POWERD).is_ok() {
info!("CtrlPower task: did {action:?} on {NVIDIA_POWERD}");
}
}
}
+33 -3
View File
@@ -200,8 +200,36 @@ impl CtrlTask for ProfileZbus {
} }
async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> {
// let ctrl = self.0.clone();
// let mut watch = self.0.lock().await.platform.monitor_platform_profile()?;
// let sig_ctx = signal_ctxt.clone();
// tokio::spawn(async move {
// let mut buffer = [0; 32];
// watch
// .event_stream(&mut buffer)
// .unwrap()
// .for_each(|_| async {
// let mut lock = ctrl.lock().await;
// let new_profile = Profile::get_active_profile().unwrap();
// if new_profile != lock.config.active_profile {
// lock.config.active_profile = new_profile;
// lock.write_profile_curve_to_platform().unwrap();
// lock.save_config();
// }
// Self::notify_profile(&sig_ctx, lock.config.active_profile)
// .await
// .ok();
// })
// .await;
// });
let ctrl = self.0.clone(); let ctrl = self.0.clone();
let mut watch = self.0.lock().await.platform.monitor_platform_profile()?; let mut watch = self
.0
.lock()
.await
.platform
.monitor_throttle_thermal_policy()?;
tokio::spawn(async move { tokio::spawn(async move {
let mut buffer = [0; 32]; let mut buffer = [0; 32];
@@ -210,13 +238,15 @@ impl CtrlTask for ProfileZbus {
.unwrap() .unwrap()
.for_each(|_| async { .for_each(|_| async {
let mut lock = ctrl.lock().await; let mut lock = ctrl.lock().await;
let new_profile = Profile::get_active_profile().unwrap(); let new_thermal = lock.platform.get_throttle_thermal_policy().unwrap();
let new_profile = Profile::from_throttle_thermal_policy(new_thermal);
if new_profile != lock.config.active_profile { if new_profile != lock.config.active_profile {
lock.config.active_profile = new_profile; lock.config.active_profile = new_profile;
lock.write_profile_curve_to_platform().unwrap(); lock.write_profile_curve_to_platform().unwrap();
lock.save_config(); lock.save_config();
Profile::set_profile(lock.config.active_profile).unwrap();
} }
Self::notify_profile(&signal_ctxt.clone(), lock.config.active_profile) Self::notify_profile(&signal_ctxt, lock.config.active_profile)
.await .await
.ok(); .ok();
}) })
+1 -2
View File
@@ -7,7 +7,6 @@ use std::time::Duration;
use ::zbus::export::futures_util::lock::Mutex; use ::zbus::export::futures_util::lock::Mutex;
use ::zbus::Connection; use ::zbus::Connection;
use daemon::ctrl_anime::CtrlAnime; use daemon::ctrl_anime::CtrlAnime;
use log::LevelFilter;
use log::{error, info, warn}; use log::{error, info, warn};
use tokio::time::sleep; use tokio::time::sleep;
use zbus::SignalContext; use zbus::SignalContext;
@@ -33,9 +32,9 @@ static PROFILE_CONFIG_PATH: &str = "/etc/asusd/profile.conf";
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = env_logger::Builder::new(); let mut logger = env_logger::Builder::new();
logger logger
.parse_default_env()
.target(env_logger::Target::Stdout) .target(env_logger::Target::Stdout)
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args())) .format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
.filter(None, LevelFilter::Info)
.init(); .init();
let is_service = match env::var_os("IS_SERVICE") { let is_service = match env::var_os("IS_SERVICE") {
+35 -11
View File
@@ -21,9 +21,11 @@ pub mod ctrl_supported;
pub mod error; pub mod error;
use std::future::Future;
use crate::error::RogError; use crate::error::RogError;
use async_trait::async_trait; use async_trait::async_trait;
use log::warn; use log::{debug, warn};
use logind_zbus::manager::ManagerProxy; use logind_zbus::manager::ManagerProxy;
use zbus::{export::futures_util::StreamExt, zvariant::ObjectPath, Connection, SignalContext}; use zbus::{export::futures_util::StreamExt, zvariant::ObjectPath, Connection, SignalContext};
@@ -134,13 +136,31 @@ pub trait CtrlTask {
/// ///
/// The closures can potentially block, so execution time should be the minimal possible /// The closures can potentially block, so execution time should be the minimal possible
/// such as save a variable. /// such as save a variable.
async fn create_sys_event_tasks( async fn create_sys_event_tasks<
Fut1,
Fut2,
Fut3,
Fut4,
F1: Send + 'static,
F2: Send + 'static,
F3: Send + 'static,
F4: Send + 'static,
>(
&self, &self,
mut on_sleep: impl FnMut() + Send + 'static, mut on_sleep: F1,
mut on_wake: impl FnMut() + Send + 'static, mut on_wake: F2,
mut on_shutdown: impl FnMut() + Send + 'static, mut on_shutdown: F3,
mut on_boot: impl FnMut() + Send + 'static, mut on_boot: F4,
) { ) where
F1: FnMut() -> Fut1,
F2: FnMut() -> Fut2,
F3: FnMut() -> Fut3,
F4: FnMut() -> Fut4,
Fut1: Future<Output = ()> + Send,
Fut2: Future<Output = ()> + Send,
Fut3: Future<Output = ()> + Send,
Fut4: Future<Output = ()> + Send,
{
let connection = Connection::system() let connection = Connection::system()
.await .await
.expect("Controller could not create dbus connection"); .expect("Controller could not create dbus connection");
@@ -154,9 +174,11 @@ pub trait CtrlTask {
while let Some(event) = notif.next().await { while let Some(event) = notif.next().await {
if let Ok(args) = event.args() { if let Ok(args) = event.args() {
if args.start { if args.start {
on_sleep(); debug!("Doing on_sleep()");
on_sleep().await;
} else if !args.start() { } else if !args.start() {
on_wake(); debug!("Doing on_wake()");
on_wake().await;
} }
} }
} }
@@ -172,9 +194,11 @@ pub trait CtrlTask {
while let Some(event) = notif.next().await { while let Some(event) = notif.next().await {
if let Ok(args) = event.args() { if let Ok(args) = event.args() {
if args.start { if args.start {
on_shutdown(); debug!("Doing on_shutdown()");
on_shutdown().await;
} else if !args.start() { } else if !args.start() {
on_boot(); debug!("Doing on_boot()");
on_boot().await;
} }
} }
} }
+21
View File
@@ -24,6 +24,9 @@ impl From<SystemdUnitAction> for &str {
pub enum SystemdUnitState { pub enum SystemdUnitState {
Active, Active,
Inactive, Inactive,
Masked,
Disabled,
Enabled,
} }
impl From<SystemdUnitState> for &str { impl From<SystemdUnitState> for &str {
@@ -31,6 +34,9 @@ impl From<SystemdUnitState> for &str {
match s { match s {
SystemdUnitState::Active => "active", SystemdUnitState::Active => "active",
SystemdUnitState::Inactive => "inactive", SystemdUnitState::Inactive => "inactive",
SystemdUnitState::Masked => "masked",
SystemdUnitState::Disabled => "disabled",
SystemdUnitState::Enabled => "enabled",
} }
} }
} }
@@ -66,6 +72,21 @@ pub fn is_systemd_unit_state(state: SystemdUnitState, unit: &str) -> Result<bool
Ok(false) Ok(false)
} }
/// Get systemd unit state. Blocks while command is run.
pub fn is_systemd_unit_enabled(state: SystemdUnitState, unit: &str) -> Result<bool, RogError> {
let mut cmd = Command::new("systemctl");
cmd.arg("is-enabled");
cmd.arg(unit);
let output = cmd
.output()
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
if output.stdout.starts_with(<&str>::from(state).as_bytes()) {
return Ok(true);
}
Ok(false)
}
/// Wait for a systemd unit to change to `state`. Checks state every 250ms for 3 seconds. Blocks while running wait. /// Wait for a systemd unit to change to `state`. Checks state every 250ms for 3 seconds. Blocks while running wait.
pub fn wait_systemd_unit_state(state: SystemdUnitState, unit: &str) -> Result<(), RogError> { pub fn wait_systemd_unit_state(state: SystemdUnitState, unit: &str) -> Result<(), RogError> {
let mut cmd = Command::new("systemctl"); let mut cmd = Command::new("systemctl");
+7
View File
@@ -1,3 +1,10 @@
[[led_data]]
prod_family = "ASUS TUF Gaming F15"
board_names = ["FX506HC"]
standard = ["Static", "Breathe", "Strobe", "Pulse"]
multizone = []
per_key = false
[[led_data]] [[led_data]]
prod_family = "TUF" prod_family = "TUF"
board_names = ["FA507"] board_names = ["FA507"]
+1
View File
@@ -6,6 +6,7 @@ Before=multi-user.target
[Service] [Service]
Environment=IS_SERVICE=1 Environment=IS_SERVICE=1
Environment=RUST_LOG="info"
ExecStartPre=/bin/sleep 2 ExecStartPre=/bin/sleep 2
ExecStart=/usr/bin/asusd ExecStart=/usr/bin/asusd
Restart=on-failure Restart=on-failure
+1 -5
View File
@@ -10,8 +10,7 @@ mocking = []
[dependencies] [dependencies]
egui = { git = "https://github.com/flukejones/egui", branch = "wayland_dark_theme" } egui = { git = "https://github.com/flukejones/egui", branch = "wayland_dark_theme" }
eframe= { git = "https://github.com/flukejones/egui", branch = "wayland_dark_theme" } eframe = { git = "https://github.com/flukejones/egui", branch = "wayland_dark_theme" }
#eframe= { git = "https://github.com/emilk/egui", default-features = false, features = ["dark-light", "default_fonts", "wgpu"] }
libappindicator = "0.7" # Tray icon libappindicator = "0.7" # Tray icon
gtk = "0.15.5" gtk = "0.15.5"
@@ -23,7 +22,6 @@ rog_aura = { path = "../rog-aura" }
rog_profiles = { path = "../rog-profiles" } rog_profiles = { path = "../rog-profiles" }
rog_platform = { path = "../rog-platform" } rog_platform = { path = "../rog-platform" }
supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git", default-features = false } supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git", default-features = false }
#supergfxctl = { path = "../../supergfxctl", default-features = false }
log.workspace = true log.workspace = true
env_logger.workspace = true env_logger.workspace = true
@@ -41,5 +39,3 @@ png_pong.workspace = true
nix = "^0.26.1" nix = "^0.26.1"
tempfile = "3.3.0" tempfile = "3.3.0"
once_cell = "1.10.0"
+30 -3
View File
@@ -4,19 +4,20 @@ use std::{
fs::{create_dir, OpenOptions}, fs::{create_dir, OpenOptions},
io::{Read, Write}, io::{Read, Write},
}; };
//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_DIR: &str = "rog";
const CFG_FILE_NAME: &str = "rog-control-center.cfg"; const CFG_FILE_NAME: &str = "rog-control-center.cfg";
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct Config { pub struct Config {
pub run_in_background: bool, pub run_in_background: bool,
pub startup_in_background: bool, pub startup_in_background: bool,
pub ac_command: String,
pub bat_command: String,
pub enable_notifications: bool, pub enable_notifications: bool,
// This field must be last
pub enabled_notifications: EnabledNotifications, pub enabled_notifications: EnabledNotifications,
} }
@@ -27,6 +28,8 @@ impl Default for Config {
startup_in_background: false, startup_in_background: false,
enable_notifications: true, enable_notifications: true,
enabled_notifications: EnabledNotifications::default(), enabled_notifications: EnabledNotifications::default(),
ac_command: String::new(),
bat_command: String::new(),
} }
} }
} }
@@ -67,6 +70,9 @@ impl Config {
} else if let Ok(data) = toml::from_str::<Config>(&buf) { } else if let Ok(data) = toml::from_str::<Config>(&buf) {
info!("Loaded config file {path:?}"); info!("Loaded config file {path:?}");
return Ok(data); return Ok(data);
} else if let Ok(data) = toml::from_str::<Config455>(&buf) {
info!("Loaded old v4.5.5 config file {path:?}");
return Ok(data.into());
} }
} }
Err(Error::ConfigLoadFail) Err(Error::ConfigLoadFail)
@@ -100,3 +106,24 @@ impl Config {
Ok(()) Ok(())
} }
} }
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Config455 {
pub run_in_background: bool,
pub startup_in_background: bool,
pub enable_notifications: bool,
pub enabled_notifications: EnabledNotifications,
}
impl From<Config455> for Config {
fn from(c: Config455) -> Self {
Self {
run_in_background: c.run_in_background,
startup_in_background: c.startup_in_background,
enable_notifications: c.enable_notifications,
enabled_notifications: c.enabled_notifications,
ac_command: String::new(),
bat_command: String::new(),
}
}
}
+1 -1
View File
@@ -13,11 +13,11 @@ pub mod config;
pub mod error; pub mod error;
#[cfg(feature = "mocking")] #[cfg(feature = "mocking")]
pub mod mocking; pub mod mocking;
pub mod notify;
pub mod pages; pub mod pages;
pub mod startup_error; pub mod startup_error;
pub mod system_state; pub mod system_state;
pub mod tray; pub mod tray;
pub mod update_and_notify;
pub mod widgets; pub mod widgets;
#[cfg(feature = "mocking")] #[cfg(feature = "mocking")]
+9 -8
View File
@@ -1,12 +1,12 @@
use eframe::{IconData, NativeOptions}; use eframe::{IconData, NativeOptions};
use log::{error, info, LevelFilter}; use log::{error, info};
use rog_aura::layouts::KeyLayout; use rog_aura::layouts::KeyLayout;
use rog_control_center::notify::EnabledNotifications;
use rog_control_center::tray::init_tray; use rog_control_center::tray::init_tray;
use rog_control_center::update_and_notify::EnabledNotifications;
use rog_control_center::{ use rog_control_center::{
config::Config, error::Result, get_ipc_file, notify::start_notifications, on_tmp_dir_exists, config::Config, error::Result, get_ipc_file, on_tmp_dir_exists, print_versions,
print_versions, startup_error::AppErrorShow, system_state::SystemState, RogApp, startup_error::AppErrorShow, system_state::SystemState, update_and_notify::start_notifications,
RogDbusClientBlocking, SHOWING_GUI, SHOW_GUI, RogApp, RogDbusClientBlocking, SHOWING_GUI, SHOW_GUI,
}; };
use rog_platform::supported::SupportedFunctions; use rog_platform::supported::SupportedFunctions;
use std::sync::Mutex; use std::sync::Mutex;
@@ -29,9 +29,9 @@ fn main() -> Result<()> {
print_versions(); print_versions();
let mut logger = env_logger::Builder::new(); let mut logger = env_logger::Builder::new();
logger logger
.parse_default_env()
.target(env_logger::Target::Stdout) .target(env_logger::Target::Stdout)
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args())) .format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
.filter(None, LevelFilter::Info)
.init(); .init();
// start tokio // start tokio
@@ -118,7 +118,7 @@ fn main() -> Result<()> {
Err(_) => on_tmp_dir_exists().unwrap(), Err(_) => on_tmp_dir_exists().unwrap(),
}; };
let states = setup_page_state_and_notifs(layout, enabled_notifications, &supported)?; let states = setup_page_state_and_notifs(layout, enabled_notifications, &config, &supported)?;
init_tray(supported, states.clone()); init_tray(supported, states.clone());
@@ -153,6 +153,7 @@ fn main() -> Result<()> {
fn setup_page_state_and_notifs( fn setup_page_state_and_notifs(
keyboard_layout: KeyLayout, keyboard_layout: KeyLayout,
enabled_notifications: Arc<Mutex<EnabledNotifications>>, enabled_notifications: Arc<Mutex<EnabledNotifications>>,
config: &Config,
supported: &SupportedFunctions, supported: &SupportedFunctions,
) -> Result<Arc<Mutex<SystemState>>> { ) -> Result<Arc<Mutex<SystemState>>> {
let page_states = Arc::new(Mutex::new(SystemState::new( let page_states = Arc::new(Mutex::new(SystemState::new(
@@ -161,7 +162,7 @@ fn setup_page_state_and_notifs(
supported, supported,
)?)); )?));
start_notifications(page_states.clone(), enabled_notifications)?; start_notifications(config, page_states.clone(), enabled_notifications)?;
Ok(page_states) Ok(page_states)
} }
+7 -3
View File
@@ -12,7 +12,7 @@ use supergfxctl::{
zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking, zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking,
}; };
use crate::{error::Result, notify::EnabledNotifications, RogDbusClientBlocking}; use crate::{error::Result, update_and_notify::EnabledNotifications, RogDbusClientBlocking};
use log::error; use log::error;
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@@ -219,6 +219,7 @@ impl AnimeState {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct GfxState { pub struct GfxState {
pub has_supergfx: bool,
pub mode: GfxMode, pub mode: GfxMode,
pub power_status: GfxPower, pub power_status: GfxPower,
} }
@@ -226,8 +227,9 @@ pub struct GfxState {
impl GfxState { impl GfxState {
pub fn new(_supported: &SupportedFunctions, dbus: &GfxProxyBlocking<'_>) -> Result<Self> { pub fn new(_supported: &SupportedFunctions, dbus: &GfxProxyBlocking<'_>) -> Result<Self> {
Ok(Self { Ok(Self {
mode: dbus.mode()?, has_supergfx: dbus.mode().is_ok(),
power_status: dbus.power()?, mode: dbus.mode().unwrap_or(GfxMode::None),
power_status: dbus.power().unwrap_or(GfxPower::Unknown),
}) })
} }
} }
@@ -235,6 +237,7 @@ impl GfxState {
impl Default for GfxState { impl Default for GfxState {
fn default() -> Self { fn default() -> Self {
Self { Self {
has_supergfx: false,
mode: GfxMode::None, mode: GfxMode::None,
power_status: GfxPower::Unknown, power_status: GfxPower::Unknown,
} }
@@ -401,6 +404,7 @@ impl Default for SystemState {
drag_delta: Default::default(), drag_delta: Default::default(),
}, },
gfx_state: GfxState { gfx_state: GfxState {
has_supergfx: false,
mode: GfxMode::None, mode: GfxMode::None,
power_status: GfxPower::Unknown, power_status: GfxPower::Unknown,
}, },
+143 -24
View File
@@ -4,6 +4,7 @@
use std::{ use std::{
io::Write, io::Write,
sync::{ sync::{
atomic::{AtomicBool, Ordering},
mpsc::{channel, Receiver}, mpsc::{channel, Receiver},
Arc, Mutex, Arc, Mutex,
}, },
@@ -21,7 +22,7 @@ use supergfxctl::{
zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking, zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking,
}; };
use log::{debug, error, info, trace}; use log::{debug, error, info, trace, warn};
const TRAY_APP_ICON: &str = "rog-control-center"; const TRAY_APP_ICON: &str = "rog-control-center";
const TRAY_LABEL: &str = "ROG Control Center"; const TRAY_LABEL: &str = "ROG Control Center";
@@ -241,7 +242,10 @@ impl ROGTray {
} }
fn menu_add_gpu(&mut self, supported: &SupportedFunctions, current_mode: GfxMode) { fn menu_add_gpu(&mut self, supported: &SupportedFunctions, current_mode: GfxMode) {
let set_mux_off = Arc::new(AtomicBool::new(false));
let gfx_dbus = self.gfx_proxy.clone(); let gfx_dbus = self.gfx_proxy.clone();
let set_mux_off1 = set_mux_off.clone();
let mut gpu_menu = RadioGroup::new("Integrated", move |_| { let mut gpu_menu = RadioGroup::new("Integrated", move |_| {
let mode = gfx_dbus let mode = gfx_dbus
.mode() .mode()
@@ -259,9 +263,11 @@ impl ROGTray {
}) })
.ok(); .ok();
} }
set_mux_off1.store(true, Ordering::Relaxed);
}); });
let gfx_dbus = self.gfx_proxy.clone(); let gfx_dbus = self.gfx_proxy.clone();
let set_mux_off1 = set_mux_off.clone();
gpu_menu.add("Hybrid", move |_| { gpu_menu.add("Hybrid", move |_| {
let mode = gfx_dbus let mode = gfx_dbus
.mode() .mode()
@@ -279,7 +285,33 @@ impl ROGTray {
}) })
.ok(); .ok();
} }
set_mux_off1.store(true, Ordering::Relaxed);
}); });
if supported.rog_bios_ctrl.egpu_enable {
let set_mux_off1 = set_mux_off.clone();
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();
}
set_mux_off1.store(true, Ordering::Relaxed);
});
}
let mut reboot_required = false;
if supported.rog_bios_ctrl.gpu_mux { if supported.rog_bios_ctrl.gpu_mux {
let gfx_dbus = self.bios_proxy.clone(); let gfx_dbus = self.bios_proxy.clone();
gpu_menu.add("Ultimate (Reboot required)", move |_| { gpu_menu.add("Ultimate (Reboot required)", move |_| {
@@ -300,35 +332,95 @@ impl ROGTray {
.ok(); .ok();
} }
}); });
}
if supported.rog_bios_ctrl.egpu_enable { if set_mux_off.load(Ordering::Relaxed) {
let gfx_dbus = self.gfx_proxy.clone(); warn!("Selected non-dgpu mode, must set MUX to optimus");
gpu_menu.add("eGPU", move |_| { self.bios_proxy
let mode = gfx_dbus .set_gpu_mux_mode(GpuMode::Optimus)
.mode()
.map_err(|e| { .map_err(|e| {
error!("ROGTray: mode: {e}"); error!("ROGTray: set_mode: {e}");
e e
}) })
.unwrap_or(GfxMode::None); .ok();
if mode != GfxMode::Egpu { }
gfx_dbus
.set_mode(&GfxMode::Egpu) if let Ok(mode) = self.bios_proxy.gpu_mux_mode() {
.map_err(|e| { let mode = match mode {
error!("ROGTray: set_mode: {e}"); GpuMode::Discrete => GfxMode::AsusMuxDiscreet,
e _ => GfxMode::Hybrid,
}) };
.ok(); reboot_required = mode != current_mode;
} }
});
} }
let active = match current_mode { let active = match current_mode {
GfxMode::AsusMuxDiscreet => "Discreet".to_owned(), GfxMode::AsusMuxDiscreet => "Discreet".to_owned(),
_ => current_mode.to_string(), _ => current_mode.to_string(),
}; };
let reboot_required = if reboot_required {
"(Reboot required)"
} else {
""
};
self.add_radio_sub_menu( self.add_radio_sub_menu(
&format!("GPU Mode: {current_mode}"), &format!("GPU Mode: {active} {reboot_required}"),
active.as_str(),
&gpu_menu,
);
debug!("ROGTray: appended gpu menu");
}
fn menu_add_mux(&mut self, current_mode: GfxMode) {
let gfx_dbus = self.bios_proxy.clone();
let mut reboot_required = false;
if let Ok(mode) = gfx_dbus.gpu_mux_mode() {
let mode = match mode {
GpuMode::Discrete => GfxMode::AsusMuxDiscreet,
_ => GfxMode::Hybrid,
};
reboot_required = mode != current_mode;
}
let mut gpu_menu = RadioGroup::new("Optimus", move |_| {
gfx_dbus
.set_gpu_mux_mode(GpuMode::Optimus)
.map_err(|e| {
error!("ROGTray: set_mode: {e}");
e
})
.ok();
debug!("Setting GPU mode: {}", GpuMode::Optimus);
});
let gfx_dbus = self.bios_proxy.clone();
gpu_menu.add("Ultimate", move |_| {
gfx_dbus
.set_gpu_mux_mode(GpuMode::Discrete)
.map_err(|e| {
error!("ROGTray: set_mode: {e}");
e
})
.ok();
debug!("Setting GPU mode: {}", GpuMode::Discrete);
});
let active = match current_mode {
GfxMode::AsusMuxDiscreet => "Ultimate".to_owned(),
GfxMode::Hybrid => "Optimus".to_owned(),
_ => current_mode.to_string(),
};
debug!("Current active GPU mode: {}", active);
let reboot_required = if reboot_required {
"(Reboot required)"
} else {
""
};
self.add_radio_sub_menu(
&format!("GPU Mode: {active} {reboot_required}"),
active.as_str(), active.as_str(),
&gpu_menu, &gpu_menu,
); );
@@ -351,6 +443,7 @@ impl ROGTray {
fn rebuild_and_update( fn rebuild_and_update(
&mut self, &mut self,
supported: &SupportedFunctions, supported: &SupportedFunctions,
has_supergfx: bool,
current_gfx_mode: GfxMode, current_gfx_mode: GfxMode,
charge_limit: u8, charge_limit: u8,
panel_od: bool, panel_od: bool,
@@ -359,7 +452,11 @@ impl ROGTray {
self.menu_add_base(); self.menu_add_base();
self.menu_add_charge_limit(supported, charge_limit); self.menu_add_charge_limit(supported, charge_limit);
self.menu_add_panel_od(supported, panel_od); 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);
} else if supported.rog_bios_ctrl.gpu_mux {
self.menu_add_mux(current_gfx_mode);
}
self.menu_update(); self.menu_update();
} }
} }
@@ -371,6 +468,12 @@ pub fn init_tray(
let (send, recv) = channel(); let (send, recv) = channel();
let _send = Arc::new(Mutex::new(send)); 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 || { std::thread::spawn(move || {
if gtk::init() if gtk::init()
.map_err(|e| { .map_err(|e| {
@@ -396,16 +499,26 @@ pub fn init_tray(
return; 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); tray.set_icon(TRAY_APP_ICON);
info!("Started ROGTray"); info!("Started ROGTray");
loop { loop {
if let Ok(mut lock) = states.lock() { if let Ok(mut lock) = states.lock() {
if lock.tray_should_update { if lock.tray_should_update {
// Supergfx ends up adding some complexity to handle if it isn't available
let current_gpu_mode = if lock.gfx_state.has_supergfx {
lock.gfx_state.mode
} else {
match lock.bios.dedicated_gfx {
GpuMode::Discrete => GfxMode::AsusMuxDiscreet,
_ => GfxMode::Hybrid,
}
};
tray.rebuild_and_update( tray.rebuild_and_update(
&supported, &supported,
lock.gfx_state.mode, has_supergfx,
current_gpu_mode,
lock.power_state.charge_limit, lock.power_state.charge_limit,
lock.bios.panel_overdrive, lock.bios.panel_overdrive,
); );
@@ -419,7 +532,13 @@ pub fn init_tray(
GfxPower::AsusMuxDiscreet | GfxPower::Active => { GfxPower::AsusMuxDiscreet | GfxPower::Active => {
tray.set_icon("asus_notif_red"); 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");
}
}
}; };
} }
} }
@@ -1,5 +1,9 @@
//! `update_and_notify` is responsible for both notifications *and* updating stored statuses
//! about the system state. This is done through either direct, intoify, zbus notifications
//! or similar methods.
use crate::{config::Config, error::Result, system_state::SystemState}; use crate::{config::Config, error::Result, system_state::SystemState};
use log::{error, info, trace}; use log::{error, info, trace, warn};
use notify_rust::{Hint, Notification, NotificationHandle, Urgency}; use notify_rust::{Hint, Notification, NotificationHandle, Urgency};
use rog_dbus::{ use rog_dbus::{
zbus_anime::AnimeProxy, zbus_led::LedProxy, zbus_platform::RogBiosProxy, zbus_anime::AnimeProxy, zbus_led::LedProxy, zbus_platform::RogBiosProxy,
@@ -12,12 +16,17 @@ use std::{
fmt::Display, fmt::Display,
process::Command, process::Command,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
time::Duration,
}; };
use supergfxctl::{pci_device::GfxPower, zbus_proxy::DaemonProxy as SuperProxy}; use supergfxctl::{pci_device::GfxPower, zbus_proxy::DaemonProxy as SuperProxy};
use tokio::time::sleep;
use zbus::export::futures_util::{future, StreamExt}; use zbus::export::futures_util::{future, StreamExt};
const NOTIF_HEADER: &str = "ROG Control"; const NOTIF_HEADER: &str = "ROG Control";
static mut POWER_AC_CMD: Option<Command> = None;
static mut POWER_BAT_CMD: Option<Command> = None;
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)] #[serde(default)]
pub struct EnabledNotifications { pub struct EnabledNotifications {
@@ -48,7 +57,7 @@ impl Default for EnabledNotifications {
receive_notify_charge_control_end_threshold: true, receive_notify_charge_control_end_threshold: true,
receive_notify_mains_online: false, receive_notify_mains_online: false,
receive_notify_profile: true, receive_notify_profile: true,
receive_notify_led: false, receive_notify_led: true,
receive_power_states: false, receive_power_states: false,
receive_notify_gfx: false, receive_notify_gfx: false,
receive_notify_gfx_status: false, receive_notify_gfx_status: false,
@@ -125,11 +134,36 @@ macro_rules! recv_notif {
type SharedHandle = Arc<Mutex<Option<NotificationHandle>>>; type SharedHandle = Arc<Mutex<Option<NotificationHandle>>>;
pub fn start_notifications( pub fn start_notifications(
config: &Config,
page_states: Arc<Mutex<SystemState>>, page_states: Arc<Mutex<SystemState>>,
enabled_notifications: Arc<Mutex<EnabledNotifications>>, enabled_notifications: Arc<Mutex<EnabledNotifications>>,
) -> Result<()> { ) -> Result<()> {
let last_notification: SharedHandle = Arc::new(Mutex::new(None)); let last_notification: SharedHandle = Arc::new(Mutex::new(None));
// Setup the AC/BAT commands that will run on poweer status change
unsafe {
let prog: Vec<&str> = config.ac_command.split_whitespace().collect();
if prog.len() > 1 {
let mut cmd = Command::new(prog[0]);
for arg in prog.iter().skip(1) {
cmd.arg(*arg);
}
POWER_AC_CMD = Some(cmd);
}
}
unsafe {
let prog: Vec<&str> = config.bat_command.split_whitespace().collect();
if prog.len() > 1 {
let mut cmd = Command::new(prog[0]);
for arg in prog.iter().skip(1) {
cmd.arg(*arg);
}
POWER_BAT_CMD = Some(cmd);
}
}
// BIOS notif // BIOS notif
recv_notif!( recv_notif!(
RogBiosProxy, RogBiosProxy,
@@ -179,18 +213,6 @@ pub fn start_notifications(
do_notification 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 // Charge notif
recv_notif!( recv_notif!(
PowerProxy, PowerProxy,
@@ -271,104 +293,139 @@ pub fn start_notifications(
}; };
}); });
recv_notif!( let page_states1 = page_states.clone();
SuperProxy, let last_notification1 = last_notification.clone();
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 { tokio::spawn(async move {
let conn = zbus::Connection::system() let conn = zbus::Connection::system()
.await .await
.map_err(|e| { .map_err(|e| {
error!("zbus signal: receive_notify_action: {e}"); error!("zbus signal: receive_notify_gpu_mux_mode: {e}");
e e
}) })
.unwrap(); .unwrap();
let proxy = SuperProxy::new(&conn) let proxy = RogBiosProxy::new(&conn)
.await .await
.map_err(|e| { .map_err(|e| {
error!("zbus signal: receive_notify_action: {e}"); error!("zbus signal: receive_notify_gpu_mux_mode: {e}");
e e
}) })
.unwrap(); .unwrap();
if let Ok(mut p) = proxy.receive_notify_action().await { if let Ok(mut p) = proxy.receive_notify_gpu_mux_mode().await {
info!("Started zbus signal thread: receive_notify_action"); info!("Started zbus signal thread: receive_power_states");
while let Some(e) = p.next().await { while let Some(e) = p.next().await {
if let Ok(out) = e.args() { if let Ok(out) = e.args() {
let action = out.action(); if let Ok(mut lock) = page_states1.lock() {
do_gfx_action_notif("Gfx mode change requires", &format!("{action:?}",)) lock.bios.dedicated_gfx = out.mode;
.map_err(|e| { lock.set_notified();
error!("zbus signal: do_gfx_action_notif: {e}"); }
e if let Ok(ref mut lock) = last_notification1.lock() {
}) if let Some(notif) = lock.take() {
.unwrap(); notif.close();
}
}
};
});
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();
} }
} }
do_mux_notification("Reboot required. BIOS GPU MUX mode set to", &out.mode)
.ok();
} }
} }
}; };
}); });
if let Ok(lock) = page_states.try_lock() {
use supergfxctl::pci_device::Device;
let dev = Device::find().unwrap_or_default();
let mut found_dgpu = false; // just for logging
for dev in dev {
if dev.is_dgpu() {
let notifs_enabled1 = enabled_notifications.clone();
let last_notif = last_notification.clone();
let page_states1 = page_states.clone();
// Plain old thread is perfectly fine since most of this is potentially blocking
tokio::spawn(async move {
let mut last_status = GfxPower::Unknown;
loop {
if let Ok(status) = dev.get_runtime_status() {
if status != GfxPower::Unknown && status != last_status {
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_states1.lock() {
lock.gfx_state.power_status = status;
lock.set_notified();
}
last_status = status;
}
}
sleep(Duration::from_millis(500)).await;
}
});
found_dgpu = true;
break;
}
}
if !found_dgpu {
warn!("Did not find a dGPU on this system, dGPU status won't be avilable");
}
if lock.gfx_state.has_supergfx {
recv_notif!(
SuperProxy,
receive_notify_gfx,
last_notification,
enabled_notifications,
page_states,
(gfx_state.mode),
(mode),
"Gfx mode changed to",
do_notification
);
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();
}
}
};
});
}
}
Ok(()) Ok(())
} }
@@ -397,8 +454,22 @@ where
fn ac_power_notification(message: &str, on: &bool) -> Result<NotificationHandle> { fn ac_power_notification(message: &str, on: &bool) -> Result<NotificationHandle> {
let data = if *on { let data = if *on {
unsafe {
if let Some(cmd) = POWER_AC_CMD.as_mut() {
if let Err(e) = cmd.spawn() {
error!("AC power command error: {e}");
}
}
}
"plugged".to_owned() "plugged".to_owned()
} else { } else {
unsafe {
if let Some(cmd) = POWER_BAT_CMD.as_mut() {
if let Err(e) = cmd.spawn() {
error!("Battery power command error: {e}");
}
}
}
"unplugged".to_owned() "unplugged".to_owned()
}; };
Ok(base_notification(message, &data).show()?) Ok(base_notification(message, &data).show()?)
@@ -452,10 +523,24 @@ where
} }
/// Actual `GpuMode` unused as data is never correct until switched by reboot /// Actual `GpuMode` unused as data is never correct until switched by reboot
fn do_mux_notification(message: &str, _: &GpuMode) -> Result<NotificationHandle> { fn do_mux_notification(message: &str, m: &GpuMode) -> Result<()> {
let mut notif = base_notification(message, &""); let mut notif = base_notification(message, &m.to_string());
notif.action("gnome-session-quit", "Reboot");
notif.urgency(Urgency::Critical); notif.urgency(Urgency::Critical);
notif.icon("system-reboot-symbolic"); notif.icon("system-reboot-symbolic");
notif.hint(Hint::Transient(true)); notif.hint(Hint::Transient(true));
Ok(notif.show()?) let handle = notif.show()?;
std::thread::spawn(|| {
handle.wait_for_action(|id| {
if id == "gnome-session-quit" {
let mut cmd = Command::new("gnome-session-quit");
cmd.arg("--reboot");
cmd.spawn().ok();
} else if id == "__closed" {
// TODO: cancel the switching
}
})
});
Ok(())
} }
+16 -6
View File
@@ -12,7 +12,8 @@ pub fn app_settings(config: &mut Config, states: &mut SystemState, ui: &mut Ui)
Default::default() Default::default()
}; };
if ui ui.label("Application settings");
let app_changed = ui
.checkbox(&mut config.run_in_background, "Run in Background") .checkbox(&mut config.run_in_background, "Run in Background")
.clicked() .clicked()
|| ui || ui
@@ -23,11 +24,19 @@ pub fn app_settings(config: &mut Config, states: &mut SystemState, ui: &mut Ui)
&mut enabled_notifications.all_enabled, &mut enabled_notifications.all_enabled,
"Enable Notifications", "Enable Notifications",
) )
.clicked() .clicked();
ui.label("Notification settings");
let notif_changed = ui
.checkbox(
&mut enabled_notifications.receive_notify_gfx_status,
"Enable dGPU status notification",
)
.clicked()
|| ui || ui
.checkbox( .checkbox(
&mut enabled_notifications.receive_notify_gfx_status, &mut enabled_notifications.receive_notify_led,
"Enable dGPU status notification", "Enable LED mode change notification",
) )
.clicked() .clicked()
|| ui || ui
@@ -71,8 +80,9 @@ pub fn app_settings(config: &mut Config, states: &mut SystemState, ui: &mut Ui)
&mut enabled_notifications.receive_notify_post_boot_sound, &mut enabled_notifications.receive_notify_post_boot_sound,
"Enable BIOS post sound notification", "Enable BIOS post sound notification",
) )
.clicked() .clicked();
{
if app_changed || notif_changed {
if let Ok(mut lock) = states.enabled_notifications.lock() { if let Ok(mut lock) = states.enabled_notifications.lock() {
// Replace inner content before save // Replace inner content before save
*lock = enabled_notifications; *lock = enabled_notifications;
+14 -3
View File
@@ -93,6 +93,13 @@ pub fn rog_bios_group(supported: &SupportedFunctions, states: &mut SystemState,
if supported.rog_bios_ctrl.gpu_mux { if supported.rog_bios_ctrl.gpu_mux {
let mut changed = false; let mut changed = false;
let mut dedicated_gfx = states.bios.dedicated_gfx;
let mut reboot_required = false;
if let Ok(mode) = states.asus_dbus.proxies().rog_bios().gpu_mux_mode() {
reboot_required = mode != states.bios.dedicated_gfx;
}
ui.group(|ui| { ui.group(|ui| {
ui.vertical(|ui| { ui.vertical(|ui| {
ui.horizontal_wrapped(|ui| ui.label("GPU MUX mode")); ui.horizontal_wrapped(|ui| ui.label("GPU MUX mode"));
@@ -100,19 +107,23 @@ pub fn rog_bios_group(supported: &SupportedFunctions, states: &mut SystemState,
ui.horizontal_wrapped(|ui| { ui.horizontal_wrapped(|ui| {
changed = ui changed = ui
.selectable_value( .selectable_value(
&mut states.bios.dedicated_gfx, &mut dedicated_gfx,
GpuMode::Discrete, GpuMode::Discrete,
"Dedicated (Ultimate)", "Dedicated (Ultimate)",
) )
.clicked() .clicked()
|| ui || ui
.selectable_value( .selectable_value(
&mut states.bios.dedicated_gfx, &mut dedicated_gfx,
GpuMode::Optimus, GpuMode::Optimus,
"Optimus (Hybrid)", "Optimus (Hybrid)",
) )
.clicked(); .clicked();
}); });
if reboot_required {
ui.horizontal_wrapped(|ui| ui.heading("REBOOT REQUIRED"));
}
}); });
}); });
@@ -121,7 +132,7 @@ pub fn rog_bios_group(supported: &SupportedFunctions, states: &mut SystemState,
.asus_dbus .asus_dbus
.proxies() .proxies()
.rog_bios() .rog_bios()
.set_gpu_mux_mode(states.bios.dedicated_gfx) .set_gpu_mux_mode(dedicated_gfx)
.map_err(|err| { .map_err(|err| {
states.error = Some(err.to_string()); states.error = Some(err.to_string());
}) })
+8
View File
@@ -72,6 +72,14 @@ impl Profile {
file.write_all(<&str>::from(profile).as_bytes())?; file.write_all(<&str>::from(profile).as_bytes())?;
Ok(()) Ok(())
} }
pub fn from_throttle_thermal_policy(num: u8) -> Self {
match num {
1 => Self::Performance,
2 => Self::Quiet,
_ => Self::Balanced,
}
}
} }
impl Default for Profile { impl Default for Profile {
+9
View File
@@ -0,0 +1,9 @@
# If you see this, run "rustup self update" to get rustup 1.23 or newer.
# NOTE: above comment is for older `rustup` (before TOML support was added),
# which will treat the first line as the toolchain name, and therefore show it
# to the user in the error, instead of "error: invalid channel name '[toolchain]'".
[toolchain]
channel = "1.65.0"
components = [ "rustfmt", "clippy" ]