Compare commits

...

52 Commits

Author SHA1 Message Date
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
Luke D. Jones 28347e87eb Prep new minor release 2022-12-06 20:10:03 +13:00
Luke D. Jones b34cb672c3 Fix: ROGCC: log and show more errors on startup 2022-12-06 14:28:35 +13:00
Luke D. Jones 559ddc9a22 Fix: ROGCC: remove unused arg in fan curve widget 2022-12-06 10:08:11 +13:00
Luke D. Jones a8c014881f Version bump for RC 2022-12-06 09:48:24 +13:00
Luke D. Jones f417032ed9 Fix: ROGCC: apply changes to correct fan curve profile
The fan curve profile changes were applying to the currently *active*
profile and not the GUI selected profile being changed. Fixed.

Also clarify the buttons for fan curve apply.
2022-12-06 09:47:48 +13:00
Luke D. Jones 616fb3aea6 chore: cranky cleanups 2022-12-05 20:31:39 +13:00
Luke D. Jones 6e6e057995 Update changelog 2022-12-05 19:44:50 +13:00
Luke D. Jones 085e63ebab Merge commit 'fdadffcdde82' because of borked HEAD after pull 2022-12-05 19:44:08 +13:00
Luke D. Jones fdadffcdde Fix: ROGCC: Correctly deny badly formed fan graphs
Closes #286
2022-12-05 19:40:00 +13:00
Luke Jones 5f51527dd7 Merge branch 'piivanov-main-patch-89025' into 'main'
Add led modes for G713RM

See merge request asus-linux/asusctl!143
2022-12-04 20:53:46 +00:00
Peter Ivanov 39525980a0 Add led modes for G713RM 2022-12-04 17:39:32 +00:00
Luke D. Jones 83a0b570e0 Cause great pain to self with cargo-deny + cargo-cranky 2022-12-04 22:10:08 +13:00
Luke D. Jones 2bfbce36b0 Bump dependencies 2022-12-04 22:09:28 +13:00
Luke D. Jones 2705b08dca Cause great pain to self with cargo-deny + cargo-cranky 2022-12-04 21:49:47 +13:00
Luke D. Jones 2fca7a09c4 bump dependencies 2022-12-04 20:16:33 +13:00
Luke Jones ef0da62c55 Merge branch 'maxbachmann-main-patch-99498' into 'main'
add led modes for G513RM

See merge request asus-linux/asusctl!141
2022-12-04 01:48:10 +00:00
maxbachmann 9dab120bcf add led modes for G513RM 2022-12-03 22:03:35 +00:00
Luke D. Jones 14bf07ba79 Version bump for dep updates 2022-12-02 16:39:46 +13:00
Luke D. Jones e76d01eaed Update dependencies 2022-12-02 16:37:33 +13:00
Luke Jones 072a066f28 Merge branch 'fixed_readme_dependency_list_for_fedora' into 'main'
rust/cargo is also needed

See merge request asus-linux/asusctl!140
2022-12-01 20:11:39 +00:00
A. Binzxxxxxx 165c6f8ab3 rust/cargo is also needed 2022-12-01 20:06:28 +00:00
Luke Jones 5728a9af62 Update README.md 2022-11-22 21:54:51 +00:00
Luke Jones 17a880b2c5 Merge branch 'main' into 'main'
Fix VivoBook detection

See merge request asus-linux/asusctl!139
2022-11-20 19:48:29 +00:00
RushingAlien 6ba9b9d75d Fix VivoBook detection 2022-11-19 22:06:34 +07:00
Luke Jones eb1f6c83ce Merge branch 'fix-gitlab-ci' into 'main'
Fix GitLab CI

See merge request asus-linux/asusctl!138
2022-11-16 20:06:06 +00:00
Herohtar af653ea405 Don't install unnecessary packages 2022-11-16 12:26:14 -06:00
Herohtar bc13891cdf Install required libgtk-3-dev package 2022-11-16 12:25:29 -06:00
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
Luke D. Jones 1211400d7b 4.5.1-RC1 2022-11-11 20:13:00 +13:00
Luke D. Jones ff9edb9876 Enable system tray status for dGPU and actions 2022-11-11 20:09:43 +13:00
Luke D. Jones 20f8251dd3 Adjust FA506IE led mode match to FA506I 2022-11-10 09:14:17 +13:00
Luke Jones 902dfed67c Merge branch 'add-asus-tuf-gaming-a15-led-modes' into 'main'
Add led_data for 2022 ASUS TUF Gaming A15 FA506IE

See merge request asus-linux/asusctl!137
2022-11-09 20:12:04 +00:00
Luke D. Jones 5e08b4416d Bump version 2022-11-10 09:11:52 +13:00
Herohtar 44c3ab7294 Add led_data for 2022 ASUS TUF Gaming A15 FA506IE 2022-11-09 12:03:23 -06:00
Luke D. Jones be40474f79 Update app icons 2022-11-09 21:47:41 +13:00
Luke Jones 3654da2ff8 Merge branch 'tuxfanou/building_opensuse' into 'main'
Add openSUSE requirements to build asusctl

See merge request asus-linux/asusctl!136
2022-11-08 20:20:46 +00:00
Luke Jones 60bbad4ab6 Merge branch 'feat-add-vivobook-family' into 'main'
Add Vivobook to asusd rules

See merge request asus-linux/asusctl!135
2022-11-08 20:19:00 +00:00
Sarang S 0a59d5c041 Add Vivobook to asusd rules 2022-11-08 20:19:00 +00:00
Stéphane Burdin 1506fc44d3 Add openSUSE requirements to build asusctl 2022-11-08 16:14:53 +01:00
Luke D. Jones aad31610f2 Add missing file 2022-11-08 22:03:42 +13:00
Luke D. Jones a6fe7645e9 Tray icons 2022-11-08 21:55:09 +13:00
Luke D. Jones 4f8745ae19 Prep release 4.5.0 2022-11-07 21:36:28 +13:00
107 changed files with 3027 additions and 1373 deletions
+42 -8
View File
@@ -1,29 +1,63 @@
image: rust:latest image: rust:latest
cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
# Don't include `incremental` to save space
# Debug
- target/debug/build/
- target/debug/deps/
- target/debug/.fingerprint/
- target/debug/.cargo-lock
- target/debug/df_storyteller
# Release
- target/release/build/
- target/release/deps/
- target/release/.fingerprint/
- target/release/.cargo-lock
before_script: before_script:
- apt-get update -qq && apt-get install -y -qq libdbus-1-dev libclang-dev libudev-dev libfontconfig1-dev - apt-get update -qq && apt-get install -y -qq libudev-dev libgtk-3-dev grep
stages: stages:
- format
- check
- test - test
- build - release
test: format:
except:
- tags
script:
- echo "nightly" > rust-toolchain
- rustup component add rustfmt
- cargo fmt --check
check:
except:
- tags
script: script:
- rustup component add clippy - rustup component add clippy
- cargo check - cargo check
- cargo clippy # deny currently catches too much
#- cargo install cargo-deny && cargo deny
- cargo install cargo-cranky && cargo cranky
test:
except:
- tags
script:
- cargo test - cargo test
build: release:
only: only:
- main - tags
script: script:
- make && make vendor - make && make vendor
artifacts: artifacts:
paths: paths:
- vendor_asus-nb-ctrl_*.tar.xz - vendor_asusctl_*.tar.xz
- cargo-config - cargo-config
variables: variables:
GIT_SUBMODULE_STRATEGY: normal GIT_SUBMODULE_STRATEGY: normal
+31 -1
View File
@@ -4,7 +4,37 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 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 - 4.5.0-RC5] ## [Unreleased]
## [v4.5.4]
### Changed
- ROGCC:: Allow ROGCC to run without supergfxd
- ROGCC: Tray/notifs now reads dGPU status directly via supergfx crate (supergfxd not required)
- Add rust-toolchain to force minimum rust version
## [v4.5.3]
### Changed
- Adjust how fan graph in ROGCC works, deny incorrect graphs
- Fix to apply the fan curve change in ROGCC to the correct profile
- Support for G713RS LED modes (Author: Peter Ivanov)
- Support for G713RM LED modes (Author: maxbachmann)
- Fix VivoBook detection
- Update dependencies to get latest winit crate (fixes various small issues)
## [v4.5.2]
### Changed
- Update dependencies and bump version
## [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 ### Added
- intofy watches on: - intofy watches on:
- `charge_control_end_threshold` - `charge_control_end_threshold`
Generated
+943 -272
View File
File diff suppressed because it is too large Load Diff
+10 -13
View File
@@ -2,20 +2,17 @@
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.0-rc5" version = "4.5.4"
[workspace.dependencies] [workspace.dependencies]
async-trait = "^0.1" async-trait = "^0.1"
tokio = { version = "^1.21.2", features = ["macros", "rt-multi-thread", "time"]} tokio = { version = "^1.22.0", features = ["macros", "rt-multi-thread", "time", "sync"]}
concat-idents = "^1.1" concat-idents = "^1.1"
dirs = "^4.0" dirs = "^4.0"
smol = "^1.2" smol = "^1.3"
zbus = "^3.4" zbus = "^3.5"
zbus_macros = "^3.4" logind-zbus = { version = "^3.0.3" } #, default-features = false, features = ["non_blocking"] }
zvariant = "^3.7"
zvariant_derive = "^3.7"
logind-zbus = { version = "^3.0" } #, default-features = false, features = ["non_blocking"] }
serde = "^1.0" serde = "^1.0"
serde_derive = "^1.0" serde_derive = "^1.0"
@@ -23,19 +20,19 @@ serde_json = "^1.0"
toml = "^0.5.9" toml = "^0.5.9"
log = "^0.4" log = "^0.4"
env_logger = "^0.9" env_logger = "^0.10.0"
glam = { version = "^0.22", features = ["serde"] } glam = { version = "^0.22", features = ["serde"] }
gumdrop = "^0.8" gumdrop = "^0.8"
udev = "^0.6" udev = "^0.7"
rusb = "^0.9" rusb = "^0.9"
sysfs-class = "^0.1.2" sysfs-class = "^0.1.3"
inotify = "^0.10.0" inotify = "^0.10.0"
png_pong = "^0.8" png_pong = "^0.8"
pix = "^0.13" pix = "^0.13"
tinybmp = "^0.3" tinybmp = "^0.4.0"
gif = "^0.11" gif = "^0.12.0"
notify-rust = { git = "https://github.com/flukejones/notify-rust.git", default-features = false, features = ["z"] } notify-rust = { git = "https://github.com/flukejones/notify-rust.git", default-features = false, features = ["z"] }
+121
View File
@@ -0,0 +1,121 @@
# https://github.com/ericseppanen/cargo-cranky
# cargo install cargo-cranky && cargo cranky
warn = [
"clippy::all",
"clippy::await_holding_lock",
"clippy::bool_to_int_with_if",
"clippy::char_lit_as_u8",
"clippy::checked_conversions",
"clippy::dbg_macro",
"clippy::debug_assert_with_mut_call",
"clippy::disallowed_methods",
"clippy::disallowed_script_idents",
"clippy::doc_link_with_quotes",
"clippy::doc_markdown",
"clippy::empty_enum",
"clippy::enum_glob_use",
"clippy::equatable_if_let",
"clippy::exit",
"clippy::expl_impl_clone_on_copy",
"clippy::explicit_deref_methods",
"clippy::explicit_into_iter_loop",
"clippy::explicit_iter_loop",
"clippy::fallible_impl_from",
"clippy::filter_map_next",
"clippy::flat_map_option",
"clippy::float_cmp_const",
"clippy::fn_params_excessive_bools",
"clippy::fn_to_numeric_cast_any",
"clippy::from_iter_instead_of_collect",
"clippy::if_let_mutex",
"clippy::implicit_clone",
"clippy::imprecise_flops",
"clippy::index_refutable_slice",
"clippy::inefficient_to_string",
"clippy::invalid_upcast_comparisons",
"clippy::iter_not_returning_iterator",
"clippy::iter_on_empty_collections",
"clippy::iter_on_single_items",
"clippy::large_digit_groups",
"clippy::large_stack_arrays",
"clippy::large_types_passed_by_value",
"clippy::let_unit_value",
"clippy::linkedlist",
"clippy::lossy_float_literal",
"clippy::macro_use_imports",
"clippy::manual_assert",
"clippy::manual_instant_elapsed",
"clippy::manual_ok_or",
"clippy::manual_string_new",
"clippy::map_err_ignore",
"clippy::map_flatten",
"clippy::map_unwrap_or",
"clippy::match_on_vec_items",
"clippy::match_same_arms",
"clippy::match_wild_err_arm",
"clippy::match_wildcard_for_single_variants",
"clippy::mem_forget",
"clippy::mismatched_target_os",
"clippy::mismatching_type_param_order",
"clippy::missing_enforced_import_renames",
# "clippy::missing_errors_doc",
"clippy::missing_safety_doc",
"clippy::mut_mut",
"clippy::mutex_integer",
"clippy::needless_borrow",
"clippy::needless_continue",
"clippy::needless_for_each",
"clippy::needless_pass_by_value",
"clippy::negative_feature_names",
"clippy::nonstandard_macro_braces",
"clippy::option_option",
"clippy::path_buf_push_overwrite",
"clippy::ptr_as_ptr",
"clippy::rc_mutex",
"clippy::ref_option_ref",
"clippy::rest_pat_in_fully_bound_structs",
"clippy::same_functions_in_if_condition",
"clippy::semicolon_if_nothing_returned",
"clippy::single_match_else",
"clippy::str_to_string",
"clippy::string_add_assign",
"clippy::string_add",
"clippy::string_lit_as_bytes",
"clippy::string_to_string",
"clippy::todo",
"clippy::trailing_empty_array",
"clippy::trait_duplication_in_bounds",
"clippy::unimplemented",
"clippy::unnecessary_wraps",
"clippy::unnested_or_patterns",
"clippy::unused_peekable",
"clippy::unused_rounding",
# "clippy::unused_self",
"clippy::useless_transmute",
"clippy::verbose_file_reads",
"clippy::zero_sized_map_values",
"elided_lifetimes_in_paths",
"future_incompatible",
"nonstandard_style",
"rust_2018_idioms",
"rust_2021_prelude_collisions",
"rustdoc::missing_crate_level_docs",
"semicolon_in_expressions_from_macros",
"trivial_numeric_casts",
"unused_extern_crates",
"unused_import_braces",
"unused_lifetimes",
]
allow = [
# TODO(emilk): enable more lints
"clippy::cloned_instead_of_copied",
"clippy::derive_partial_eq_without_eq",
"clippy::type_complexity",
"clippy::undocumented_unsafe_blocks",
"trivial_casts",
"unsafe_op_in_unsafe_fn", # `unsafe_op_in_unsafe_fn` may become the default in future Rust versions: https://github.com/rust-lang/rust/issues/71668
"unused_qualifications",
]
+4 -1
View File
@@ -1,4 +1,4 @@
VERSION := $(shell grep -Pm1 'version = "(\d.\d.\d)"' daemon/Cargo.toml | cut -d'"' -f2) VERSION := $(shell /usr/bin/grep -Pm1 'version = "(\d.\d.\d)"' Cargo.toml | cut -d'"' -f2)
INSTALL = install INSTALL = install
INSTALL_PROGRAM = ${INSTALL} -D -m 0755 INSTALL_PROGRAM = ${INSTALL} -D -m 0755
@@ -57,7 +57,10 @@ install:
$(INSTALL_DATA) "./data/icons/asus_notif_yellow.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png" $(INSTALL_DATA) "./data/icons/asus_notif_yellow.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png"
$(INSTALL_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png" $(INSTALL_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png"
$(INSTALL_DATA) "./data/icons/asus_notif_blue.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_blue.png"
$(INSTALL_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png" $(INSTALL_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
$(INSTALL_DATA) "./data/icons/asus_notif_orange.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_orange.png"
$(INSTALL_DATA) "./data/icons/asus_notif_white.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_white.png"
$(INSTALL_DATA) "./data/icons/scalable/gpu-compute.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-compute.svg" $(INSTALL_DATA) "./data/icons/scalable/gpu-compute.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-compute.svg"
$(INSTALL_DATA) "./data/icons/scalable/gpu-hybrid.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-hybrid.svg" $(INSTALL_DATA) "./data/icons/scalable/gpu-hybrid.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-hybrid.svg"
+11 -2
View File
@@ -2,7 +2,7 @@
[![](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/donate/?hosted_button_id=4V2DEPS7K6APC) - [Asus Linux Website](https://asus-linux.org/) [![](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/donate/?hosted_button_id=4V2DEPS7K6APC) - [Asus Linux Website](https://asus-linux.org/)
**WARNING:** Do not run the main branch of this repo unless you have all the asus-wmi kernel patches. You should use stable kernels + tagged releases. **WARNING:** Many features are developed in tandem with kernel patches. If you see a feature is missing you either need a patched kernel, or v6.1 which has all my work merged upstream.
`asusd` is a utility for Linux to control many aspects of various ASUS laptops `asusd` is a utility for Linux to control many aspects of various ASUS laptops
but can also be used with non-asus laptops with reduced features. but can also be used with non-asus laptops with reduced features.
@@ -81,7 +81,16 @@ Requirements are rust >= 1.57 installed from rustup.io if the distro provided ve
**fedora:** **fedora:**
dnf install clang-devel systemd-devel cargo dnf install cmake clang-devel systemd-devel gtk3-devel cargo
make
sudo make install
**openSUSE:**
Works with KDE Plasma (without GTK packages)
zypper in -t pattern devel_basis
zypper in rustup cmake clang-devel systemd-devel glib2-devel cairo-devel atkmm-devel pangomm-devel gdk-pixbuf-devel gtk3-devel
make make
sudo make install sudo make install
+1
View File
@@ -1,5 +1,6 @@
[package] [package]
name = "asusctl" name = "asusctl"
license = "MPL-2.0"
authors = ["Luke D Jones <luke@ljones.dev>"] authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2021" edition = "2021"
version.workspace = true version.workspace = true
+1 -1
View File
@@ -20,7 +20,7 @@ fn main() {
} }
for c in (0..35).into_iter().step_by(step) { for c in (0..35).into_iter().step_by(step) {
for i in matrix.get_mut()[c].iter_mut() { for i in &mut matrix.get_mut()[c] {
*i = 50; *i = 50;
} }
} }
-1
View File
@@ -17,7 +17,6 @@ fn main() {
for (y, row) in tmp.iter_mut().enumerate() { for (y, row) in tmp.iter_mut().enumerate() {
if y % 2 == 0 && i + 1 != row.len() - 1 { if y % 2 == 0 && i + 1 != row.len() - 1 {
i += 1; i += 1;
dbg!(i);
} }
row[row.len() - i] = 0x22; row[row.len() - i] = 0x22;
if i > 5 { if i > 5 {
+1 -1
View File
@@ -35,7 +35,7 @@ fn main() -> Result<(), Box<dyn Error>> {
loop { loop {
matrix.angle += 0.05; matrix.angle += 0.05;
if matrix.angle > PI * 2.0 { if matrix.angle > PI * 2.0 {
matrix.angle = 0.0 matrix.angle = 0.0;
} }
matrix.update(); matrix.update();
+3 -3
View File
@@ -6,17 +6,17 @@ use rog_aura::{
KeyColourArray, KeyColourArray,
}; };
use rog_dbus::RogDbusClientBlocking; use rog_dbus::RogDbusClientBlocking;
use std::collections::LinkedList; use std::collections::VecDeque;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Ball { struct Ball {
position: (f32, f32), position: (f32, f32),
direction: (f32, f32), direction: (f32, f32),
trail: LinkedList<(f32, f32)>, trail: VecDeque<(f32, f32)>,
} }
impl Ball { impl Ball {
fn new(x: f32, y: f32, trail_len: u32) -> Self { fn new(x: f32, y: f32, trail_len: u32) -> Self {
let mut trail = LinkedList::new(); let mut trail = VecDeque::new();
for _ in 1..=trail_len { for _ in 1..=trail_len {
trail.push_back((x, y)); trail.push_back((x, y));
} }
+1 -1
View File
@@ -105,7 +105,7 @@ impl ToString for LedBrightness {
Some(0x02) => "high", Some(0x02) => "high",
_ => "unknown", _ => "unknown",
}; };
s.to_string() s.to_owned()
} }
} }
+29 -35
View File
@@ -26,7 +26,7 @@ mod aura_cli;
mod cli_opts; mod cli_opts;
mod profiles_cli; mod profiles_cli;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() {
let args: Vec<String> = args().skip(1).collect(); let args: Vec<String> = args().skip(1).collect();
let missing_argument_k = gumdrop::Error::missing_argument(Opt::Short('k')); let missing_argument_k = gumdrop::Error::missing_argument(Opt::Short('k'));
@@ -44,7 +44,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = RogDbusClientBlocking::new() let (dbus, _) = RogDbusClientBlocking::new()
.map_err(|e| { .map_err(|e| {
print_error_help(Box::new(e), None); print_error_help(&e, None);
std::process::exit(3); std::process::exit(3);
}) })
.unwrap(); .unwrap();
@@ -54,7 +54,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.supported() .supported()
.supported_functions() .supported_functions()
.map_err(|e| { .map_err(|e| {
print_error_help(Box::new(e), None); print_error_help(&e, None);
std::process::exit(4); std::process::exit(4);
}) })
.unwrap(); .unwrap();
@@ -63,17 +63,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
print_versions(); print_versions();
println!(); println!();
print_laptop_info(); print_laptop_info();
return Ok(());
} }
if let Err(err) = do_parsed(&parsed, &supported, &dbus) { if let Err(err) = do_parsed(&parsed, &supported, &dbus) {
print_error_help(err, Some(&supported)); print_error_help(&*err, Some(&supported));
} }
Ok(())
} }
fn print_error_help(err: Box<dyn std::error::Error>, supported: Option<&SupportedFunctions>) { fn print_error_help(err: &dyn std::error::Error, supported: Option<&SupportedFunctions>) {
check_service("asusd"); check_service("asusd");
println!("\nError: {}\n", err); println!("\nError: {}\n", err);
print_versions(); print_versions();
@@ -126,7 +123,7 @@ fn check_service(name: &str) -> bool {
fn do_parsed( fn do_parsed(
parsed: &CliStart, parsed: &CliStart,
supported: &SupportedFunctions, supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
match &parsed.command { match &parsed.command {
Some(CliCommand::LedMode(mode)) => handle_led_mode(dbus, &supported.keyboard_led, mode)?, Some(CliCommand::LedMode(mode)) => handle_led_mode(dbus, &supported.keyboard_led, mode)?,
@@ -134,9 +131,9 @@ fn do_parsed(
Some(CliCommand::LedPow2(pow)) => handle_led_power2(dbus, &supported.keyboard_led, pow)?, Some(CliCommand::LedPow2(pow)) => handle_led_power2(dbus, &supported.keyboard_led, pow)?,
Some(CliCommand::Profile(cmd)) => handle_profile(dbus, &supported.platform_profile, cmd)?, Some(CliCommand::Profile(cmd)) => handle_profile(dbus, &supported.platform_profile, cmd)?,
Some(CliCommand::FanCurve(cmd)) => { Some(CliCommand::FanCurve(cmd)) => {
handle_fan_curve(dbus, &supported.platform_profile, cmd)? handle_fan_curve(dbus, &supported.platform_profile, cmd)?;
} }
Some(CliCommand::Graphics(_)) => do_gfx()?, Some(CliCommand::Graphics(_)) => do_gfx(),
Some(CliCommand::Anime(cmd)) => handle_anime(dbus, &supported.anime_ctrl, cmd)?, Some(CliCommand::Anime(cmd)) => handle_anime(dbus, &supported.anime_ctrl, cmd)?,
Some(CliCommand::Bios(cmd)) => handle_bios_option(dbus, &supported.rog_bios_ctrl, cmd)?, Some(CliCommand::Bios(cmd)) => handle_bios_option(dbus, &supported.rog_bios_ctrl, cmd)?,
None => { None => {
@@ -150,7 +147,7 @@ fn do_parsed(
println!("{}", CliStart::usage()); println!("{}", CliStart::usage());
println!(); println!();
if let Some(cmdlist) = CliStart::command_list() { if let Some(cmdlist) = CliStart::command_list() {
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_string()).collect(); let commands: Vec<String> = cmdlist.lines().map(|s| s.to_owned()).collect();
for command in commands.iter().filter(|command| { for command in commands.iter().filter(|command| {
if !matches!( if !matches!(
supported.keyboard_led.prod_id, supported.keyboard_led.prod_id,
@@ -214,14 +211,13 @@ fn do_parsed(
Ok(()) Ok(())
} }
fn do_gfx() -> Result<(), Box<dyn std::error::Error>> { fn do_gfx() {
println!("Please use supergfxctl for graphics switching. supergfxctl is the result of making asusctl graphics switching generic so all laptops can use it"); println!("Please use supergfxctl for graphics switching. supergfxctl is the result of making asusctl graphics switching generic so all laptops can use it");
println!("This command will be removed in future"); println!("This command will be removed in future");
Ok(())
} }
fn handle_anime( fn handle_anime(
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
_supported: &AnimeSupportedFunctions, _supported: &AnimeSupportedFunctions,
cmd: &AnimeCommand, cmd: &AnimeCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -237,14 +233,14 @@ fn handle_anime(
} }
} }
if let Some(anime_turn) = cmd.enable { if let Some(anime_turn) = cmd.enable {
dbus.proxies().anime().set_on_off(anime_turn)? dbus.proxies().anime().set_on_off(anime_turn)?;
} }
if let Some(anime_boot) = cmd.boot_enable { if let Some(anime_boot) = cmd.boot_enable {
dbus.proxies().anime().set_boot_on_off(anime_boot)? dbus.proxies().anime().set_boot_on_off(anime_boot)?;
} }
if let Some(bright) = cmd.brightness { if let Some(bright) = cmd.brightness {
verify_brightness(bright); verify_brightness(bright);
dbus.proxies().anime().set_brightness(bright)? dbus.proxies().anime().set_brightness(bright)?;
} }
if cmd.clear { if cmd.clear {
let anime_type = get_anime_type()?; let anime_type = get_anime_type()?;
@@ -381,7 +377,7 @@ fn verify_brightness(brightness: f32) {
} }
fn handle_led_mode( fn handle_led_mode(
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
supported: &LedSupportedFunctions, supported: &LedSupportedFunctions,
mode: &LedModeCommand, mode: &LedModeCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -438,7 +434,7 @@ fn handle_led_mode(
} }
fn handle_led_power1( fn handle_led_power1(
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
supported: &LedSupportedFunctions, supported: &LedSupportedFunctions,
power: &LedPowerCommand1, power: &LedPowerCommand1,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -473,7 +469,7 @@ fn handle_led_power1(
} }
fn handle_led_power_1_do_1866( fn handle_led_power_1_do_1866(
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
power: &LedPowerCommand1, power: &LedPowerCommand1,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let mut enabled: Vec<AuraDev1866> = Vec::new(); let mut enabled: Vec<AuraDev1866> = Vec::new();
@@ -513,7 +509,7 @@ fn handle_led_power_1_do_1866(
} }
fn handle_led_power_1_do_tuf( fn handle_led_power_1_do_tuf(
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
power: &LedPowerCommand1, power: &LedPowerCommand1,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let mut enabled: Vec<AuraDevTuf> = Vec::new(); let mut enabled: Vec<AuraDevTuf> = Vec::new();
@@ -539,7 +535,6 @@ fn handle_led_power_1_do_tuf(
x19b6: vec![], x19b6: vec![],
tuf: enabled, tuf: enabled,
}; };
dbg!(&data);
dbus.proxies().led().set_leds_power(data, true)?; dbus.proxies().led().set_leds_power(data, true)?;
let data = AuraPowerDev { let data = AuraPowerDev {
@@ -553,7 +548,7 @@ fn handle_led_power_1_do_tuf(
} }
fn handle_led_power2( fn handle_led_power2(
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
supported: &LedSupportedFunctions, supported: &LedSupportedFunctions,
power: &LedPowerCommand2, power: &LedPowerCommand2,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -565,8 +560,8 @@ fn handle_led_power2(
println!("Commands available"); println!("Commands available");
if let Some(cmdlist) = LedPowerCommand2::command_list() { if let Some(cmdlist) = LedPowerCommand2::command_list() {
let commands: Vec<String> = cmdlist.lines().map(|s| s.to_string()).collect(); let commands: Vec<String> = cmdlist.lines().map(|s| s.to_owned()).collect();
for command in commands.iter() { for command in &commands {
println!("{}", command); println!("{}", command);
} }
} }
@@ -582,7 +577,7 @@ fn handle_led_power2(
} }
if supported.prod_id != AuraDevice::X19B6 { if supported.prod_id != AuraDevice::X19B6 {
println!("This option applies only to keyboards with product ID 0x19b6") println!("This option applies only to keyboards with product ID 0x19b6");
} }
let mut enabled: Vec<AuraDev19b6> = Vec::new(); let mut enabled: Vec<AuraDev19b6> = Vec::new();
@@ -647,7 +642,7 @@ fn handle_led_power2(
} }
fn handle_profile( fn handle_profile(
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
supported: &PlatformProfileFunctions, supported: &PlatformProfileFunctions,
cmd: &ProfileCommand, cmd: &ProfileCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -676,7 +671,9 @@ fn handle_profile(
if cmd.list { if cmd.list {
let res = dbus.proxies().profile().profiles()?; let res = dbus.proxies().profile().profiles()?;
res.iter().for_each(|p| println!("{:?}", p)); for p in &res {
println!("{:?}", p);
}
} }
if cmd.profile_get { if cmd.profile_get {
@@ -688,7 +685,7 @@ fn handle_profile(
} }
fn handle_fan_curve( fn handle_fan_curve(
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
supported: &PlatformProfileFunctions, supported: &PlatformProfileFunctions,
cmd: &FanCurveCommand, cmd: &FanCurveCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -750,7 +747,7 @@ fn handle_fan_curve(
} }
fn handle_bios_option( fn handle_bios_option(
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
supported: &RogBiosSupportedFunctions, supported: &RogBiosSupportedFunctions,
cmd: &BiosCommand, cmd: &BiosCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
@@ -765,10 +762,7 @@ fn handle_bios_option(
{ {
println!("Missing arg or command\n"); println!("Missing arg or command\n");
let usage: Vec<String> = BiosCommand::usage() let usage: Vec<String> = BiosCommand::usage().lines().map(|s| s.to_owned()).collect();
.lines()
.map(|s| s.to_string())
.collect();
for line in usage.iter().filter(|line| { for line in usage.iter().filter(|line| {
line.contains("sound") && supported.post_sound line.contains("sound") && supported.post_sound
+1 -2
View File
@@ -1,5 +1,6 @@
[package] [package]
name = "daemon-user" name = "daemon-user"
license = "MPL-2.0"
version.workspace = true version.workspace = true
authors = ["Luke D Jones <luke@ljones.dev>"] authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2021" edition = "2021"
@@ -28,5 +29,3 @@ rog_dbus = { path = "../rog-dbus" }
rog_platform = { path = "../rog-platform" } rog_platform = { path = "../rog-platform" }
zbus.workspace = true zbus.workspace = true
zvariant.workspace = true
zvariant_derive.workspace = true
+13 -12
View File
@@ -11,9 +11,10 @@ use std::{
}, },
}; };
use std::{sync::Arc, thread::sleep, time::Instant}; use std::{sync::Arc, thread::sleep, time::Instant};
use zbus::dbus_interface; use zbus::{
use zvariant::ObjectPath; dbus_interface,
use zvariant_derive::Type; zvariant::{ObjectPath, Type},
};
use crate::user_config::ConfigLoadSave; use crate::user_config::ConfigLoadSave;
use crate::{error::Error, user_config::UserAnimeConfig}; use crate::{error::Error, user_config::UserAnimeConfig};
@@ -102,7 +103,7 @@ impl<'a> CtrlAnimeInner<'static> {
.write(output) .write(output)
.map_err(|e| AnimeError::Dbus(format!("{}", e))) .map_err(|e| AnimeError::Dbus(format!("{}", e)))
.map(|_| false) .map(|_| false)
})?; });
} }
ActionData::Image(image) => { ActionData::Image(image) => {
self.client self.client
@@ -123,10 +124,10 @@ impl<'a> CtrlAnimeInner<'static> {
sleep(Duration::from_millis(1)); sleep(Duration::from_millis(1));
} }
} }
ActionData::AudioEq => {} ActionData::AudioEq
ActionData::SystemInfo => {} | ActionData::SystemInfo
ActionData::TimeDate => {} | ActionData::TimeDate
ActionData::Matrix => {} | ActionData::Matrix => {}
} }
} }
@@ -142,7 +143,7 @@ pub struct CtrlAnime<'a> {
inner_early_return: Arc<AtomicBool>, inner_early_return: Arc<AtomicBool>,
} }
impl<'a> CtrlAnime<'static> { impl CtrlAnime<'static> {
pub fn new( pub fn new(
config: Arc<Mutex<UserAnimeConfig>>, config: Arc<Mutex<UserAnimeConfig>>,
inner: Arc<Mutex<CtrlAnimeInner<'static>>>, inner: Arc<Mutex<CtrlAnimeInner<'static>>>,
@@ -184,7 +185,7 @@ impl CtrlAnime<'static> {
pub fn insert_asus_gif( pub fn insert_asus_gif(
&mut self, &mut self,
index: u32, index: u32,
file: String, file: &str,
time: Timer, time: Timer,
brightness: f32, brightness: f32,
) -> zbus::fdo::Result<String> { ) -> zbus::fdo::Result<String> {
@@ -222,7 +223,7 @@ impl CtrlAnime<'static> {
pub fn insert_image_gif( pub fn insert_image_gif(
&mut self, &mut self,
index: u32, index: u32,
file: String, file: &str,
scale: f32, scale: f32,
angle: f32, angle: f32,
xy: (f32, f32), xy: (f32, f32),
@@ -268,7 +269,7 @@ impl CtrlAnime<'static> {
pub fn insert_image( pub fn insert_image(
&mut self, &mut self,
index: u32, index: u32,
file: String, file: &str,
scale: f32, scale: f32,
angle: f32, angle: f32,
xy: (f32, f32), xy: (f32, f32),
+1 -1
View File
@@ -13,7 +13,7 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
// This trait requires `fmt` with this exact signature. // This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Error::Io(err) => write!(f, "Failed to open: {}", err), Error::Io(err) => write!(f, "Failed to open: {}", err),
Error::ConfigLoadFail => write!(f, "Failed to load user config"), Error::ConfigLoadFail => write!(f, "Failed to load user config"),
+4 -4
View File
@@ -114,7 +114,7 @@ impl ConfigLoadSave<UserAnimeConfig> for UserAnimeConfig {
impl Default for UserAnimeConfig { impl Default for UserAnimeConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
name: "default".to_string(), name: "default".to_owned(),
anime: vec![ anime: vec![
ActionLoader::AsusImage { ActionLoader::AsusImage {
file: "/usr/share/asusd/anime/custom/diagonal-template.png".into(), file: "/usr/share/asusd/anime/custom/diagonal-template.png".into(),
@@ -233,7 +233,7 @@ impl Default for UserAuraConfig {
seq.push(key); seq.push(key);
Self { Self {
name: "default".to_string(), name: "default".to_owned(),
aura: seq, aura: seq,
} }
} }
@@ -251,8 +251,8 @@ pub struct UserConfig {
impl UserConfig { impl UserConfig {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
active_anime: Some("anime-default".to_string()), active_anime: Some("anime-default".to_owned()),
active_aura: Some("aura-default".to_string()), active_aura: Some("aura-default".to_owned()),
} }
} }
+1 -2
View File
@@ -1,7 +1,7 @@
[package] [package]
name = "daemon" name = "daemon"
version.workspace = true
license = "MPL-2.0" license = "MPL-2.0"
version.workspace = true
readme = "README.md" readme = "README.md"
authors = ["Luke <luke@ljones.dev>"] authors = ["Luke <luke@ljones.dev>"]
repository = "https://gitlab.com/asus-linux/asus-nb-ctrl" repository = "https://gitlab.com/asus-linux/asus-nb-ctrl"
@@ -32,7 +32,6 @@ log.workspace = true
env_logger.workspace = true env_logger.workspace = true
zbus.workspace = true zbus.workspace = true
zvariant.workspace = true
logind-zbus.workspace = true logind-zbus.workspace = true
# serialisation # serialisation
+3 -3
View File
@@ -42,7 +42,7 @@ impl Config {
"Could not deserialise {}.\nWill rename to {}-old and recreate config", "Could not deserialise {}.\nWill rename to {}-old and recreate config",
CONFIG_PATH, CONFIG_PATH CONFIG_PATH, CONFIG_PATH
); );
let cfg_old = CONFIG_PATH.to_string() + "-old"; let cfg_old = CONFIG_PATH.to_owned() + "-old";
std::fs::rename(CONFIG_PATH, cfg_old).unwrap_or_else(|err| { std::fs::rename(CONFIG_PATH, cfg_old).unwrap_or_else(|err| {
panic!( panic!(
"Could not rename. Please remove {} then restart service: Error {}", "Could not rename. Please remove {} then restart service: Error {}",
@@ -52,7 +52,7 @@ impl Config {
config = Self::new(); config = Self::new();
} }
} else { } else {
config = Self::new() config = Self::new();
} }
config.write(); config.write();
config config
@@ -61,7 +61,7 @@ impl Config {
pub fn read(&mut self) { pub fn read(&mut self) {
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
.read(true) .read(true)
.open(&CONFIG_PATH) .open(CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_PATH, err)); .unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_PATH, err));
let mut buf = String::new(); let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) { if let Ok(l) = file.read_to_string(&mut buf) {
+6 -6
View File
@@ -86,25 +86,25 @@ impl AnimeConfigCached {
anime_type: AnimeType, anime_type: AnimeType,
) -> Result<(), AnimeError> { ) -> Result<(), AnimeError> {
let mut sys = Vec::with_capacity(config.system.len()); let mut sys = Vec::with_capacity(config.system.len());
for ani in config.system.iter() { for ani in &config.system {
sys.push(ActionData::from_anime_action(anime_type, ani)?); sys.push(ActionData::from_anime_action(anime_type, ani)?);
} }
self.system = sys; self.system = sys;
let mut boot = Vec::with_capacity(config.boot.len()); let mut boot = Vec::with_capacity(config.boot.len());
for ani in config.boot.iter() { for ani in &config.boot {
boot.push(ActionData::from_anime_action(anime_type, ani)?); boot.push(ActionData::from_anime_action(anime_type, ani)?);
} }
self.boot = boot; self.boot = boot;
let mut wake = Vec::with_capacity(config.wake.len()); let mut wake = Vec::with_capacity(config.wake.len());
for ani in config.wake.iter() { for ani in &config.wake {
wake.push(ActionData::from_anime_action(anime_type, ani)?); wake.push(ActionData::from_anime_action(anime_type, ani)?);
} }
self.wake = wake; self.wake = wake;
let mut shutdown = Vec::with_capacity(config.shutdown.len()); let mut shutdown = Vec::with_capacity(config.shutdown.len());
for ani in config.shutdown.iter() { for ani in &config.shutdown {
shutdown.push(ActionData::from_anime_action(anime_type, ani)?); shutdown.push(ActionData::from_anime_action(anime_type, ani)?);
} }
self.shutdown = shutdown; self.shutdown = shutdown;
@@ -145,7 +145,7 @@ impl AnimeConfig {
.read(true) .read(true)
.write(true) .write(true)
.create(true) .create(true)
.open(&ANIME_CONFIG_PATH) .open(ANIME_CONFIG_PATH)
.unwrap_or_else(|_| { .unwrap_or_else(|_| {
panic!( panic!(
"The file {} or directory /etc/asusd/ is missing", "The file {} or directory /etc/asusd/ is missing",
@@ -249,7 +249,7 @@ impl AnimeConfig {
pub fn read(&mut self) { pub fn read(&mut self) {
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
.read(true) .read(true)
.open(&ANIME_CONFIG_PATH) .open(ANIME_CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", ANIME_CONFIG_PATH, err)); .unwrap_or_else(|err| panic!("Error reading {}: {}", ANIME_CONFIG_PATH, err));
let mut buf = String::new(); let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) { if let Ok(l) = file.read_to_string(&mut buf) {
+17 -18
View File
@@ -1,5 +1,5 @@
pub mod config; pub mod config;
/// Implements CtrlTask, Reloadable, ZbusRun /// Implements `CtrlTask`, Reloadable, `ZbusRun`
pub mod trait_impls; pub mod trait_impls;
use self::config::{AnimeConfig, AnimeConfigCached}; use self::config::{AnimeConfig, AnimeConfigCached};
@@ -62,7 +62,7 @@ impl CtrlAnime {
/// one running - so the thread uses atomics to signal run/exit. /// one running - so the thread uses atomics to signal run/exit.
/// ///
/// Because this also writes to the usb device, other write tries (display only) *must* /// Because this also writes to the usb device, other write tries (display only) *must*
/// get the mutex lock and set the thread_exit atomic. /// get the mutex lock and set the `thread_exit` atomic.
fn run_thread(inner: Arc<Mutex<CtrlAnime>>, actions: Vec<ActionData>, mut once: bool) { fn run_thread(inner: Arc<Mutex<CtrlAnime>>, actions: Vec<ActionData>, mut once: bool) {
if actions.is_empty() { if actions.is_empty() {
warn!("AniMe system actions was empty"); warn!("AniMe system actions was empty");
@@ -106,13 +106,13 @@ impl CtrlAnime {
'main: loop { 'main: loop {
thread_running.store(true, Ordering::SeqCst); thread_running.store(true, Ordering::SeqCst);
for action in actions.iter() { for action in &actions {
if thread_exit.load(Ordering::SeqCst) { if thread_exit.load(Ordering::SeqCst) {
break 'main; break 'main;
} }
match action { match action {
ActionData::Animation(frames) => { ActionData::Animation(frames) => {
if let Err(err) = rog_anime::run_animation(frames, &|frame| { rog_anime::run_animation(frames, &|frame| {
if thread_exit.load(Ordering::Acquire) { if thread_exit.load(Ordering::Acquire) {
info!("rog-anime: frame-loop was asked to exit"); info!("rog-anime: frame-loop was asked to exit");
return Ok(true); // Do safe exit return Ok(true); // Do safe exit
@@ -130,15 +130,14 @@ impl CtrlAnime {
.ok(); .ok();
false // Don't exit yet false // Don't exit yet
}) })
.map(Ok) .map_or_else(
.unwrap_or_else(|| { || {
warn!("rog_anime::run_animation:callback failed"); warn!("rog_anime::run_animation:callback failed");
Err(AnimeError::NoFrames) Err(AnimeError::NoFrames)
}) },
}) { Ok,
warn!("rog_anime::run_animation:Animation {}", err); )
break 'main; });
};
} }
ActionData::Image(image) => { ActionData::Image(image) => {
once = false; once = false;
@@ -149,10 +148,10 @@ impl CtrlAnime {
} }
} }
ActionData::Pause(duration) => sleep(*duration), ActionData::Pause(duration) => sleep(*duration),
ActionData::AudioEq => {} ActionData::AudioEq
ActionData::SystemInfo => {} | ActionData::SystemInfo
ActionData::TimeDate => {} | ActionData::TimeDate
ActionData::Matrix => {} | ActionData::Matrix => {}
} }
} }
if thread_exit.load(Ordering::SeqCst) { if thread_exit.load(Ordering::SeqCst) {
@@ -194,7 +193,7 @@ impl CtrlAnime {
*led = bright as u8; *led = bright as u8;
} }
let data = AnimePacketType::try_from(buffer)?; let data = AnimePacketType::try_from(buffer)?;
for row in data.iter() { for row in &data {
self.node.write_bytes(row)?; self.node.write_bytes(row)?;
} }
self.node.write_bytes(&pkt_for_flush())?; self.node.write_bytes(&pkt_for_flush())?;
+2 -2
View File
@@ -47,7 +47,7 @@ impl CtrlAnimeZbus {
let mut lock = self.0.lock().await; let mut lock = self.0.lock().await;
let mut bright = bright; let mut bright = bright;
if bright < 0.0 { if bright < 0.0 {
bright = 0.0 bright = 0.0;
} else if bright > 1.0 { } else if bright > 1.0 {
bright = 1.0; bright = 1.0;
} }
@@ -149,7 +149,7 @@ impl crate::CtrlTask for CtrlAnimeZbus {
async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> { async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> {
let run_action = let run_action =
|start: bool, lock: MutexGuard<CtrlAnime>, inner: Arc<Mutex<CtrlAnime>>| { |start: bool, lock: MutexGuard<'_, CtrlAnime>, inner: Arc<Mutex<CtrlAnime>>| {
if start { if start {
info!("CtrlAnimeTask running sleep animation"); info!("CtrlAnimeTask running sleep animation");
CtrlAnime::run_thread(inner, lock.cache.shutdown.clone(), true); CtrlAnime::run_thread(inner, lock.cache.shutdown.clone(), true);
+22 -25
View File
@@ -127,7 +127,7 @@ pub struct AuraConfig {
impl Default for AuraConfig { impl Default for AuraConfig {
fn default() -> Self { fn default() -> Self {
let mut prod_id = AuraDevice::Unknown; let mut prod_id = AuraDevice::Unknown;
for prod in ASUS_KEYBOARD_DEVICES.iter() { for prod in &ASUS_KEYBOARD_DEVICES {
if HidRaw::new(prod).is_ok() { if HidRaw::new(prod).is_ok() {
prod_id = AuraDevice::from(*prod); prod_id = AuraDevice::from(*prod);
break; break;
@@ -192,7 +192,7 @@ impl AuraConfig {
.read(true) .read(true)
.write(true) .write(true)
.create(true) .create(true)
.open(&AURA_CONFIG_PATH) .open(AURA_CONFIG_PATH)
.unwrap_or_else(|_| { .unwrap_or_else(|_| {
panic!( panic!(
"The file {} or directory /etc/asusd/ is missing", "The file {} or directory /etc/asusd/ is missing",
@@ -242,7 +242,7 @@ impl AuraConfig {
colour2: *GRADIENT.get(GRADIENT.len() - i).unwrap_or(&GRADIENT[6]), colour2: *GRADIENT.get(GRADIENT.len() - i).unwrap_or(&GRADIENT[6]),
speed: Speed::Med, speed: Speed::Med,
direction: Direction::Left, direction: Direction::Left,
}) });
} }
if let Some(m) = config.multizone.as_mut() { if let Some(m) = config.multizone.as_mut() {
m.insert(*n, default); m.insert(*n, default);
@@ -264,7 +264,7 @@ impl AuraConfig {
pub fn read(&mut self) { pub fn read(&mut self) {
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
.read(true) .read(true)
.open(&AURA_CONFIG_PATH) .open(AURA_CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", AURA_CONFIG_PATH, err)); .unwrap_or_else(|err| panic!("Error reading {}: {}", AURA_CONFIG_PATH, err));
let mut buf = String::new(); let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) { if let Ok(l) = file.read_to_string(&mut buf) {
@@ -287,34 +287,31 @@ impl AuraConfig {
/// Set the mode data, current mode, and if multizone enabled. /// Set the mode data, current mode, and if multizone enabled.
/// ///
/// Multipurpose, will accept AuraEffect with zones and put in the correct store. /// Multipurpose, will accept `AuraEffect` with zones and put in the correct store.
pub fn set_builtin(&mut self, effect: AuraEffect) { pub fn set_builtin(&mut self, effect: AuraEffect) {
self.current_mode = effect.mode; self.current_mode = effect.mode;
match effect.zone() { if effect.zone() == AuraZone::None {
AuraZone::None => { self.builtins.insert(*effect.mode(), effect);
self.builtins.insert(*effect.mode(), effect); self.multizone_on = false;
self.multizone_on = false; } else {
} if let Some(multi) = self.multizone.as_mut() {
_ => { if let Some(fx) = multi.get_mut(effect.mode()) {
if let Some(multi) = self.multizone.as_mut() { for fx in fx.iter_mut() {
if let Some(fx) = multi.get_mut(effect.mode()) { if fx.zone == effect.zone {
for fx in fx.iter_mut() { *fx = effect;
if fx.zone == effect.zone { return;
*fx = effect;
return;
}
} }
fx.push(effect);
} else {
multi.insert(*effect.mode(), vec![effect]);
} }
fx.push(effect);
} else { } else {
let mut tmp = BTreeMap::new(); multi.insert(*effect.mode(), vec![effect]);
tmp.insert(*effect.mode(), vec![effect]);
self.multizone = Some(tmp);
} }
self.multizone_on = true; } else {
let mut tmp = BTreeMap::new();
tmp.insert(*effect.mode(), vec![effect]);
self.multizone = Some(tmp);
} }
self.multizone_on = true;
} }
} }
+7 -7
View File
@@ -26,7 +26,7 @@ impl GetSupported for CtrlKbdLed {
let per_key_led_mode = laptop.per_key; let per_key_led_mode = laptop.per_key;
let mut prod_id = AuraDevice::Unknown; let mut prod_id = AuraDevice::Unknown;
for prod in ASUS_KEYBOARD_DEVICES.iter() { for prod in &ASUS_KEYBOARD_DEVICES {
if HidRaw::new(prod).is_ok() { if HidRaw::new(prod).is_ok() {
prod_id = AuraDevice::from(*prod); prod_id = AuraDevice::from(*prod);
break; break;
@@ -72,10 +72,10 @@ impl CtrlKbdLed {
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> { pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {
let mut led_prod = None; let mut led_prod = None;
let mut led_node = None; let mut led_node = None;
for prod in ASUS_KEYBOARD_DEVICES.iter() { for prod in &ASUS_KEYBOARD_DEVICES {
match HidRaw::new(prod) { match HidRaw::new(prod) {
Ok(node) => { Ok(node) => {
led_prod = Some(prod.to_string()); led_prod = Some((*prod).to_owned());
led_node = Some(node); led_node = Some(node);
info!("Looked for keyboard controller 0x{prod}: Found"); info!("Looked for keyboard controller 0x{prod}: Found");
break; break;
@@ -335,7 +335,7 @@ impl CtrlKbdLed {
colour2: *GRADIENT.get(GRADIENT.len() - i).unwrap_or(&GRADIENT[6]), colour2: *GRADIENT.get(GRADIENT.len() - i).unwrap_or(&GRADIENT[6]),
speed: Speed::Med, speed: Speed::Med,
direction: Direction::Left, direction: Direction::Left,
}) });
} }
if default.is_empty() { if default.is_empty() {
return Err(RogError::AuraEffectNotSupported); return Err(RogError::AuraEffectNotSupported);
@@ -370,7 +370,7 @@ mod tests {
// Checking to ensure set_mode errors when unsupported modes are tried // Checking to ensure set_mode errors when unsupported modes are tried
let config = AuraConfig::default(); let config = AuraConfig::default();
let supported_modes = LaptopLedData { let supported_modes = LaptopLedData {
prod_family: "".into(), prod_family: String::new(),
board_names: vec![], board_names: vec![],
standard: vec![AuraModeNum::Static], standard: vec![AuraModeNum::Static],
multizone: vec![], multizone: vec![],
@@ -432,7 +432,7 @@ mod tests {
// Checking to ensure set_mode errors when unsupported modes are tried // Checking to ensure set_mode errors when unsupported modes are tried
let config = AuraConfig::default(); let config = AuraConfig::default();
let supported_modes = LaptopLedData { let supported_modes = LaptopLedData {
prod_family: "".into(), prod_family: String::new(),
board_names: vec![], board_names: vec![],
standard: vec![AuraModeNum::Static], standard: vec![AuraModeNum::Static],
multizone: vec![], multizone: vec![],
@@ -470,7 +470,7 @@ mod tests {
// Checking to ensure set_mode errors when unsupported modes are tried // Checking to ensure set_mode errors when unsupported modes are tried
let config = AuraConfig::default(); let config = AuraConfig::default();
let supported_modes = LaptopLedData { let supported_modes = LaptopLedData {
prod_family: "".into(), prod_family: String::new(),
board_names: vec![], board_names: vec![],
standard: vec![AuraModeNum::Static], standard: vec![AuraModeNum::Static],
multizone: vec![AuraZone::Key1, AuraZone::Key2], multizone: vec![AuraZone::Key1, AuraZone::Key2],
+1 -1
View File
@@ -237,7 +237,7 @@ impl CtrlTask for CtrlKbdLedZbus {
} }
async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> { async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> {
let load_save = |start: bool, mut lock: MutexGuard<CtrlKbdLed>| { let load_save = |start: bool, mut lock: MutexGuard<'_, CtrlKbdLed>| {
// If waking up // If waking up
if !start { if !start {
info!("CtrlKbdLedTask reloading brightness and modes"); info!("CtrlKbdLedTask reloading brightness and modes");
+2 -1
View File
@@ -43,7 +43,8 @@ impl ProfileConfig {
"Could not deserialise {}.\nWill rename to {}-old and recreate config", "Could not deserialise {}.\nWill rename to {}-old and recreate config",
config_path, config_path config_path, config_path
); );
let cfg_old = config_path.clone() + "-old"; let mut cfg_old = config_path.clone();
cfg_old.push_str("-old");
std::fs::rename(config_path.clone(), cfg_old).unwrap_or_else(|err| { std::fs::rename(config_path.clone(), cfg_old).unwrap_or_else(|err| {
panic!( panic!(
"Could not rename. Please remove {} then restart service: Error {}", "Could not rename. Please remove {} then restart service: Error {}",
+1 -1
View File
@@ -1,4 +1,4 @@
pub mod config; pub mod config;
pub mod controller; pub mod controller;
/// Implements CtrlTask, Reloadable, ZbusRun /// Implements `CtrlTask`, Reloadable, `ZbusRun`
pub mod trait_impls; pub mod trait_impls;
+6 -6
View File
@@ -32,7 +32,7 @@ impl ProfileZbus {
return Ok(profiles); return Ok(profiles);
} }
Err(Error::Failed( Err(Error::Failed(
"Failed to get all profile details".to_string(), "Failed to get all profile details".to_owned(),
)) ))
} }
@@ -85,9 +85,9 @@ impl ProfileZbus {
let mut ctrl = self.0.lock().await; let mut ctrl = self.0.lock().await;
ctrl.config.read(); ctrl.config.read();
if let Some(curves) = &ctrl.config.fan_curves { if let Some(curves) = &ctrl.config.fan_curves {
return Ok(curves.get_enabled_curve_profiles().to_vec()); return Ok(curves.get_enabled_curve_profiles());
} }
Err(Error::Failed(UNSUPPORTED_MSG.to_string())) Err(Error::Failed(UNSUPPORTED_MSG.to_owned()))
} }
/// Set a profile fan curve enabled status. Will also activate a fan curve if in the /// Set a profile fan curve enabled status. Will also activate a fan curve if in the
@@ -109,7 +109,7 @@ impl ProfileZbus {
ctrl.save_config(); ctrl.save_config();
Ok(()) Ok(())
} else { } else {
Err(Error::Failed(UNSUPPORTED_MSG.to_string())) Err(Error::Failed(UNSUPPORTED_MSG.to_owned()))
} }
} }
@@ -121,7 +121,7 @@ impl ProfileZbus {
let curve = curves.get_fan_curves_for(profile); let curve = curves.get_fan_curves_for(profile);
return Ok(curve.clone()); return Ok(curve.clone());
} }
Err(Error::Failed(UNSUPPORTED_MSG.to_string())) Err(Error::Failed(UNSUPPORTED_MSG.to_owned()))
} }
/// Set the fan curve for the specified profile. /// Set the fan curve for the specified profile.
@@ -134,7 +134,7 @@ impl ProfileZbus {
.save_fan_curve(curve, profile) .save_fan_curve(curve, profile)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?; .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
} else { } else {
return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); return Err(Error::Failed(UNSUPPORTED_MSG.to_owned()));
} }
ctrl.write_profile_curve_to_platform() ctrl.write_profile_curve_to_platform()
.map_err(|e| warn!("Profile::set_profile, {}", e)) .map_err(|e| warn!("Profile::set_profile, {}", e))
+1 -3
View File
@@ -1,8 +1,6 @@
use async_trait::async_trait; use async_trait::async_trait;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use zbus::dbus_interface; use zbus::{dbus_interface, zvariant::Type, Connection};
use zbus::Connection;
use zvariant::Type;
use crate::{ use crate::{
ctrl_anime::CtrlAnime, ctrl_aura::controller::CtrlKbdLed, ctrl_platform::CtrlPlatform, ctrl_anime::CtrlAnime, ctrl_aura::controller::CtrlKbdLed, ctrl_platform::CtrlPlatform,
+2 -2
View File
@@ -37,7 +37,7 @@ pub enum RogError {
impl fmt::Display for RogError { impl fmt::Display for RogError {
// This trait requires `fmt` with this exact signature. // This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
RogError::ParseVendor => write!(f, "Parse gfx vendor error"), RogError::ParseVendor => write!(f, "Parse gfx vendor error"),
RogError::ParseLed => write!(f, "Parse LED error"), RogError::ParseLed => write!(f, "Parse LED error"),
@@ -51,7 +51,7 @@ impl fmt::Display for RogError {
RogError::DoTask(deets) => write!(f, "Task error: {}", deets), RogError::DoTask(deets) => write!(f, "Task error: {}", deets),
RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets), RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets),
RogError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error), RogError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error),
RogError::ReloadFail(deets) => write!(f, "Task error: {}", deets), RogError::ReloadFail(deets) => write!(f, "Reload error: {}", deets),
RogError::Profiles(deets) => write!(f, "Profile error: {}", deets), RogError::Profiles(deets) => write!(f, "Profile error: {}", deets),
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail), RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail), RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
+3 -3
View File
@@ -71,7 +71,7 @@ impl LaptopLedData {
} }
impl LedSupportFile { impl LedSupportFile {
/// Consumes the LEDModes /// Consumes the `LEDModes`
fn matcher(self, prod_family: &str, board_name: &str) -> Option<LaptopLedData> { fn matcher(self, prod_family: &str, board_name: &str) -> Option<LaptopLedData> {
for config in self.led_data { for config in self.led_data {
if prod_family.contains(&config.prod_family) { if prod_family.contains(&config.prod_family) {
@@ -90,7 +90,7 @@ impl LedSupportFile {
let mut loaded = false; let mut loaded = false;
let mut data = LedSupportFile::default(); let mut data = LedSupportFile::default();
// Load user configs first so they are first to be checked // Load user configs first so they are first to be checked
if let Ok(mut file) = OpenOptions::new().read(true).open(&ASUS_LED_MODE_USER_CONF) { if let Ok(mut file) = OpenOptions::new().read(true).open(ASUS_LED_MODE_USER_CONF) {
let mut buf = String::new(); let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) { if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 { if l == 0 {
@@ -107,7 +107,7 @@ impl LedSupportFile {
} }
} }
// Load and append the default LED support data // Load and append the default LED support data
if let Ok(mut file) = OpenOptions::new().read(true).open(&ASUS_LED_MODE_CONF) { if let Ok(mut file) = OpenOptions::new().read(true).open(ASUS_LED_MODE_CONF) {
let mut buf = String::new(); let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) { if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 { if l == 0 {
+2 -4
View File
@@ -1,7 +1,7 @@
#![deny(unused_must_use)] #![deny(unused_must_use)]
/// Configuration loading, saving /// Configuration loading, saving
pub mod config; pub mod config;
/// Control of AniMe matrix display /// Control of anime matrix display
pub mod ctrl_anime; pub mod ctrl_anime;
/// Keyboard LED brightness control, RGB, and LED display modes /// Keyboard LED brightness control, RGB, and LED display modes
pub mod ctrl_aura; pub mod ctrl_aura;
@@ -25,8 +25,7 @@ use crate::error::RogError;
use async_trait::async_trait; use async_trait::async_trait;
use log::warn; use log::warn;
use logind_zbus::manager::ManagerProxy; use logind_zbus::manager::ManagerProxy;
use zbus::{export::futures_util::StreamExt, Connection, SignalContext}; use zbus::{export::futures_util::StreamExt, zvariant::ObjectPath, Connection, SignalContext};
use zvariant::ObjectPath;
/// This macro adds a function which spawns an `inotify` task on the passed in `Executor`. /// This macro adds a function which spawns an `inotify` task on the passed in `Executor`.
/// ///
@@ -64,7 +63,6 @@ macro_rules! task_watch_item {
let mut buffer = [0; 32]; let mut buffer = [0; 32];
watch.event_stream(&mut buffer).unwrap().for_each(|_| async { watch.event_stream(&mut buffer).unwrap().for_each(|_| async {
let value = ctrl.$name(); let value = ctrl.$name();
dbg!(&value);
concat_idents::concat_idents!(notif_fn = notify_, $name { concat_idents::concat_idents!(notif_fn = notify_, $name {
Self::notif_fn(&signal_ctxt, value).await.ok(); Self::notif_fn(&signal_ctxt, value).await.ok();
}); });
+9 -2
View File
@@ -12,6 +12,13 @@ standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = [] multizone = []
per_key = false per_key = false
[[led_data]]
prod_family = "ASUS TUF Gaming A15"
board_names = ["FA506I"]
standard = ["Static", "Breathe", "Strobe", "Pulse"]
multizone = []
per_key = false
[[led_data]] [[led_data]]
prod_family = "Zephyrus S" prod_family = "Zephyrus S"
board_names = ["GX502", "GX701", "G531", "GL531", "G532"] board_names = ["GX502", "GX701", "G531", "GL531", "G532"]
@@ -71,7 +78,7 @@ per_key = true
[[led_data]] [[led_data]]
prod_family = "ROG Strix" prod_family = "ROG Strix"
board_names = ["G513QE", "GX531", "G512LV", "G712LV", "G712LW", "G513IH", "G513QY", "G713QM", "G512", "G713RW"] board_names = ["G513QE", "GX531", "G512LV", "G712LV", "G712LW", "G513IH", "G513QY", "G713QM", "G512", "G713RM", "G713RW"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = ["Key1", "Key2", "Key3", "Key4"] multizone = ["Key1", "Key2", "Key3", "Key4"]
per_key = false per_key = false
@@ -177,7 +184,7 @@ per_key = false
[[led_data]] [[led_data]]
prod_family = "ROG Strix" prod_family = "ROG Strix"
board_names = ["G513IC", "G513RC"] board_names = ["G513IC", "G513RC", "G513RM"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = [] multizone = []
per_key = false per_key = false
+1
View File
@@ -9,6 +9,7 @@ ENV{DMI_FAMILY}=="*TUF*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*ROG*", GOTO="asusd_start" ENV{DMI_FAMILY}=="*ROG*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*Zephyrus*", GOTO="asusd_start" ENV{DMI_FAMILY}=="*Zephyrus*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*Strix*", GOTO="asusd_start" ENV{DMI_FAMILY}=="*Strix*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*Vivo*ook*", GOTO="asusd_start"
# No match so # No match so
GOTO="asusd_end" GOTO="asusd_end"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 74 KiB

+69
View File
@@ -0,0 +1,69 @@
# https://embarkstudios.github.io/cargo-deny/
targets = [
{ triple = "aarch64-apple-darwin" },
{ triple = "aarch64-linux-android" },
{ triple = "wasm32-unknown-unknown" },
{ triple = "x86_64-apple-darwin" },
{ triple = "x86_64-pc-windows-msvc" },
{ triple = "x86_64-unknown-linux-gnu" },
{ triple = "x86_64-unknown-linux-musl" },
]
[advisories]
vulnerability = "deny"
unmaintained = "warn"
yanked = "deny"
ignore = [
"RUSTSEC-2020-0071", # https://rustsec.org/advisories/RUSTSEC-2020-0071 - chrono/time: Potential segfault in the time crate
"RUSTSEC-2020-0159", # https://rustsec.org/advisories/RUSTSEC-2020-0159 - chrono/time: Potential segfault in localtime_r invocations
"RUSTSEC-2021-0127", # https://rustsec.org/advisories/RUSTSEC-2021-0127 - https://github.com/bheisler/criterion.rs/issues/534
]
[bans]
multiple-versions = "deny"
wildcards = "allow" # at least until https://github.com/EmbarkStudios/cargo-deny/issues/241 is fixed
deny = [
{ name = "openssl" }, # prefer rustls
{ name = "openssl-sys" }, # prefer rustls
]
skip-tree = [
{ name = "criterion" }, # dev-dependency
{ name = "glium" }, # legacy crate, lots of old dependencies
{ name = "rfd" }, # example dependency
{ name = "three-d" }, # example dependency
]
[licenses]
unlicensed = "deny"
allow-osi-fsf-free = "neither"
confidence-threshold = 0.92 # We want really high confidence when inferring licenses from text
copyleft = "deny"
allow = [
"Apache-2.0", # https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)
"BSD-2-Clause", # https://tldrlegal.com/license/bsd-2-clause-license-(freebsd)
"BSD-3-Clause", # https://tldrlegal.com/license/bsd-3-clause-license-(revised)
"BSL-1.0", # https://tldrlegal.com/license/boost-software-license-1.0-explained
"CC0-1.0", # https://creativecommons.org/publicdomain/zero/1.0/
"ISC", # https://tldrlegal.com/license/-isc-license
"LicenseRef-UFL-1.0", # https://tldrlegal.com/license/ubuntu-font-license,-1.0 - no official SPDX, see https://github.com/emilk/egui/issues/2321
"MIT", # https://tldrlegal.com/license/mit-license
"MPL-2.0", # https://www.mozilla.org/en-US/MPL/2.0/FAQ/ - see Q11
"OFL-1.1", # https://spdx.org/licenses/OFL-1.1.html
"OpenSSL", # https://www.openssl.org/source/license.html
"Unicode-DFS-2016", # https://spdx.org/licenses/Unicode-DFS-2016.html
"Zlib", # https://tldrlegal.com/license/zlib-libpng-license-(zlib)
]
[[licenses.clarify]]
name = "webpki"
expression = "ISC"
license-files = [{ path = "LICENSE", hash = 0x001c7e6c }]
[[licenses.clarify]]
name = "ring"
expression = "MIT AND ISC AND OpenSSL"
license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }]
+2 -3
View File
@@ -1,7 +1,7 @@
[package] [package]
name = "rog_anime" name = "rog_anime"
version.workspace = true
license = "MPL-2.0" license = "MPL-2.0"
version.workspace = true
readme = "README.md" readme = "README.md"
authors = ["Luke <luke@ljones.dev>"] authors = ["Luke <luke@ljones.dev>"]
repository = "https://gitlab.com/asus-linux/asus-nb-ctrl" repository = "https://gitlab.com/asus-linux/asus-nb-ctrl"
@@ -14,7 +14,7 @@ exclude = ["data"]
[features] [features]
default = ["dbus", "detect"] default = ["dbus", "detect"]
dbus = ["zvariant", "zbus"] dbus = ["zbus"]
detect = ["sysfs-class"] detect = ["sysfs-class"]
[dependencies] [dependencies]
@@ -28,7 +28,6 @@ serde_derive.workspace = true
glam.workspace = true glam.workspace = true
zvariant = { workspace = true, optional = true }
zbus = { workspace = true, optional = true } zbus = { workspace = true, optional = true }
sysfs-class = { workspace = true, optional = true } sysfs-class = { workspace = true, optional = true }
+7 -11
View File
@@ -7,7 +7,7 @@ use std::{
use log::info; use log::info;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "dbus")] #[cfg(feature = "dbus")]
use zvariant::Type; use zbus::zvariant::Type;
use crate::{ use crate::{
error::{AnimeError, Result}, error::{AnimeError, Result},
@@ -47,8 +47,7 @@ impl AnimeType {
/// The width of diagonal images /// The width of diagonal images
pub fn width(&self) -> usize { pub fn width(&self) -> usize {
match self { match self {
AnimeType::GA401 => 74, AnimeType::GA401 | AnimeType::GA402 => 74,
AnimeType::GA402 => 74,
} }
} }
@@ -103,8 +102,8 @@ impl AnimeDataBuffer {
/// Create from a vector of bytes /// Create from a vector of bytes
/// ///
/// # Panics /// # Errors
/// Will panic if the vector length is not `ANIME_DATA_LEN` /// Will error if the vector length is not `ANIME_DATA_LEN`
#[inline] #[inline]
pub fn from_vec(anime: AnimeType, data: Vec<u8>) -> Result<Self> { pub fn from_vec(anime: AnimeType, data: Vec<u8>) -> Result<Self> {
if data.len() != anime.data_length() { if data.len() != anime.data_length() {
@@ -147,10 +146,7 @@ impl TryFrom<AnimeDataBuffer> for AnimePacketType {
/// This runs the animations as a blocking loop by using the `callback` to write data /// This runs the animations as a blocking loop by using the `callback` to write data
/// ///
/// If `callback` is `Ok(true)` then `run_animation` will exit the animation loop early. /// If `callback` is `Ok(true)` then `run_animation` will exit the animation loop early.
pub fn run_animation( pub fn run_animation(frames: &AnimeGif, callback: &dyn Fn(AnimeDataBuffer) -> Result<bool>) {
frames: &AnimeGif,
callback: &dyn Fn(AnimeDataBuffer) -> Result<bool>,
) -> Result<()> {
let mut count = 0; let mut count = 0;
let start = Instant::now(); let start = Instant::now();
@@ -215,9 +211,10 @@ pub fn run_animation(
} }
} }
// TODO: Log this error
if matches!(callback(output), Ok(true)) { if matches!(callback(output), Ok(true)) {
info!("rog-anime: frame-loop callback asked to exit early"); info!("rog-anime: frame-loop callback asked to exit early");
return Ok(()); return;
} }
if timed && Instant::now().duration_since(start) > run_time { if timed && Instant::now().duration_since(start) > run_time {
@@ -232,5 +229,4 @@ pub fn run_animation(
} }
} }
} }
Ok(())
} }
+18 -14
View File
@@ -52,39 +52,43 @@ impl AnimeDiagonal {
let mut matrix = AnimeDiagonal::new(anime_type, duration); let mut matrix = AnimeDiagonal::new(anime_type, duration);
match raster { match &raster {
png_pong::PngRaster::Gray8(ras) => { png_pong::PngRaster::Gray8(ras) => {
Self::pixels_from_8bit(ras, &mut matrix, bright, true) Self::pixels_from_8bit(ras, &mut matrix, bright, true);
} }
png_pong::PngRaster::Graya8(ras) => { png_pong::PngRaster::Graya8(ras) => {
Self::pixels_from_8bit(ras, &mut matrix, bright, true) Self::pixels_from_8bit(ras, &mut matrix, bright, true);
} }
png_pong::PngRaster::Rgb8(ras) => { png_pong::PngRaster::Rgb8(ras) => {
Self::pixels_from_8bit(ras, &mut matrix, bright, false) Self::pixels_from_8bit(ras, &mut matrix, bright, false);
} }
png_pong::PngRaster::Rgba8(ras) => { png_pong::PngRaster::Rgba8(ras) => {
Self::pixels_from_8bit(ras, &mut matrix, bright, false) Self::pixels_from_8bit(ras, &mut matrix, bright, false);
} }
png_pong::PngRaster::Gray16(ras) => { png_pong::PngRaster::Gray16(ras) => {
Self::pixels_from_16bit(ras, &mut matrix, bright, true) Self::pixels_from_16bit(ras, &mut matrix, bright, true);
} }
png_pong::PngRaster::Rgb16(ras) => { png_pong::PngRaster::Rgb16(ras) => {
Self::pixels_from_16bit(ras, &mut matrix, bright, false) Self::pixels_from_16bit(ras, &mut matrix, bright, false);
} }
png_pong::PngRaster::Graya16(ras) => { png_pong::PngRaster::Graya16(ras) => {
Self::pixels_from_16bit(ras, &mut matrix, bright, true) Self::pixels_from_16bit(ras, &mut matrix, bright, true);
} }
png_pong::PngRaster::Rgba16(ras) => { png_pong::PngRaster::Rgba16(ras) => {
Self::pixels_from_16bit(ras, &mut matrix, bright, false) Self::pixels_from_16bit(ras, &mut matrix, bright, false);
} }
_ => return Err(AnimeError::Format), png_pong::PngRaster::Palette(..) => return Err(AnimeError::Format),
}; };
Ok(matrix) Ok(matrix)
} }
fn pixels_from_8bit<P>(ras: pix::Raster<P>, matrix: &mut AnimeDiagonal, bright: f32, grey: bool) fn pixels_from_8bit<P>(
where ras: &pix::Raster<P>,
matrix: &mut AnimeDiagonal,
bright: f32,
grey: bool,
) where
P: pix::el::Pixel<Chan = pix::chan::Ch8>, P: pix::el::Pixel<Chan = pix::chan::Ch8>,
{ {
let width = ras.width(); let width = ras.width();
@@ -105,7 +109,7 @@ impl AnimeDiagonal {
} }
fn pixels_from_16bit<P>( fn pixels_from_16bit<P>(
ras: pix::Raster<P>, ras: &pix::Raster<P>,
matrix: &mut AnimeDiagonal, matrix: &mut AnimeDiagonal,
bright: f32, bright: f32,
grey: bool, grey: bool,
@@ -136,7 +140,7 @@ impl AnimeDiagonal {
} }
} }
/// Do conversion from the nested Vec in AnimeMatrix to the two required /// Do conversion from the nested Vec in `AnimeMatrix` to the two required
/// packets suitable for sending over USB /// packets suitable for sending over USB
fn to_ga401_packets(&self) -> Result<AnimeDataBuffer> { fn to_ga401_packets(&self) -> Result<AnimeDataBuffer> {
let mut buf = vec![0u8; AnimeType::GA401.data_length()]; let mut buf = vec![0u8; AnimeType::GA401.data_length()];
+1 -1
View File
@@ -26,7 +26,7 @@ pub enum AnimeError {
impl fmt::Display for AnimeError { impl fmt::Display for AnimeError {
#[inline] #[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
AnimeError::NoFrames => write!(f, "No frames in PNG"), AnimeError::NoFrames => write!(f, "No frames in PNG"),
AnimeError::Io(e) => write!(f, "Could not open: {}", e), AnimeError::Io(e) => write!(f, "Could not open: {}", e),
+1 -1
View File
@@ -93,7 +93,7 @@ impl AnimeGrid {
impl TryFrom<AnimeGrid> for AnimeDataBuffer { impl TryFrom<AnimeGrid> for AnimeDataBuffer {
type Error = AnimeError; type Error = AnimeError;
/// Do conversion from the nested Vec in AniMeMatrix to the two required /// Do conversion from the nested Vec in anime matrix to the two required
/// packets suitable for sending over USB /// packets suitable for sending over USB
fn try_from(anime: AnimeGrid) -> Result<Self> { fn try_from(anime: AnimeGrid) -> Result<Self> {
let mut buf = vec![0u8; anime.anime_type.data_length()]; let mut buf = vec![0u8; anime.anime_type.data_length()];
+9 -9
View File
@@ -30,7 +30,7 @@ impl Default for Pixel {
/// is to be used to sample an image and set the LED brightness. /// is to be used to sample an image and set the LED brightness.
/// ///
/// The position of the Led in `LedPositions` determines the placement in the final /// The position of the Led in `LedPositions` determines the placement in the final
/// data packets when written to the AniMe. /// data packets when written to the `AniMe`.
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct Led(f32, f32, u8); pub struct Led(f32, f32, u8);
@@ -58,7 +58,7 @@ impl Led {
/// Container of `Led`, each of which specifies a position within the image /// Container of `Led`, each of which specifies a position within the image
/// The main use of this is to position and sample colours for the final image /// The main use of this is to position and sample colours for the final image
/// to show on AniMe /// to show on `AniMe`
pub struct AnimeImage { pub struct AnimeImage {
pub scale: Vec2, pub scale: Vec2,
/// Angle in radians /// Angle in radians
@@ -294,8 +294,8 @@ impl AnimeImage {
let x0 = led_from_px.mul_vec3(pos + Vec3::new(0.0, -0.5, 0.0)); let x0 = led_from_px.mul_vec3(pos + Vec3::new(0.0, -0.5, 0.0));
const GROUP: [f32; 4] = [0.0, 0.5, 1.0, 1.5]; const GROUP: [f32; 4] = [0.0, 0.5, 1.0, 1.5];
for u in GROUP.iter() { for u in &GROUP {
for v in GROUP.iter() { for v in &GROUP {
let sample = x0 + *u * du + *v * dv; let sample = x0 + *u * du + *v * dv;
let x = sample.x as i32; let x = sample.x as i32;
@@ -399,7 +399,7 @@ impl AnimeImage {
let png_pong::Step { raster, delay: _ } = decoder.last().ok_or(AnimeError::NoFrames)??; let png_pong::Step { raster, delay: _ } = decoder.last().ok_or(AnimeError::NoFrames)??;
let width; let width;
let pixels = match raster { let pixels = match &raster {
png_pong::PngRaster::Gray8(ras) => { png_pong::PngRaster::Gray8(ras) => {
width = ras.width(); width = ras.width();
Self::pixels_from_8bit(ras, true) Self::pixels_from_8bit(ras, true)
@@ -432,7 +432,7 @@ impl AnimeImage {
width = ras.width(); width = ras.width();
Self::pixels_from_16bit(ras, false) Self::pixels_from_16bit(ras, false)
} }
_ => return Err(AnimeError::Format), png_pong::PngRaster::Palette(..) => return Err(AnimeError::Format),
}; };
let mut matrix = AnimeImage::new( let mut matrix = AnimeImage::new(
@@ -449,7 +449,7 @@ impl AnimeImage {
Ok(matrix) Ok(matrix)
} }
fn pixels_from_8bit<P>(ras: pix::Raster<P>, grey: bool) -> Vec<Pixel> fn pixels_from_8bit<P>(ras: &pix::Raster<P>, grey: bool) -> Vec<Pixel>
where where
P: pix::el::Pixel<Chan = pix::chan::Ch8>, P: pix::el::Pixel<Chan = pix::chan::Ch8>,
{ {
@@ -468,7 +468,7 @@ impl AnimeImage {
.collect() .collect()
} }
fn pixels_from_16bit<P>(ras: pix::Raster<P>, grey: bool) -> Vec<Pixel> fn pixels_from_16bit<P>(ras: &pix::Raster<P>, grey: bool) -> Vec<Pixel>
where where
P: pix::el::Pixel<Chan = pix::chan::Ch16>, P: pix::el::Pixel<Chan = pix::chan::Ch16>,
{ {
@@ -491,7 +491,7 @@ impl AnimeImage {
impl TryFrom<&AnimeImage> for AnimeDataBuffer { impl TryFrom<&AnimeImage> for AnimeDataBuffer {
type Error = AnimeError; type Error = AnimeError;
/// Do conversion from the nested Vec in AnimeDataBuffer to the two required /// Do conversion from the nested Vec in `AnimeDataBuffer` to the two required
/// packets suitable for sending over USB /// packets suitable for sending over USB
fn try_from(leds: &AnimeImage) -> Result<Self> { fn try_from(leds: &AnimeImage) -> Result<Self> {
let mut l: Vec<u8> = leds let mut l: Vec<u8> = leds
+2 -2
View File
@@ -7,11 +7,11 @@ pub use data::*;
mod grid; mod grid;
pub use grid::*; pub use grid::*;
/// Transform a PNG image for displaying on AniMe matrix display /// Transform a PNG image for displaying on `AniMe` matrix display
mod image; mod image;
pub use image::*; pub use image::*;
/// A grid of data that is intended to be read out and displayed on the ANiMe as /// A grid of data that is intended to be read out and displayed on the `AniMe` as
/// a diagonal /// a diagonal
mod diagonal; mod diagonal;
pub use diagonal::*; pub use diagonal::*;
+3 -3
View File
@@ -7,7 +7,7 @@ use crate::{
error::Result, AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType, error::Result, AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType,
}; };
/// All the possible AniMe actions that can be used. This enum is intended to be /// All the possible `AniMe` actions that can be used. This enum is intended to be
/// a helper for loading up `ActionData`. /// a helper for loading up `ActionData`.
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
pub enum ActionLoader { pub enum ActionLoader {
@@ -44,7 +44,7 @@ pub enum ActionLoader {
Pause(Duration), Pause(Duration),
} }
/// All the possible AniMe actions that can be used. The enum is intended to be /// All the possible `AniMe` actions that can be used. The enum is intended to be
/// used in a array allowing the user to cycle through a series of actions. /// used in a array allowing the user to cycle through a series of actions.
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
pub enum ActionData { pub enum ActionData {
@@ -194,7 +194,7 @@ impl Sequences {
None None
} }
pub fn iter(&self) -> ActionIterator { pub fn iter(&self) -> ActionIterator<'_> {
ActionIterator { ActionIterator {
actions: self, actions: self,
next_idx: 0, next_idx: 0,
+2 -2
View File
@@ -1,4 +1,4 @@
//! Utils for writing to the AniMe USB device //! Utils for writing to the `AniMe` USB device
//! //!
//! Use of the device requires a few steps: //! Use of the device requires a few steps:
//! 1. Initialise the device by writing the two packets from `get_init_packets()` //! 1. Initialise the device by writing the two packets from `get_init_packets()`
@@ -63,7 +63,7 @@ pub const fn pkt_for_flush() -> [u8; PACKET_SIZE] {
} }
/// Get the packet required for setting the device to on, on boot. Requires /// Get the packet required for setting the device to on, on boot. Requires
/// pkt_for_apply()` to be written after. /// `pkt_for_apply()` to be written after.
#[inline] #[inline]
pub const fn pkt_for_set_boot(status: bool) -> [u8; PACKET_SIZE] { pub const fn pkt_for_set_boot(status: bool) -> [u8; PACKET_SIZE] {
let mut pkt = [0; PACKET_SIZE]; let mut pkt = [0; PACKET_SIZE];
+3 -3
View File
@@ -1,7 +1,7 @@
[package] [package]
name = "rog_aura" name = "rog_aura"
version.workspace = true
license = "MPL-2.0" license = "MPL-2.0"
version.workspace = true
readme = "README.md" readme = "README.md"
authors = ["Luke <luke@ljones.dev>"] authors = ["Luke <luke@ljones.dev>"]
repository = "https://gitlab.com/asus-linux/asusctl" repository = "https://gitlab.com/asus-linux/asusctl"
@@ -14,13 +14,13 @@ exclude = ["data"]
[features] [features]
default = ["dbus", "toml"] default = ["dbus", "toml"]
dbus = ["zvariant"] dbus = ["zbus"]
[dependencies] [dependencies]
serde.workspace = true serde.workspace = true
serde_derive.workspace = true serde_derive.workspace = true
toml = { workspace = true, optional = true } toml = { workspace = true, optional = true }
zvariant = { workspace = true, optional = true } zbus = { workspace = true, optional = true }
[dev-dependencies] [dev-dependencies]
serde_json.workspace = true serde_json.workspace = true
+28 -45
View File
@@ -5,9 +5,9 @@ pub const LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08]; pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::str::FromStr; use std::{fmt::Display, str::FromStr};
#[cfg(feature = "dbus")] #[cfg(feature = "dbus")]
use zvariant::Type; use zbus::zvariant::Type;
use crate::{error::Error, LED_MSG_LEN}; use crate::{error::Error, LED_MSG_LEN};
@@ -25,7 +25,6 @@ impl From<u32> for LedBrightness {
match bright { match bright {
0 => LedBrightness::Off, 0 => LedBrightness::Off,
1 => LedBrightness::Low, 1 => LedBrightness::Low,
2 => LedBrightness::Med,
3 => LedBrightness::High, 3 => LedBrightness::High,
_ => LedBrightness::Med, _ => LedBrightness::Med,
} }
@@ -171,23 +170,15 @@ pub enum AuraModeNum {
Flash = 12, 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 { impl From<AuraModeNum> for String {
fn from(mode: AuraModeNum) -> Self { fn from(mode: AuraModeNum) -> Self {
match mode { <&str>::from(&mode).to_owned()
AuraModeNum::Static => "Static",
AuraModeNum::Breathe => "Breathe",
AuraModeNum::Strobe => "Strobe",
AuraModeNum::Rainbow => "Rainbow",
AuraModeNum::Star => "Stars",
AuraModeNum::Rain => "Rain",
AuraModeNum::Highlight => "Highlight",
AuraModeNum::Laser => "Laser",
AuraModeNum::Ripple => "Ripple",
AuraModeNum::Pulse => "Pulse",
AuraModeNum::Comet => "Comet",
AuraModeNum::Flash => "Flash",
}
.to_string()
} }
} }
@@ -212,7 +203,6 @@ impl From<&AuraModeNum> for &str {
impl From<&str> for AuraModeNum { impl From<&str> for AuraModeNum {
fn from(mode: &str) -> Self { fn from(mode: &str) -> Self {
match mode { match mode {
"Static" => AuraModeNum::Static,
"Breathe" => AuraModeNum::Breathe, "Breathe" => AuraModeNum::Breathe,
"Strobe" => AuraModeNum::Strobe, "Strobe" => AuraModeNum::Strobe,
"Rainbow" => AuraModeNum::Rainbow, "Rainbow" => AuraModeNum::Rainbow,
@@ -232,7 +222,6 @@ impl From<&str> for AuraModeNum {
impl From<u8> for AuraModeNum { impl From<u8> for AuraModeNum {
fn from(mode: u8) -> Self { fn from(mode: u8) -> Self {
match mode { match mode {
0 => AuraModeNum::Static,
1 => AuraModeNum::Breathe, 1 => AuraModeNum::Breathe,
2 => AuraModeNum::Strobe, 2 => AuraModeNum::Strobe,
3 => AuraModeNum::Rainbow, 3 => AuraModeNum::Rainbow,
@@ -278,22 +267,14 @@ impl FromStr for AuraZone {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase(); let s = s.to_lowercase();
match s.to_ascii_lowercase().as_str() { match s.to_ascii_lowercase().as_str() {
"0" => Ok(AuraZone::None), "0" | "none" => Ok(AuraZone::None),
"none" => Ok(AuraZone::None), "1" | "one" => Ok(AuraZone::Key1),
"1" => Ok(AuraZone::Key1), "2" | "two" => Ok(AuraZone::Key2),
"one" => Ok(AuraZone::Key1), "3" | "three" => Ok(AuraZone::Key3),
"2" => Ok(AuraZone::Key2), "4" | "four" => Ok(AuraZone::Key4),
"two" => Ok(AuraZone::Key2), "5" | "logo" => Ok(AuraZone::Logo),
"3" => Ok(AuraZone::Key3), "6" | "lightbar-left" => Ok(AuraZone::BarLeft),
"three" => Ok(AuraZone::Key3), "7" | "lightbar-right" => Ok(AuraZone::BarRight),
"4" => Ok(AuraZone::Key4),
"four" => Ok(AuraZone::Key4),
"5" => Ok(AuraZone::Logo),
"logo" => Ok(AuraZone::Logo),
"6" => Ok(AuraZone::BarLeft),
"lightbar-left" => Ok(AuraZone::BarLeft),
"7" => Ok(AuraZone::BarRight),
"lightbar-right" => Ok(AuraZone::BarRight),
_ => Err(Error::ParseSpeed), _ => Err(Error::ParseSpeed),
} }
} }
@@ -389,18 +370,20 @@ impl AuraEffect {
/// factory mode accepts only one colour. /// factory mode accepts only one colour.
pub const fn allowed_parameters(mode: AuraModeNum) -> AuraParameters { pub const fn allowed_parameters(mode: AuraModeNum) -> AuraParameters {
match mode { match mode {
AuraModeNum::Static => AuraParameters::new(true, true, false, false, false), AuraModeNum::Static
| AuraModeNum::Highlight
| AuraModeNum::Pulse
| AuraModeNum::Comet
| AuraModeNum::Flash => AuraParameters::new(true, true, false, false, false),
AuraModeNum::Breathe => AuraParameters::new(true, true, true, true, false), AuraModeNum::Breathe => AuraParameters::new(true, true, true, true, false),
AuraModeNum::Strobe => AuraParameters::new(true, false, false, true, false), AuraModeNum::Strobe | AuraModeNum::Rain => {
AuraParameters::new(true, false, false, true, false)
}
AuraModeNum::Rainbow => AuraParameters::new(true, false, false, true, true), AuraModeNum::Rainbow => AuraParameters::new(true, false, false, true, true),
AuraModeNum::Star => AuraParameters::new(true, true, true, true, true), AuraModeNum::Star => AuraParameters::new(true, true, true, true, true),
AuraModeNum::Rain => AuraParameters::new(true, false, false, true, false), AuraModeNum::Laser | AuraModeNum::Ripple => {
AuraModeNum::Highlight => AuraParameters::new(true, true, false, false, false), AuraParameters::new(true, true, false, true, false)
AuraModeNum::Laser => AuraParameters::new(true, true, false, true, false), }
AuraModeNum::Ripple => AuraParameters::new(true, true, false, true, false),
AuraModeNum::Pulse => AuraParameters::new(true, true, false, false, false),
AuraModeNum::Comet => AuraParameters::new(true, true, false, false, false),
AuraModeNum::Flash => AuraParameters::new(true, true, false, false, false),
} }
} }
} }
+1 -1
View File
@@ -13,7 +13,7 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
// This trait requires `fmt` with this exact signature. // This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Error::ParseColour => write!(f, "Could not parse colour"), Error::ParseColour => write!(f, "Could not parse colour"),
Error::ParseSpeed => write!(f, "Could not parse speed"), Error::ParseSpeed => write!(f, "Could not parse speed"),
+11 -11
View File
@@ -139,17 +139,17 @@ impl From<&Key> for &str {
Key::MediaStop => "Media Stop", Key::MediaStop => "Media Stop",
Key::MediaNext => "Media Next", Key::MediaNext => "Media Next",
Key::MediaPrev => "Media Previous", Key::MediaPrev => "Media Previous",
Key::NormalBlank => "", Key::NormalBlank
Key::NormalSpacer => "", | Key::NormalSpacer
Key::FuncBlank => "", | Key::FuncBlank
Key::FuncSpacer => "", | Key::FuncSpacer
Key::ArrowBlank => "", | Key::ArrowBlank
Key::ArrowSpacer => "", | Key::ArrowSpacer
Key::ArrowRegularBlank => "", | Key::ArrowRegularBlank
Key::ArrowRegularSpacer => "", | Key::ArrowRegularSpacer
Key::ArrowSplitBlank => "", | Key::ArrowSplitBlank
Key::ArrowSplitSpacer => "", | Key::ArrowSplitSpacer
Key::RowEndSpacer => "", | Key::RowEndSpacer => "",
} }
} }
} }
+14 -12
View File
@@ -203,17 +203,22 @@ pub enum KeyShape {
impl KeyShape { impl KeyShape {
pub const fn width(&self) -> f32 { pub const fn width(&self) -> f32 {
match self { match self {
Self::Tilde => 0.8, Self::Tilde | Self::Arrow => 0.8,
Self::Normal => 1.0, Self::Normal
Self::NormalBlank => 1.0, | Self::NormalBlank
Self::NormalSpacer => 1.0, | Self::NormalSpacer
Self::Func => 1.0, | Self::Func
Self::FuncBlank => 1.0, | Self::FuncBlank
| Self::Space5
| Self::ArrowBlank
| Self::ArrowSpacer
| Self::ArrowSplit
| Self::ArrowSplitBlank
| Self::ArrowSplitSpacer => 1.0,
Self::FuncSpacer => 0.6, Self::FuncSpacer => 0.6,
Self::Space => 5.0, Self::Space => 5.0,
Self::Space5 => 1.0,
Self::LCtrlMed => 1.1, Self::LCtrlMed => 1.1,
Self::LShift => 2.0, Self::LShift | Self::Backspace => 2.0,
Self::LShift3 => 0.67, Self::LShift3 => 0.67,
Self::RShift => 2.8, Self::RShift => 2.8,
Self::RshiftSmall => 1.8, Self::RshiftSmall => 1.8,
@@ -222,12 +227,9 @@ impl KeyShape {
Self::Return3 => 0.7333, Self::Return3 => 0.7333,
Self::Tab => 1.4, Self::Tab => 1.4,
Self::Caps => 1.6, Self::Caps => 1.6,
Self::Backspace => 2.0,
Self::Backspace3 => 0.666, Self::Backspace3 => 0.666,
Self::ArrowRegularBlank | Self::ArrowRegularSpacer => 0.7, Self::ArrowRegularBlank | Self::ArrowRegularSpacer => 0.7,
Self::Arrow => 0.8,
Self::ArrowBlank | Self::ArrowSpacer => 1.0,
Self::ArrowSplit | Self::ArrowSplitBlank | Self::ArrowSplitSpacer => 1.0,
Self::RowEndSpacer => 0.1, Self::RowEndSpacer => 0.1,
} }
} }
+1 -1
View File
@@ -6,7 +6,7 @@ impl KeyLayout {
pub fn g513_layout() -> Self { pub fn g513_layout() -> Self {
Self { Self {
matches: vec!["G513".into()], matches: vec!["G513".into()],
locale: "US".to_string(), locale: "US".to_owned(),
rows: vec![ rows: vec![
KeyRow::new( KeyRow::new(
0.8, 0.8,
+1 -1
View File
@@ -5,7 +5,7 @@ impl KeyLayout {
pub fn ga401_layout() -> Self { pub fn ga401_layout() -> Self {
Self { Self {
matches: vec!["GA401".into(), "GA402".into()], matches: vec!["GA401".into(), "GA402".into()],
locale: "US".to_string(), locale: "US".to_owned(),
rows: vec![ rows: vec![
KeyRow::new( KeyRow::new(
0.8, 0.8,
+1 -1
View File
@@ -5,7 +5,7 @@ impl KeyLayout {
pub fn gx502_layout() -> Self { pub fn gx502_layout() -> Self {
Self { Self {
matches: vec!["GX502".into(), "GU502".into()], matches: vec!["GX502".into(), "GU502".into()],
locale: "US".to_string(), locale: "US".to_owned(),
rows: vec![ rows: vec![
KeyRow::new( KeyRow::new(
0.8, 0.8,
+2 -2
View File
@@ -43,7 +43,7 @@ impl KeyLayout {
pub fn matches(&self, board_name: &str) -> bool { pub fn matches(&self, board_name: &str) -> bool {
let board = board_name.to_ascii_uppercase(); let board = board_name.to_ascii_uppercase();
for tmp in self.matches.iter() { for tmp in &self.matches {
if board.contains(tmp.as_str()) { if board.contains(tmp.as_str()) {
return true; return true;
} }
@@ -91,7 +91,7 @@ impl KeyRow {
Self { height, row } Self { height, row }
} }
pub fn row(&self) -> Iter<Key> { pub fn row(&self) -> Iter<'_, Key> {
self.row.iter() self.row.iter()
} }
+1 -1
View File
@@ -1,7 +1,7 @@
use crate::keys::Key; use crate::keys::Key;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "dbus")] #[cfg(feature = "dbus")]
use zvariant::Type; use zbus::zvariant::Type;
/// Represents the per-key raw USB packets /// Represents the per-key raw USB packets
pub type PerKeyRaw = Vec<Vec<u8>>; pub type PerKeyRaw = Vec<Vec<u8>>;
+2 -3
View File
@@ -1,6 +1,6 @@
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "dbus")] #[cfg(feature = "dbus")]
use zvariant::Type; use zbus::zvariant::Type;
/// Represents the zoned raw USB packets /// Represents the zoned raw USB packets
pub type ZonedRaw = Vec<u8>; pub type ZonedRaw = Vec<u8>;
@@ -43,8 +43,7 @@ impl ZonedColourArray {
pub fn rgb_for_zone(&mut self, zone: PerZone) -> &mut [u8] { pub fn rgb_for_zone(&mut self, zone: PerZone) -> &mut [u8] {
match zone { match zone {
PerZone::None => &mut self.0[9..=11], PerZone::None | PerZone::KeyboardLeft => &mut self.0[9..=11],
PerZone::KeyboardLeft => &mut self.0[9..=11],
PerZone::KeyboardCenterLeft => &mut self.0[12..=14], PerZone::KeyboardCenterLeft => &mut self.0[12..=14],
PerZone::KeyboardCenterRight => &mut self.0[15..=17], PerZone::KeyboardCenterRight => &mut self.0[15..=17],
PerZone::KeyboardRight => &mut self.0[18..=20], PerZone::KeyboardRight => &mut self.0[18..=20],
+3 -3
View File
@@ -9,7 +9,7 @@ use serde_derive::{Deserialize, Serialize};
// static mut RNDINDEX: usize = 0; // static mut RNDINDEX: usize = 0;
static mut PRNDINDEX: usize = 0; static mut PRNDINDEX: usize = 0;
/// Pseudo random table ripped straight out of Room4Doom /// Pseudo random table ripped straight out of room4doom
pub const RNDTABLE: [i32; 256] = [ pub const RNDTABLE: [i32; 256] = [
0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66, 74, 21, 211, 47, 80, 242, 154, 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66, 74, 21, 211, 47, 80, 242, 154,
27, 205, 128, 161, 89, 77, 36, 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188, 27, 205, 128, 161, 89, 77, 36, 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188,
@@ -88,7 +88,7 @@ impl Sequences {
} }
pub fn next_state(&mut self, layout: &KeyLayout) { pub fn next_state(&mut self, layout: &KeyLayout) {
for effect in self.0.iter_mut() { for effect in &mut self.0 {
effect.next_state(layout); effect.next_state(layout);
} }
} }
@@ -97,7 +97,7 @@ impl Sequences {
let mut keys = KeyColourArray::new(); let mut keys = KeyColourArray::new();
let mut zones = ZonedColourArray::new(); let mut zones = ZonedColourArray::new();
let mut is_per_key = false; let mut is_per_key = false;
for effect in self.0.iter() { for effect in &self.0 {
match effect.get_led_type() { match effect.get_led_type() {
LedType::Key(key) => { LedType::Key(key) => {
is_per_key = true; is_per_key = true;
+9 -13
View File
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::ops::{BitAnd, BitOr}; use std::ops::{BitAnd, BitOr};
#[cfg(feature = "dbus")] #[cfg(feature = "dbus")]
use zvariant::Type; use zbus::zvariant::Type;
pub const LED_INIT1: [u8; 2] = [0x5d, 0xb9]; pub const LED_INIT1: [u8; 2] = [0x5d, 0xb9];
pub const LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d pub const LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
@@ -36,14 +36,10 @@ impl From<&str> for AuraDevice {
fn from(s: &str) -> Self { fn from(s: &str) -> Self {
match s.to_lowercase().as_str() { match s.to_lowercase().as_str() {
"tuf" => AuraDevice::Tuf, "tuf" => AuraDevice::Tuf,
"1866" => AuraDevice::X1866, "1866" | "0x1866" => AuraDevice::X1866,
"1869" => AuraDevice::X1869, "1869" | "0x1869" => AuraDevice::X1869,
"1854" => AuraDevice::X1854, "1854" | "0x1854" => AuraDevice::X1854,
"19b6" => AuraDevice::X19B6, "19b6" | "0x19b6" => AuraDevice::X19B6,
"0x1866" => AuraDevice::X1866,
"0x1869" => AuraDevice::X1869,
"0x1854" => AuraDevice::X1854,
"0x19b6" => AuraDevice::X19B6,
_ => AuraDevice::Unknown, _ => AuraDevice::Unknown,
} }
} }
@@ -108,9 +104,9 @@ impl From<AuraDev1866> for u32 {
impl AuraDev1866 { impl AuraDev1866 {
pub fn to_bytes(control: &[Self]) -> [u8; 3] { pub fn to_bytes(control: &[Self]) -> [u8; 3] {
let mut a: u32 = 0; let mut a: u32 = 0;
control.iter().for_each(|n| { for n in control {
a |= *n as u32; a |= *n as u32;
}); }
[ [
((a & 0xff0000) >> 16) as u8, ((a & 0xff0000) >> 16) as u8,
((a & 0xff00) >> 8) as u8, ((a & 0xff00) >> 8) as u8,
@@ -197,9 +193,9 @@ impl From<AuraDev19b6> for u32 {
impl AuraDev19b6 { impl AuraDev19b6 {
pub fn to_bytes(control: &[Self]) -> [u8; 3] { pub fn to_bytes(control: &[Self]) -> [u8; 3] {
let mut a: u32 = 0; let mut a: u32 = 0;
control.iter().for_each(|n| { for n in control {
a |= *n as u32; a |= *n as u32;
}); }
[ [
(a & 0xff) as u8, (a & 0xff) as u8,
((a & 0xff00) >> 8) as u8, ((a & 0xff00) >> 8) as u8,
+17 -7
View File
@@ -1,5 +1,6 @@
[package] [package]
name = "rog-control-center" name = "rog-control-center"
license = "MPL-2.0"
version.workspace = true version.workspace = true
authors = ["Luke D. Jones <luke@ljones.dev>"] authors = ["Luke D. Jones <luke@ljones.dev>"]
edition = "2021" edition = "2021"
@@ -8,9 +9,11 @@ edition = "2021"
mocking = [] mocking = []
[dependencies] [dependencies]
egui = { git = "https://github.com/flukejones/egui" } egui = { git = "https://github.com/flukejones/egui", branch = "wayland_dark_theme" }
eframe= { git = "https://github.com/flukejones/egui" } 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
gtk = "0.15.5"
daemon = { path = "../daemon" } daemon = { path = "../daemon" }
rog_anime = { path = "../rog-anime" } rog_anime = { path = "../rog-anime" }
@@ -18,8 +21,11 @@ rog_dbus = { path = "../rog-dbus" }
rog_aura = { path = "../rog-aura" } 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" } supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git", default-features = false }
#supergfxctl = { path = "../../supergfxctl" } #supergfxctl = { path = "../../supergfxctl", default-features = false }
log.workspace = true
env_logger.workspace = true
tokio.workspace = true tokio.workspace = true
serde.workspace = true serde.workspace = true
@@ -30,5 +36,9 @@ zbus.workspace = true
dirs.workspace = true dirs.workspace = true
notify-rust.workspace = true notify-rust.workspace = true
nix = "^0.20.0" png_pong.workspace = true
tempfile = "3.2.0"
nix = "^0.26.1"
tempfile = "3.3.0"
once_cell = "1.10.0"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

+53 -50
View File
@@ -2,7 +2,7 @@ use std::{
f64::consts::PI, f64::consts::PI,
sync::{ sync::{
atomic::{AtomicBool, AtomicU8, Ordering}, atomic::{AtomicBool, AtomicU8, Ordering},
Arc, Arc, Mutex,
}, },
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@@ -11,16 +11,15 @@ use egui::{Button, RichText};
use rog_platform::supported::SupportedFunctions; use rog_platform::supported::SupportedFunctions;
use crate::{ use crate::{
config::Config, error::Result, page_states::PageDataStates, Page, RogDbusClientBlocking, config::Config, error::Result, system_state::SystemState, Page, RogDbusClientBlocking,
}; };
pub struct RogApp<'a> { pub struct RogApp {
pub page: Page, pub page: Page,
pub states: PageDataStates, pub states: Arc<Mutex<SystemState>>,
pub supported: SupportedFunctions, pub supported: SupportedFunctions,
// TODO: can probably just open and read whenever // TODO: can probably just open and read whenever
pub config: Config, pub config: Config,
pub asus_dbus: RogDbusClientBlocking<'a>,
/// Oscillator in percentage /// Oscillator in percentage
pub oscillator1: Arc<AtomicU8>, pub oscillator1: Arc<AtomicU8>,
pub oscillator2: Arc<AtomicU8>, pub oscillator2: Arc<AtomicU8>,
@@ -31,11 +30,11 @@ pub struct RogApp<'a> {
pub oscillator_toggle: Arc<AtomicBool>, pub oscillator_toggle: Arc<AtomicBool>,
} }
impl<'a> RogApp<'a> { impl RogApp {
/// Called once before the first frame. /// Called once before the first frame.
pub fn new( pub fn new(
config: Config, config: Config,
states: PageDataStates, states: Arc<Mutex<SystemState>>,
_cc: &eframe::CreationContext<'_>, _cc: &eframe::CreationContext<'_>,
) -> Result<Self> { ) -> Result<Self> {
let (dbus, _) = RogDbusClientBlocking::new()?; let (dbus, _) = RogDbusClientBlocking::new()?;
@@ -55,6 +54,7 @@ impl<'a> RogApp<'a> {
let oscillator_freq1 = oscillator_freq.clone(); let oscillator_freq1 = oscillator_freq.clone();
let oscillator_toggle = Arc::new(AtomicBool::new(false)); let oscillator_toggle = Arc::new(AtomicBool::new(false));
let oscillator_toggle1 = oscillator_toggle.clone(); let oscillator_toggle1 = oscillator_toggle.clone();
std::thread::spawn(move || { std::thread::spawn(move || {
let started = Instant::now(); let started = Instant::now();
let mut toggled = false; let mut toggled = false;
@@ -83,6 +83,7 @@ impl<'a> RogApp<'a> {
oscillator1_1.store(tmp1, Ordering::SeqCst); oscillator1_1.store(tmp1, Ordering::SeqCst);
oscillator1_2.store(tmp2, Ordering::SeqCst); oscillator1_2.store(tmp2, Ordering::SeqCst);
oscillator1_3.store(tmp3, Ordering::SeqCst); oscillator1_3.store(tmp3, Ordering::SeqCst);
std::thread::sleep(Duration::from_millis(33)); std::thread::sleep(Duration::from_millis(33));
} }
}); });
@@ -92,7 +93,6 @@ impl<'a> RogApp<'a> {
states, states,
page: Page::System, page: Page::System,
config, config,
asus_dbus: dbus,
oscillator1, oscillator1,
oscillator2, oscillator2,
oscillator3, oscillator3,
@@ -102,60 +102,63 @@ impl<'a> RogApp<'a> {
} }
} }
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. /// 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`. /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`.
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
let Self { let states = self.states.clone();
supported,
asus_dbus: dbus, if let Ok(mut states) = states.try_lock() {
states, if states.app_should_update {
.. states.app_should_update = false;
} = self; ctx.request_repaint();
states }
.refresh_if_notfied(supported, dbus) }
.map(|repaint| {
if repaint {
ctx.request_repaint();
}
})
.map_err(|e| self.states.error = Some(e.to_string()))
.ok();
let page = self.page; let page = self.page;
self.top_bar(ctx, frame); self.top_bar(ctx, frame);
self.side_panel(ctx); self.side_panel(ctx);
if let Some(err) = self.states.error.clone() { let mut was_error = false;
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading(RichText::new("Error!").size(28.0));
ui.centered_and_justified(|ui| { if let Ok(mut states) = states.try_lock() {
ui.label(RichText::new(format!("The error was: {:?}", err)).size(22.0)); if let Some(err) = states.error.clone() {
}); was_error = true;
}); egui::CentralPanel::default().show(ctx, |ui| {
egui::TopBottomPanel::bottom("error_bar") ui.heading(RichText::new("Error!").size(28.0));
.default_height(26.0)
.show(ctx, |ui| { ui.centered_and_justified(|ui| {
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| { ui.label(RichText::new(format!("The error was: {:?}", err)).size(22.0));
if ui
.add(Button::new(RichText::new("Okay").size(20.0)))
.clicked()
{
self.states.error = None;
}
}); });
}); });
} else if page == Page::System { egui::TopBottomPanel::bottom("error_bar")
self.system_page(ctx); .default_height(26.0)
} else if page == Page::AuraEffects { .show(ctx, |ui| {
self.aura_page(ctx); ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
// TODO: Anime page is not complete if ui
// } else if page == Page::AnimeMatrix { .add(Button::new(RichText::new("Okay").size(20.0)))
// self.anime_page(ctx); .clicked()
} else if page == Page::FanCurves { {
self.fan_curve_page(ctx); 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);
}
}
} }
} }
} }
+15 -5
View File
@@ -1,22 +1,23 @@
use log::{error, info, warn};
use serde_derive::{Deserialize, Serialize};
use std::{ use std::{
fs::{create_dir, OpenOptions}, fs::{create_dir, OpenOptions},
io::{Read, Write}, io::{Read, Write},
}; };
use serde_derive::{Deserialize, Serialize};
//use log::{error, info, warn}; //use log::{error, info, warn};
use crate::error::Error; 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, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)] #[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 enable_notifications: bool, pub enable_notifications: bool,
pub enabled_notifications: EnabledNotifications,
} }
impl Default for Config { impl Default for Config {
@@ -25,6 +26,7 @@ impl Default for Config {
run_in_background: true, run_in_background: true,
startup_in_background: false, startup_in_background: false,
enable_notifications: true, enable_notifications: true,
enabled_notifications: EnabledNotifications::default(),
} }
} }
} }
@@ -32,14 +34,17 @@ impl Default for Config {
impl Config { impl Config {
pub fn load() -> Result<Config, Error> { pub fn load() -> Result<Config, Error> {
let mut path = if let Some(dir) = dirs::config_dir() { let mut path = if let Some(dir) = dirs::config_dir() {
info!("Found XDG config dir {dir:?}");
dir dir
} else { } else {
error!("Could not get XDG config dir");
return Err(Error::XdgVars); return Err(Error::XdgVars);
}; };
path.push(CFG_DIR); path.push(CFG_DIR);
if !path.exists() { if !path.exists() {
create_dir(path.clone())?; create_dir(path.clone())?;
info!("Created {path:?}");
} }
path.push(CFG_FILE_NAME); path.push(CFG_FILE_NAME);
@@ -54,18 +59,20 @@ impl Config {
if let Ok(read_len) = file.read_to_string(&mut buf) { if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 { if read_len == 0 {
warn!("Zero len read of Config file");
let default = Config::default(); let default = Config::default();
let t = toml::to_string_pretty(&default).unwrap(); let t = toml::to_string_pretty(&default).unwrap();
file.write_all(t.as_bytes())?; file.write_all(t.as_bytes())?;
return Ok(default); return Ok(default);
} 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:?}");
return Ok(data); return Ok(data);
} }
} }
Err(Error::ConfigLoadFail) Err(Error::ConfigLoadFail)
} }
pub fn save(&self) -> Result<(), Error> { pub fn save(&mut self, enabled_notifications: &EnabledNotifications) -> Result<(), Error> {
let mut path = if let Some(dir) = dirs::config_dir() { let mut path = if let Some(dir) = dirs::config_dir() {
dir dir
} else { } else {
@@ -75,6 +82,7 @@ impl Config {
path.push(CFG_DIR); path.push(CFG_DIR);
if !path.exists() { if !path.exists() {
create_dir(path.clone())?; create_dir(path.clone())?;
info!("Created {path:?}");
} }
path.push(CFG_FILE_NAME); path.push(CFG_FILE_NAME);
@@ -85,8 +93,10 @@ impl Config {
.truncate(true) .truncate(true)
.open(&path)?; .open(&path)?;
self.enabled_notifications = enabled_notifications.clone();
let t = toml::to_string_pretty(&self).unwrap(); let t = toml::to_string_pretty(&self).unwrap();
file.write_all(t.as_bytes())?; file.write_all(t.as_bytes())?;
info!("Saved config file {path:?}");
Ok(()) Ok(())
} }
} }
+1 -1
View File
@@ -15,7 +15,7 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
// This trait requires `fmt` with this exact signature. // This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Error::Io(err) => write!(f, "Failed to open: {}", err), Error::Io(err) => write!(f, "Failed to open: {}", err),
Error::Nix(err) => write!(f, "Error: {}", err), Error::Nix(err) => write!(f, "Error: {}", err),
+4 -3
View File
@@ -13,10 +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 page_states;
pub mod pages; pub mod pages;
pub mod startup_error; pub mod startup_error;
pub mod system_state;
pub mod tray;
pub mod update_and_notify;
pub mod widgets; pub mod widgets;
#[cfg(feature = "mocking")] #[cfg(feature = "mocking")]
@@ -96,7 +97,7 @@ pub fn get_ipc_file() -> Result<File, crate::error::Error> {
let tmp_dir = std::env::temp_dir().join("rog-gui"); let tmp_dir = std::env::temp_dir().join("rog-gui");
let fifo_path = tmp_dir.join("ipc.pipe"); let fifo_path = tmp_dir.join("ipc.pipe");
if let Err(e) = unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) { if let Err(e) = unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) {
if !matches!(e, nix::Error::Sys(nix::errno::Errno::EEXIST)) { if !matches!(e, nix::errno::Errno::EEXIST) {
return Err(e)?; return Err(e)?;
} }
} }
+91 -63
View File
@@ -1,28 +1,38 @@
use eframe::NativeOptions; use eframe::{IconData, NativeOptions};
use log::{error, info, LevelFilter};
use rog_aura::layouts::KeyLayout; use rog_aura::layouts::KeyLayout;
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,
page_states::PageDataStates, print_versions, startup_error::AppErrorShow, 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 tokio::runtime::Runtime; use std::sync::Mutex;
use std::{ use std::{
fs::OpenOptions, fs::OpenOptions,
io::{Read, Write}, io::{Read, Write},
path::PathBuf, path::PathBuf,
sync::{atomic::AtomicBool, Arc}, sync::Arc,
}; };
use tokio::runtime::Runtime;
#[cfg(not(feature = "mocking"))] #[cfg(not(feature = "mocking"))]
const DATA_DIR: &str = "/usr/share/rog-gui/"; const DATA_DIR: &str = "/usr/share/rog-gui/";
#[cfg(feature = "mocking")] #[cfg(feature = "mocking")]
const DATA_DIR: &str = env!("CARGO_MANIFEST_DIR"); const DATA_DIR: &str = env!("CARGO_MANIFEST_DIR");
const BOARD_NAME: &str = "/sys/class/dmi/id/board_name"; const BOARD_NAME: &str = "/sys/class/dmi/id/board_name";
const APP_ICON_PATH: &str = "/usr/share/icons/hicolor/512x512/apps/rog-control-center.png";
fn main() -> Result<()> { fn main() -> Result<()> {
print_versions(); print_versions();
let mut logger = env_logger::Builder::new();
logger
.target(env_logger::Target::Stdout)
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
.filter(None, LevelFilter::Info)
.init();
// start tokio // start tokio
let rt = Runtime::new().expect("Unable to create Runtime"); let rt = Runtime::new().expect("Unable to create Runtime");
@@ -36,6 +46,7 @@ fn main() -> Result<()> {
min_window_size: Some(egui::vec2(840.0, 600.0)), min_window_size: Some(egui::vec2(840.0, 600.0)),
max_window_size: Some(egui::vec2(840.0, 600.0)), max_window_size: Some(egui::vec2(840.0, 600.0)),
run_and_return: true, run_and_return: true,
icon_data: Some(load_icon()),
..Default::default() ..Default::default()
}; };
@@ -49,14 +60,28 @@ fn main() -> Result<()> {
}) })
.unwrap(); .unwrap();
let supported = match dbus.proxies().supported().supported_functions() {
Ok(s) => s,
Err(e) => {
eframe::run_native(
"ROG Control Center",
native_options.clone(),
Box::new(move |_| Box::new(AppErrorShow::new(e.to_string()))),
);
SupportedFunctions::default()
}
};
// Startup // Startup
let mut config = Config::load()?; let mut config = Config::load()?;
let mut start_closed = config.startup_in_background; let mut start_closed = config.startup_in_background;
if config.startup_in_background { if config.startup_in_background {
config.run_in_background = true; config.run_in_background = true;
config.save()?; let tmp = config.enabled_notifications.clone(); // ends up being a double clone, oh well.
config.save(&tmp)?;
} }
let enabled_notifications = EnabledNotifications::tokio_mutex(&config);
// Find and load a matching layout for laptop // Find and load a matching layout for laptop
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
@@ -93,16 +118,16 @@ fn main() -> Result<()> {
Err(_) => on_tmp_dir_exists().unwrap(), Err(_) => on_tmp_dir_exists().unwrap(),
}; };
let states = let states = setup_page_state_and_notifs(layout, enabled_notifications, &supported)?;
setup_page_state_and_notifs(layout.clone(), &config, native_options.clone(), &dbus)
.unwrap(); init_tray(supported, states.clone());
loop { loop {
if !start_closed { if !start_closed {
start_app(states.clone(), native_options.clone())?; start_app(states.clone(), native_options.clone())?;
} }
let config = Config::load().unwrap(); let config = Config::load()?;
if !config.run_in_background { if !config.run_in_background {
break; break;
} }
@@ -111,7 +136,7 @@ fn main() -> Result<()> {
let mut buf = [0u8; 4]; let mut buf = [0u8; 4];
// blocks until it is read, typically the read will happen after a second // 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) // 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; start_closed = false;
continue; continue;
} }
@@ -127,59 +152,23 @@ fn main() -> Result<()> {
fn setup_page_state_and_notifs( fn setup_page_state_and_notifs(
keyboard_layout: KeyLayout, keyboard_layout: KeyLayout,
config: &Config, enabled_notifications: Arc<Mutex<EnabledNotifications>>,
native_options: NativeOptions, supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking, ) -> Result<Arc<Mutex<SystemState>>> {
) -> Result<PageDataStates> { let page_states = Arc::new(Mutex::new(SystemState::new(
// 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));
let notifs_enabled = Arc::new(AtomicBool::new(config.enable_notifications));
start_notifications(
charge_notified.clone(),
bios_notified.clone(),
aura_notified.clone(),
anime_notified.clone(),
profiles_notified.clone(),
fans_notified.clone(),
notifs_enabled.clone(),
)?;
let supported = match dbus.proxies().supported().supported_functions() {
Ok(s) => s,
Err(e) => {
eframe::run_native(
"ROG Control Center",
native_options,
Box::new(move |_| Box::new(AppErrorShow::new(e.to_string()))),
);
SupportedFunctions::default()
}
};
PageDataStates::new(
keyboard_layout, keyboard_layout,
notifs_enabled.clone(), enabled_notifications.clone(),
charge_notified.clone(), supported,
bios_notified.clone(), )?));
aura_notified.clone(),
anime_notified.clone(), start_notifications(page_states.clone(), enabled_notifications)?;
profiles_notified.clone(),
fans_notified.clone(), Ok(page_states)
&supported,
&dbus,
)
} }
fn start_app(states: PageDataStates, native_options: NativeOptions) -> Result<()> { fn start_app(states: Arc<Mutex<SystemState>>, native_options: NativeOptions) -> Result<()> {
let mut ipc_file = get_ipc_file().unwrap(); let mut ipc_file = get_ipc_file()?;
ipc_file.write_all(&[SHOWING_GUI]).unwrap(); ipc_file.write_all(&[SHOWING_GUI])?;
eframe::run_native( eframe::run_native(
"ROG Control Center", "ROG Control Center",
native_options, native_options,
@@ -187,3 +176,42 @@ fn start_app(states: PageDataStates, native_options: NativeOptions) -> Result<()
); );
Ok(()) Ok(())
} }
/// Bah.. the icon dosn't work on wayland anyway, but we'll leave it in for now.
fn load_icon() -> IconData {
let path = PathBuf::from(APP_ICON_PATH);
let mut buf = Vec::new();
let mut rgba = Vec::new();
let mut height = 512;
let mut width = 512;
if path.exists() {
if let Ok(mut file) = OpenOptions::new()
.read(true)
.open(path)
.map_err(|e| error!("Error opening app icon: {e:?}"))
{
file.read_to_end(&mut buf)
.map_err(|e| error!("Error reading app icon: {e:?}"))
.ok();
let data = std::io::Cursor::new(buf);
let decoder = png_pong::Decoder::new(data).unwrap().into_steps();
let png_pong::Step { raster, delay: _ } = decoder.last().unwrap().unwrap();
if let png_pong::PngRaster::Rgba8(ras) = raster {
rgba = ras.as_u8_slice().to_vec();
width = ras.width();
height = ras.height();
info!("Loaded app icon. Not actually supported in Wayland yet");
}
}
} else {
error!("Missing {APP_ICON_PATH}");
}
IconData {
height,
width,
rgba,
}
}
-290
View File
@@ -1,290 +0,0 @@
use crate::error::Result;
use notify_rust::{Hint, Notification, NotificationHandle};
use rog_dbus::{
zbus_anime::AnimeProxy, zbus_led::LedProxy, zbus_platform::RogBiosProxy,
zbus_power::PowerProxy, zbus_profile::ProfileProxy,
};
use rog_platform::platform::GpuMode;
use rog_profiles::Profile;
use std::{
fmt::Display,
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
},
};
use supergfxctl::pci_device::GfxPower;
use zbus::export::futures_util::{future, StreamExt};
const NOTIF_HEADER: &str = "ROG Control";
macro_rules! notify {
($notifier:expr, $last_notif:ident) => {
if let Some(notif) = $last_notif.take() {
notif.close();
}
if let Ok(x) = $notifier {
$last_notif.replace(x);
}
};
}
macro_rules! recv_notif {
($proxy:ident,
$signal:ident,
$was_notified:ident,
$last_notif:ident,
$notif_enabled:ident,
[$($out_arg:ident)+],
$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...
tokio::spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = $proxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.$signal().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if notifs_enabled1.load(Ordering::SeqCst) {
if let Ok(ref mut lock) = last_notif.try_lock() {
notify!($notifier($msg, &out$(.$out_arg)+()), lock);
}
}
notified.store(true, Ordering::SeqCst);
}
future::ready(())
})
.await;
};
});
};
}
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>,
notifs_enabled: Arc<AtomicBool>,
) -> Result<()> {
let last_notification: SharedHandle = Arc::new(Mutex::new(None));
// BIOS notif
recv_notif!(
RogBiosProxy,
receive_notify_post_boot_sound,
bios_notified,
last_notification,
notifs_enabled,
[on],
"BIOS Post sound",
do_notification
);
recv_notif!(
RogBiosProxy,
receive_notify_panel_od,
bios_notified,
last_notification,
notifs_enabled,
[overdrive],
"Panel Overdrive enabled:",
do_notification
);
recv_notif!(
RogBiosProxy,
receive_notify_dgpu_disable,
bios_notified,
last_notification,
notifs_enabled,
[disable],
"BIOS dGPU disabled",
do_notification
);
recv_notif!(
RogBiosProxy,
receive_notify_egpu_enable,
bios_notified,
last_notification,
notifs_enabled,
[enable],
"BIOS eGPU enabled",
do_notification
);
recv_notif!(
RogBiosProxy,
receive_notify_gpu_mux_mode,
bios_notified,
last_notification,
notifs_enabled,
[mode],
"BIOS GPU MUX mode (reboot required)",
mux_notification
);
// Charge notif
recv_notif!(
PowerProxy,
receive_notify_charge_control_end_threshold,
charge_notified,
last_notification,
notifs_enabled,
[limit],
"Battery charge limit changed to",
do_notification
);
recv_notif!(
PowerProxy,
receive_notify_mains_online,
bios_notified,
last_notification,
notifs_enabled,
[on],
"AC Power power is",
ac_power_notification
);
// Profile notif
recv_notif!(
ProfileProxy,
receive_notify_profile,
profiles_notified,
last_notification,
notifs_enabled,
[profile],
"Profile changed to",
do_thermal_notif
);
// notify!(do_thermal_notif(&out.profile), lock);
// LED notif
recv_notif!(
LedProxy,
receive_notify_led,
aura_notified,
last_notification,
notifs_enabled,
[data mode_name],
"Keyboard LED mode changed to",
do_notification
);
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(())
})
.await;
};
});
tokio::spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = AnimeProxy::new(&conn).await.unwrap();
if let Ok(p) = proxy.receive_power_states().await {
p.for_each(|_| {
anime_notified.store(true, Ordering::SeqCst);
future::ready(())
})
.await;
};
});
let notifs_enabled1 = notifs_enabled.clone();
let last_notif = last_notification.clone();
let bios_notified1 = bios_notified.clone();
tokio::spawn(async move {
let conn = zbus::Connection::system().await.unwrap();
let proxy = supergfxctl::zbus_proxy::DaemonProxy::new(&conn)
.await
.unwrap();
if let Ok(p) = proxy.receive_notify_gfx_status().await {
p.for_each(|e| {
if let Ok(out) = e.args() {
if notifs_enabled1.load(Ordering::SeqCst) {
let status = out.status();
if *status != GfxPower::Unknown {
// Required check because status cycles through active/unknown/suspended
if let Ok(ref mut lock) = last_notif.try_lock() {
notify!(
do_notification(
"dGPU status changed:",
&format!("{status:?}",)
),
lock
);
}
}
}
}
bios_notified1.store(true, Ordering::SeqCst);
future::ready(())
})
.await;
};
});
Ok(())
}
fn base_notification<T>(message: &str, data: &T) -> Notification
where
T: Display,
{
let mut notif = Notification::new();
notif
.summary(NOTIF_HEADER)
.body(&format!("{message} {data}"))
.timeout(2000)
//.hint(Hint::Resident(true))
.hint(Hint::Category("device".into()));
notif
}
fn do_notification<T>(message: &str, data: &T) -> Result<NotificationHandle>
where
T: Display,
{
Ok(base_notification(message, data).show()?)
}
fn ac_power_notification(message: &str, on: &bool) -> Result<NotificationHandle> {
let data = if *on {
"plugged".to_string()
} else {
"unplugged".to_string()
};
Ok(base_notification(message, &data).show()?)
}
/// Actual GpuMode unused as data is never correct until switched by reboot
fn mux_notification(message: &str, _: &GpuMode) -> Result<NotificationHandle> {
Ok(base_notification(message, &"").show()?)
}
fn do_thermal_notif(message: &str, profile: &Profile) -> Result<NotificationHandle> {
let icon = match profile {
Profile::Balanced => "asus_notif_yellow",
Profile::Performance => "asus_notif_red",
Profile::Quiet => "asus_notif_green",
};
let profile: &str = (*profile).into();
let mut notif = base_notification(message, &profile.to_uppercase());
Ok(notif.icon(icon).show()?)
}
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::RogApp; use crate::RogApp;
impl<'a> RogApp<'a> { impl RogApp {
pub fn anime_page(&mut self, ctx: &egui::Context) { pub fn anime_page(&mut self, ctx: &egui::Context) {
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
ui.label("In progress"); ui.label("In progress");
+4 -6
View File
@@ -4,16 +4,15 @@ use egui::Color32;
use rog_aura::{AuraEffect, AuraModeNum}; use rog_aura::{AuraEffect, AuraModeNum};
use crate::{ use crate::{
system_state::SystemState,
widgets::{aura_modes_group, keyboard}, widgets::{aura_modes_group, keyboard},
RogApp, RogApp,
}; };
impl<'a> RogApp<'a> { impl RogApp {
pub fn aura_page(&mut self, ctx: &egui::Context) { pub fn aura_page(&mut self, states: &mut SystemState, ctx: &egui::Context) {
let Self { let Self {
supported, supported,
states,
asus_dbus: dbus,
oscillator1, oscillator1,
oscillator2, oscillator2,
oscillator3, oscillator3,
@@ -26,7 +25,6 @@ impl<'a> RogApp<'a> {
let blue = oscillator3.load(Ordering::SeqCst) as u32; let blue = oscillator3.load(Ordering::SeqCst) as u32;
states.aura.nudge_wave(red as u8, green as u8, blue as u8); states.aura.nudge_wave(red as u8, green as u8, blue as u8);
// let osc = c.0 * 255 / osc; // let osc = c.0 * 255 / osc;
// dbg!(osc);
let c1 = states let c1 = states
.aura .aura
.modes .modes
@@ -72,7 +70,7 @@ impl<'a> RogApp<'a> {
// TODO: animation of colour changes/periods/blending // TODO: animation of colour changes/periods/blending
egui::CentralPanel::default().show(ctx, |ui| { 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); keyboard(ui, &states.keyboard_layout, &mut states.aura, colour);
}); });
+9 -15
View File
@@ -1,5 +1,5 @@
use crate::{ use crate::{
page_states::{FanCurvesState, ProfilesState}, system_state::{FanCurvesState, ProfilesState, SystemState},
widgets::fan_graphs, widgets::fan_graphs,
RogApp, RogDbusClientBlocking, RogApp, RogDbusClientBlocking,
}; };
@@ -7,14 +7,9 @@ use egui::Ui;
use rog_platform::supported::SupportedFunctions; use rog_platform::supported::SupportedFunctions;
use rog_profiles::Profile; use rog_profiles::Profile;
impl<'a> RogApp<'a> { impl RogApp {
pub fn fan_curve_page(&mut self, ctx: &egui::Context) { pub fn fan_curve_page(&mut self, states: &mut SystemState, ctx: &egui::Context) {
let Self { let Self { supported, .. } = self;
supported,
states,
asus_dbus: dbus,
..
} = self;
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Custom fan curves"); ui.heading("Custom fan curves");
@@ -23,11 +18,11 @@ impl<'a> RogApp<'a> {
supported, supported,
&mut states.profiles, &mut states.profiles,
&mut states.fan_curves, &mut states.fan_curves,
dbus, &mut states.error, &states.asus_dbus, &mut states.error,
ui, ui,
); );
fan_graphs(supported, &mut states.profiles, &mut states.fan_curves, dbus, &mut states.error, ui); fan_graphs(supported, &mut states.fan_curves, &states.asus_dbus, &mut states.error, ui);
}); });
} }
@@ -35,7 +30,7 @@ impl<'a> RogApp<'a> {
supported: &SupportedFunctions, supported: &SupportedFunctions,
profiles: &mut ProfilesState, profiles: &mut ProfilesState,
curves: &mut FanCurvesState, curves: &mut FanCurvesState,
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
do_error: &mut Option<String>, do_error: &mut Option<String>,
ui: &mut Ui, ui: &mut Ui,
) { ) {
@@ -67,7 +62,7 @@ impl<'a> RogApp<'a> {
}; };
profiles.list.sort(); profiles.list.sort();
for f in profiles.list.iter() { for f in &profiles.list {
item(*f, curves, curves.enabled.contains(f)); item(*f, curves, curves.enabled.contains(f));
} }
}); });
@@ -76,8 +71,7 @@ impl<'a> RogApp<'a> {
let selected_profile = curves.show_curve; let selected_profile = curves.show_curve;
let selected_pu = curves.show_graph; let selected_pu = curves.show_graph;
let notif = curves.was_notified.clone(); match FanCurvesState::new(supported, dbus) {
match FanCurvesState::new(notif, supported, dbus) {
Ok(f) => *curves = f, Ok(f) => *curves = f,
Err(e) => *do_error = Some(e.to_string()), Err(e) => *do_error = Some(e.to_string()),
} }
+11 -16
View File
@@ -1,18 +1,15 @@
use crate::{ use crate::{
system_state::SystemState,
widgets::{ widgets::{
anime_power_group, app_settings, aura_power_group, platform_profile, rog_bios_group, anime_power_group, app_settings, aura_power_group, platform_profile, rog_bios_group,
}, },
RogApp, RogApp,
}; };
impl<'a> RogApp<'a> { impl RogApp {
pub fn system_page(&mut self, ctx: &egui::Context) { pub fn system_page(&mut self, states: &mut SystemState, ctx: &egui::Context) {
let Self { let Self {
config, config, supported, ..
supported,
states,
asus_dbus: dbus,
..
} = self; } = self;
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
@@ -27,26 +24,24 @@ impl<'a> RogApp<'a> {
/******************************************************/ /******************************************************/
ui.vertical(|ui| { ui.vertical(|ui| {
ui.separator(); ui.separator();
app_settings(config, states, ui); if supported.platform_profile.platform_profile {
platform_profile(states, ui);
}
}); });
ui.vertical(|ui| { ui.vertical(|ui| {
ui.separator(); ui.separator();
if supported.platform_profile.platform_profile { aura_power_group(supported, states, ui);
platform_profile(states, dbus, ui);
}
}); });
ui.end_row(); ui.end_row();
/******************************************************/ /******************************************************/
ui.vertical(|ui| { ui.vertical(|ui| {
ui.separator(); ui.separator();
aura_power_group(supported, states, dbus, ui); app_settings(config, states, ui);
}); });
ui.vertical(|ui| { ui.vertical(|ui| {
ui.separator(); ui.separator();
rog_bios_group(supported, states, dbus, ui); rog_bios_group(supported, states, ui);
}); });
ui.end_row(); ui.end_row();
@@ -54,7 +49,7 @@ impl<'a> RogApp<'a> {
ui.vertical(|ui| { ui.vertical(|ui| {
ui.separator(); ui.separator();
if supported.anime_ctrl.0 { if supported.anime_ctrl.0 {
anime_power_group(supported, states, dbus, ui); anime_power_group(supported, states, ui);
} }
}); });
ui.vertical(|ui| { ui.vertical(|ui| {
@@ -1,24 +1,25 @@
use std::{ use std::{
collections::{BTreeMap, HashSet}, collections::{BTreeMap, HashSet},
sync::{ sync::{Arc, Mutex},
atomic::{AtomicBool, Ordering},
Arc,
},
}; };
use egui::Vec2; use egui::Vec2;
use rog_aura::{layouts::KeyLayout, usb::AuraPowerDev, AuraEffect, AuraModeNum}; use rog_aura::{layouts::KeyLayout, usb::AuraPowerDev, AuraEffect, AuraModeNum};
use rog_platform::{platform::GpuMode, supported::SupportedFunctions}; use rog_platform::{platform::GpuMode, supported::SupportedFunctions};
use rog_profiles::{fan_curve_set::FanCurveSet, FanCurvePU, Profile}; use rog_profiles::{fan_curve_set::FanCurveSet, FanCurvePU, Profile};
use supergfxctl::{
pci_device::{GfxMode, GfxPower},
zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking,
};
use crate::{error::Result, RogDbusClientBlocking}; use crate::{error::Result, update_and_notify::EnabledNotifications, RogDbusClientBlocking};
use log::error;
#[derive(Clone, Debug)] #[derive(Clone, Debug, Default)]
pub struct BiosState { pub struct BiosState {
/// To be shared to a thread that checks notifications. /// To be shared to a thread that checks notifications.
/// It's a bit general in that it won't provide *what* was /// It's a bit general in that it won't provide *what* was
/// updated, so the full state needs refresh /// updated, so the full state needs refresh
pub was_notified: Arc<AtomicBool>,
pub post_sound: bool, pub post_sound: bool,
pub dedicated_gfx: GpuMode, pub dedicated_gfx: GpuMode,
pub panel_overdrive: bool, pub panel_overdrive: bool,
@@ -27,13 +28,8 @@ pub struct BiosState {
} }
impl BiosState { impl BiosState {
pub fn new( pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking<'_>) -> Result<Self> {
was_notified: Arc<AtomicBool>,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> {
Ok(Self { Ok(Self {
was_notified,
post_sound: if supported.rog_bios_ctrl.post_sound { post_sound: if supported.rog_bios_ctrl.post_sound {
dbus.proxies().rog_bios().post_boot_sound()? != 0 dbus.proxies().rog_bios().post_boot_sound()? != 0
} else { } else {
@@ -56,21 +52,15 @@ impl BiosState {
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, Default)]
pub struct ProfilesState { pub struct ProfilesState {
pub was_notified: Arc<AtomicBool>,
pub list: Vec<Profile>, pub list: Vec<Profile>,
pub current: Profile, pub current: Profile,
} }
impl ProfilesState { impl ProfilesState {
pub fn new( pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking<'_>) -> Result<Self> {
was_notified: Arc<AtomicBool>,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> {
Ok(Self { Ok(Self {
was_notified,
list: if supported.platform_profile.platform_profile { list: if supported.platform_profile.platform_profile {
let mut list = dbus.proxies().profile().profiles()?; let mut list = dbus.proxies().profile().profiles()?;
list.sort(); list.sort();
@@ -87,9 +77,8 @@ impl ProfilesState {
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, Default)]
pub struct FanCurvesState { pub struct FanCurvesState {
pub was_notified: Arc<AtomicBool>,
pub show_curve: Profile, pub show_curve: Profile,
pub show_graph: FanCurvePU, pub show_graph: FanCurvePU,
pub enabled: HashSet<Profile>, pub enabled: HashSet<Profile>,
@@ -98,30 +87,25 @@ pub struct FanCurvesState {
} }
impl FanCurvesState { impl FanCurvesState {
pub fn new( pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking<'_>) -> Result<Self> {
was_notified: Arc<AtomicBool>,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> {
let profiles = if supported.platform_profile.platform_profile { let profiles = if supported.platform_profile.platform_profile {
dbus.proxies().profile().profiles()? dbus.proxies().profile().profiles()?
} else { } else {
vec![Profile::Balanced, Profile::Quiet, Profile::Performance] vec![Profile::Balanced, Profile::Quiet, Profile::Performance]
}; };
let enabled = if supported.platform_profile.fan_curves { let enabled = if supported.platform_profile.fan_curves {
HashSet::from_iter( dbus.proxies()
dbus.proxies() .profile()
.profile() .enabled_fan_profiles()?
.enabled_fan_profiles()? .iter()
.iter() .cloned()
.cloned(), .collect::<HashSet<_>>()
)
} else { } else {
HashSet::from([Profile::Balanced, Profile::Quiet, Profile::Performance]) HashSet::from([Profile::Balanced, Profile::Quiet, Profile::Performance])
}; };
let mut curves: BTreeMap<Profile, FanCurveSet> = BTreeMap::new(); let mut curves: BTreeMap<Profile, FanCurveSet> = BTreeMap::new();
profiles.iter().for_each(|p| { for p in &profiles {
if supported.platform_profile.fan_curves { if supported.platform_profile.fan_curves {
if let Ok(curve) = dbus.proxies().profile().fan_curve_data(*p) { if let Ok(curve) = dbus.proxies().profile().fan_curve_data(*p) {
curves.insert(*p, curve); curves.insert(*p, curve);
@@ -134,7 +118,7 @@ impl FanCurvesState {
curve.gpu.temp = [20, 30, 40, 50, 70, 80, 90, 100]; curve.gpu.temp = [20, 30, 40, 50, 70, 80, 90, 100];
curves.insert(*p, curve); curves.insert(*p, curve);
} }
}); }
let show_curve = if supported.platform_profile.fan_curves { let show_curve = if supported.platform_profile.fan_curves {
dbus.proxies().profile().active_profile()? dbus.proxies().profile().active_profile()?
@@ -143,7 +127,6 @@ impl FanCurvesState {
}; };
Ok(Self { Ok(Self {
was_notified,
show_curve, show_curve,
show_graph: FanCurvePU::CPU, show_graph: FanCurvePU::CPU,
enabled, enabled,
@@ -153,9 +136,8 @@ impl FanCurvesState {
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, Default)]
pub struct AuraState { pub struct AuraState {
pub was_notified: Arc<AtomicBool>,
pub current_mode: AuraModeNum, pub current_mode: AuraModeNum,
pub modes: BTreeMap<AuraModeNum, AuraEffect>, pub modes: BTreeMap<AuraModeNum, AuraEffect>,
pub enabled: AuraPowerDev, pub enabled: AuraPowerDev,
@@ -167,13 +149,8 @@ pub struct AuraState {
} }
impl AuraState { impl AuraState {
pub fn new( pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking<'_>) -> Result<Self> {
was_notified: Arc<AtomicBool>,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> {
Ok(Self { Ok(Self {
was_notified,
current_mode: if !supported.keyboard_led.stock_led_modes.is_empty() { current_mode: if !supported.keyboard_led.stock_led_modes.is_empty() {
dbus.proxies().led().led_mode().unwrap_or_default() dbus.proxies().led().led_mode().unwrap_or_default()
} else { } else {
@@ -212,9 +189,8 @@ impl AuraState {
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, Default)]
pub struct AnimeState { pub struct AnimeState {
pub was_notified: Arc<AtomicBool>,
pub bright: u8, pub bright: u8,
pub boot: bool, pub boot: bool,
pub awake: bool, pub awake: bool,
@@ -222,13 +198,8 @@ pub struct AnimeState {
} }
impl AnimeState { impl AnimeState {
pub fn new( pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking<'_>) -> Result<Self> {
was_notified: Arc<AtomicBool>,
supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> {
Ok(Self { Ok(Self {
was_notified,
boot: if supported.anime_ctrl.0 { boot: if supported.anime_ctrl.0 {
dbus.proxies().anime().boot_enabled()? dbus.proxies().anime().boot_enabled()?
} else { } else {
@@ -246,11 +217,53 @@ impl AnimeState {
} }
} }
#[derive(Debug, Clone)] #[derive(Clone, Debug)]
pub struct PageDataStates { pub struct GfxState {
pub has_supergfx: bool,
pub mode: GfxMode,
pub power_status: GfxPower,
}
impl GfxState {
pub fn new(_supported: &SupportedFunctions, dbus: &GfxProxyBlocking<'_>) -> Result<Self> {
Ok(Self {
has_supergfx: dbus.mode().is_ok(),
mode: dbus.mode().unwrap_or(GfxMode::None),
power_status: dbus.power().unwrap_or(GfxPower::Unknown),
})
}
}
impl Default for GfxState {
fn default() -> Self {
Self {
has_supergfx: false,
mode: GfxMode::None,
power_status: GfxPower::Unknown,
}
}
}
#[derive(Clone, Debug, Default)]
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 keyboard_layout: KeyLayout,
pub notifs_enabled: Arc<AtomicBool>, pub enabled_notifications: Arc<Mutex<EnabledNotifications>>,
pub was_notified: Arc<AtomicBool>,
/// Because much of the app state here is the same as `RogBiosSupportedFunctions` /// Because much of the app state here is the same as `RogBiosSupportedFunctions`
/// we can re-use that structure. /// we can re-use that structure.
pub bios: BiosState, pub bios: BiosState,
@@ -258,87 +271,102 @@ pub struct PageDataStates {
pub anime: AnimeState, pub anime: AnimeState,
pub profiles: ProfilesState, pub profiles: ProfilesState,
pub fan_curves: FanCurvesState, pub fan_curves: FanCurvesState,
pub charge_limit: u8, pub gfx_state: GfxState,
pub power_state: PowerState,
pub error: Option<String>, 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 SystemState {
impl PageDataStates { /// Creates self, including the relevant dbus connections and proixies for internal use
pub fn new( pub fn new(
keyboard_layout: KeyLayout, keyboard_layout: KeyLayout,
notifs_enabled: Arc<AtomicBool>, 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, supported: &SupportedFunctions,
dbus: &RogDbusClientBlocking,
) -> Result<Self> { ) -> Result<Self> {
let (asus_dbus, conn) = RogDbusClientBlocking::new()?;
let mut error = None;
let gfx_dbus = GfxProxyBlocking::new(&conn).expect("Couldn't connect to supergfxd");
Ok(Self { Ok(Self {
keyboard_layout, keyboard_layout,
notifs_enabled, enabled_notifications,
was_notified: charge_notified, power_state: PowerState::new(supported, &asus_dbus)
charge_limit: dbus.proxies().charge().charge_control_end_threshold()?, .map_err(|e| {
bios: BiosState::new(bios_notified, supported, dbus)?, let e = format!("Could not get PowerState state: {e}");
aura: AuraState::new(aura_notified, supported, dbus)?, error!("{e}");
anime: AnimeState::new(anime_notified, supported, dbus)?, error = Some(e);
profiles: ProfilesState::new(profiles_notified, supported, dbus)?, })
fan_curves: FanCurvesState::new(fans_notified, supported, dbus)?, .unwrap_or_default(),
error: None, bios: BiosState::new(supported, &asus_dbus)
.map_err(|e| {
let e = format!("Could not get BiosState state: {e}");
error!("{e}");
error = Some(e);
})
.unwrap_or_default(),
aura: AuraState::new(supported, &asus_dbus)
.map_err(|e| {
let e = format!("Could not get AuraState state: {e}");
error!("{e}");
error = Some(e);
})
.unwrap_or_default(),
anime: AnimeState::new(supported, &asus_dbus)
.map_err(|e| {
let e = format!("Could not get AanimeState state: {e}");
error!("{e}");
error = Some(e);
})
.unwrap_or_default(),
profiles: ProfilesState::new(supported, &asus_dbus)
.map_err(|e| {
let e = format!("Could not get ProfilesState state: {e}");
error!("{e}");
error = Some(e);
})
.unwrap_or_default(),
fan_curves: FanCurvesState::new(supported, &asus_dbus)
.map_err(|e| {
let e = format!("Could not get FanCurvesState state: {e}");
error!("{e}");
error = Some(e);
})
.unwrap_or_default(),
gfx_state: GfxState::new(supported, &gfx_dbus)
.map_err(|e| {
let e = format!("Could not get supergfxd state: {e}");
error!("{e}");
error = Some(e);
})
.unwrap_or_default(),
error,
tray_should_update: true,
app_should_update: true,
asus_dbus,
gfx_dbus,
}) })
} }
pub fn refresh_if_notfied( pub fn set_notified(&mut self) {
&mut self, self.tray_should_update = true;
supported: &SupportedFunctions, self.app_should_update = true;
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)
} }
} }
impl Default for PageDataStates { impl Default for SystemState {
fn default() -> Self { fn default() -> Self {
let (asus_dbus, conn) = RogDbusClientBlocking::new().expect("Couldn't connect to asusd");
let gfx_dbus = GfxProxyBlocking::new(&conn).expect("Couldn't connect to supergfxd");
Self { Self {
keyboard_layout: KeyLayout::ga401_layout(), keyboard_layout: KeyLayout::ga401_layout(),
notifs_enabled: Default::default(), enabled_notifications: Default::default(),
was_notified: Default::default(),
bios: BiosState { bios: BiosState {
was_notified: Default::default(),
post_sound: Default::default(), post_sound: Default::default(),
dedicated_gfx: GpuMode::NotSupported, dedicated_gfx: GpuMode::NotSupported,
panel_overdrive: Default::default(), panel_overdrive: Default::default(),
@@ -346,7 +374,6 @@ impl Default for PageDataStates {
egpu_enable: Default::default(), egpu_enable: Default::default(),
}, },
aura: AuraState { aura: AuraState {
was_notified: Default::default(),
current_mode: AuraModeNum::Static, current_mode: AuraModeNum::Static,
modes: Default::default(), modes: Default::default(),
enabled: AuraPowerDev { enabled: AuraPowerDev {
@@ -360,27 +387,36 @@ impl Default for PageDataStates {
wave_blue: Default::default(), wave_blue: Default::default(),
}, },
anime: AnimeState { anime: AnimeState {
was_notified: Default::default(),
bright: Default::default(), bright: Default::default(),
boot: Default::default(), boot: Default::default(),
awake: Default::default(), awake: Default::default(),
sleep: Default::default(), sleep: Default::default(),
}, },
profiles: ProfilesState { profiles: ProfilesState {
was_notified: Default::default(),
list: Default::default(), list: Default::default(),
current: Default::default(), current: Default::default(),
}, },
fan_curves: FanCurvesState { fan_curves: FanCurvesState {
was_notified: Default::default(),
show_curve: Default::default(), show_curve: Default::default(),
show_graph: Default::default(), show_graph: Default::default(),
enabled: Default::default(), enabled: Default::default(),
curves: Default::default(), curves: Default::default(),
drag_delta: Default::default(), drag_delta: Default::default(),
}, },
charge_limit: Default::default(), gfx_state: GfxState {
has_supergfx: false,
mode: GfxMode::None,
power_status: GfxPower::Unknown,
},
power_state: PowerState {
charge_limit: 99,
ac_power: false,
},
error: Default::default(), error: Default::default(),
tray_should_update: true,
app_should_update: true,
asus_dbus,
gfx_dbus,
} }
} }
} }
+455
View File
@@ -0,0 +1,455 @@
//! A seld-contained tray icon with menus. The control of app<->tray is done via
//! commands over an MPSC channel.
use std::{
io::Write,
sync::{
mpsc::{channel, Receiver},
Arc, Mutex,
},
time::Duration,
};
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, system_state::SystemState, SHOW_GUI};
use libappindicator::{AppIndicator, AppIndicatorStatus};
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";
pub enum AppToTray {
DgpuStatus(GfxPower),
}
pub enum TrayToApp {
Open,
Quit,
}
pub struct RadioGroup(Vec<gtk::RadioMenuItem>);
impl RadioGroup {
/// Add new radio menu item. `set_no_show_all()` is true until added to menu
/// to prevent teh callback from running
pub fn new<F>(first_label: &str, cb: F) -> Self
where
F: Fn(&gtk::RadioMenuItem) + Send + 'static,
{
let item = gtk::RadioMenuItem::with_label(first_label);
item.set_active(false);
item.set_no_show_all(true);
item.connect_activate(move |this| {
if this.is_active() && !this.is_no_show_all() {
cb(this);
}
});
Self(vec![item])
}
/// Add new radio menu item. `set_no_show_all()` is true until added to menu
/// to prevent teh callback from running
pub fn add<F>(&mut self, label: &str, cb: F)
where
F: Fn(&gtk::RadioMenuItem) + Send + 'static,
{
debug_assert!(!self.0.is_empty());
let group = self.0[0].group();
let item = gtk::RadioMenuItem::with_label_from_widget(&group[0], Some(label));
item.set_active(false);
item.set_no_show_all(true);
item.connect_activate(move |this| {
if this.is_active() && !this.is_no_show_all() {
cb(this);
}
});
self.0.push(item);
}
}
pub struct ROGTray {
tray: AppIndicator,
menu: gtk::Menu,
icon: &'static str,
bios_proxy: RogBiosProxyBlocking<'static>,
gfx_proxy: GfxProxyBlocking<'static>,
}
impl ROGTray {
pub fn new() -> Result<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(),
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
})?,
};
Ok(rog_tray)
}
pub fn set_icon(&mut self, icon: &'static str) {
self.icon = icon;
self.tray.set_icon(self.icon);
self.tray.set_status(AppIndicatorStatus::Active);
}
/// Add a non-interactive label
fn add_inactive_label(&mut self, label: &str) {
let item = gtk::MenuItem::with_label(label);
item.set_sensitive(false);
self.menu.append(&item);
self.menu.show_all();
}
/// 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,
) {
let header_item = gtk::MenuItem::with_label(header_label);
header_item.show_all();
self.menu.add(&header_item);
let menu = gtk::Menu::new();
for item in &sub_menu.0 {
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);
}
menu.show_all();
header_item.set_submenu(Some(&menu));
}
fn _add_menu_item<F>(&mut self, label: &str, cb: F)
where
F: Fn() + Send + 'static,
{
let item = gtk::MenuItem::with_label(label);
item.connect_activate(move |_| {
cb();
});
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();
}
/// Add a menu item with an icon to the right
fn add_icon_menu_item<F>(&mut self, label: &str, icon: &str, cb: F)
where
F: Fn() + Send + 'static,
{
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 item = gtk::MenuItem::new();
g_box.add(&icon);
g_box.add(&label);
item.add(&g_box);
item.show_all();
item.connect_activate(move |_| {
cb();
});
self.menu.append(&item);
self.menu.show_all();
self.tray.set_menu(&mut self.menu);
}
fn _set_status(&mut self, status: AppIndicatorStatus) {
self.tray.set_status(status);
}
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");
}
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_owned(),
_ => 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,
has_supergfx: bool,
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);
if has_supergfx {
self.menu_add_gpu(supported, current_gfx_mode);
}
self.menu_update();
}
}
pub fn init_tray(
supported: SupportedFunctions,
states: Arc<Mutex<SystemState>>,
) -> Receiver<TrayToApp> {
let (send, recv) = channel();
let _send = Arc::new(Mutex::new(send));
let has_supergfx = if let Ok(lock) = states.try_lock() {
lock.gfx_state.has_supergfx
} else {
false
};
std::thread::spawn(move || {
if gtk::init()
.map_err(|e| {
error!("ROGTray: gtk init {e}");
e
})
.is_err()
{
return;
} // Make this the main thread for gtk
debug!("init_tray gtk");
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, has_supergfx, GfxMode::Hybrid, 100, false);
tray.set_icon(TRAY_APP_ICON);
info!("Started ROGTray");
loop {
if let Ok(mut lock) = states.lock() {
if lock.tray_should_update {
tray.rebuild_and_update(
&supported,
has_supergfx,
lock.gfx_state.mode,
lock.power_state.charge_limit,
lock.bios.panel_overdrive,
);
lock.tray_should_update = false;
debug!("ROGTray: rebuilt menus due to state change");
match lock.gfx_state.power_status {
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 | GfxPower::Active => {
tray.set_icon("asus_notif_red");
}
GfxPower::Unknown => {
if has_supergfx {
tray.set_icon("gpu-integrated");
} else {
tray.set_icon("asus_notif_red");
}
}
};
}
}
if gtk::events_pending() {
// This is blocking until any events are available
gtk::main_iteration();
continue;
}
// Don't spool at max speed if no gtk events
std::thread::sleep(Duration::from_millis(300));
trace!("Tray loop ticked");
}
});
recv
}
+465
View File
@@ -0,0 +1,465 @@
//! `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 log::{error, info, trace, warn};
use notify_rust::{Hint, Notification, NotificationHandle, Urgency};
use rog_dbus::{
zbus_anime::AnimeProxy, zbus_led::LedProxy, zbus_platform::RogBiosProxy,
zbus_power::PowerProxy, zbus_profile::ProfileProxy,
};
use rog_platform::platform::GpuMode;
use rog_profiles::Profile;
use serde::{Deserialize, Serialize};
use std::{
fmt::Display,
process::Command,
sync::{Arc, Mutex},
time::Duration,
};
use supergfxctl::{pci_device::GfxPower, zbus_proxy::DaemonProxy as SuperProxy};
use tokio::time::sleep;
use zbus::export::futures_util::{future, StreamExt};
const NOTIF_HEADER: &str = "ROG Control";
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct EnabledNotifications {
pub receive_notify_post_boot_sound: bool,
pub receive_notify_panel_od: bool,
pub receive_notify_dgpu_disable: bool,
pub receive_notify_egpu_enable: bool,
pub receive_notify_gpu_mux_mode: bool,
pub receive_notify_charge_control_end_threshold: bool,
pub receive_notify_mains_online: bool,
pub receive_notify_profile: bool,
pub receive_notify_led: bool,
/// Anime
pub receive_power_states: bool,
pub receive_notify_gfx: bool,
pub receive_notify_gfx_status: bool,
pub all_enabled: bool,
}
impl Default for EnabledNotifications {
fn default() -> Self {
Self {
receive_notify_post_boot_sound: false,
receive_notify_panel_od: true,
receive_notify_dgpu_disable: true,
receive_notify_egpu_enable: true,
receive_notify_gpu_mux_mode: true,
receive_notify_charge_control_end_threshold: true,
receive_notify_mains_online: false,
receive_notify_profile: true,
receive_notify_led: false,
receive_power_states: false,
receive_notify_gfx: false,
receive_notify_gfx_status: false,
all_enabled: false,
}
}
}
impl EnabledNotifications {
pub fn tokio_mutex(config: &Config) -> Arc<Mutex<Self>> {
Arc::new(Mutex::new(config.enabled_notifications.clone()))
}
}
macro_rules! notify {
($notifier:expr, $last_notif:ident) => {
if let Some(notif) = $last_notif.take() {
notif.close();
}
if let Ok(x) = $notifier {
$last_notif.replace(x);
}
};
}
// TODO: drop the macro and use generics plus closure
macro_rules! recv_notif {
($proxy:ident,
$signal:ident,
$last_notif:ident,
$notif_enabled:ident,
$page_states:ident,
($($args: tt)*),
($($out_arg:tt)+),
$msg:literal,
$notifier:ident) => {
let last_notif = $last_notif.clone();
let notifs_enabled1 = $notif_enabled.clone();
let page_states1 = $page_states.clone();
tokio::spawn(async move {
let conn = zbus::Connection::system().await.map_err(|e| {
log::error!("zbus signal: {}: {e}", stringify!($signal));
e
}).unwrap();
let proxy = $proxy::new(&conn).await.map_err(|e| {
log::error!("zbus signal: {}: {e}", stringify!($signal));
e
}).unwrap();
if let Ok(mut p) = proxy.$signal().await {
info!("Started zbus signal thread: {}", stringify!($signal));
while let Some(e) = p.next().await {
if let Ok(out) = e.args() {
if let Ok(config) = notifs_enabled1.lock() {
if config.all_enabled && config.$signal {
if let Ok(ref mut lock) = last_notif.lock() {
trace!("zbus signal {} locked last_notif", stringify!($signal));
notify!($notifier($msg, &out.$($out_arg)+()), lock);
}
}
}
if let Ok(mut lock) = page_states1.lock() {
lock.$($args)+ = *out.$($out_arg)+();
lock.set_notified();
}
}
}
};
});
};
}
type SharedHandle = Arc<Mutex<Option<NotificationHandle>>>;
pub fn start_notifications(
page_states: Arc<Mutex<SystemState>>,
enabled_notifications: Arc<Mutex<EnabledNotifications>>,
) -> Result<()> {
let last_notification: SharedHandle = Arc::new(Mutex::new(None));
// BIOS notif
recv_notif!(
RogBiosProxy,
receive_notify_post_boot_sound,
last_notification,
enabled_notifications,
page_states,
(bios.post_sound),
(on),
"BIOS Post sound",
do_notification
);
recv_notif!(
RogBiosProxy,
receive_notify_panel_od,
last_notification,
enabled_notifications,
page_states,
(bios.panel_overdrive),
(overdrive),
"Panel Overdrive enabled:",
do_notification
);
recv_notif!(
RogBiosProxy,
receive_notify_dgpu_disable,
last_notification,
enabled_notifications,
page_states,
(bios.dgpu_disable),
(disable),
"BIOS dGPU disabled",
do_notification
);
recv_notif!(
RogBiosProxy,
receive_notify_egpu_enable,
last_notification,
enabled_notifications,
page_states,
(bios.egpu_enable),
(enable),
"BIOS eGPU enabled",
do_notification
);
recv_notif!(
RogBiosProxy,
receive_notify_gpu_mux_mode,
last_notification,
enabled_notifications,
page_states,
(bios.dedicated_gfx),
(mode),
"Reboot required. BIOS GPU MUX mode set to",
do_mux_notification
);
// Charge notif
recv_notif!(
PowerProxy,
receive_notify_charge_control_end_threshold,
last_notification,
enabled_notifications,
page_states,
(power_state.charge_limit),
(limit),
"Battery charge limit changed to",
do_notification
);
recv_notif!(
PowerProxy,
receive_notify_mains_online,
last_notification,
enabled_notifications,
page_states,
(power_state.ac_power),
(on),
"AC Power power is",
ac_power_notification
);
// Profile notif
recv_notif!(
ProfileProxy,
receive_notify_profile,
last_notification,
enabled_notifications,
page_states,
(profiles.current),
(profile),
"Profile changed to",
do_thermal_notif
);
// notify!(do_thermal_notif(&out.profile), lock);
// LED notif
recv_notif!(
LedProxy,
receive_notify_led,
last_notification,
enabled_notifications,
page_states,
(aura.current_mode),
(data.mode),
"Keyboard LED mode changed to",
do_notification
);
let page_states1 = page_states.clone();
tokio::spawn(async move {
let conn = zbus::Connection::system()
.await
.map_err(|e| {
error!("zbus signal: receive_power_states: {e}");
e
})
.unwrap();
let proxy = AnimeProxy::new(&conn)
.await
.map_err(|e| {
error!("zbus signal: receive_power_states: {e}");
e
})
.unwrap();
if let Ok(p) = proxy.receive_power_states().await {
info!("Started zbus signal thread: receive_power_states");
p.for_each(|_| {
if let Ok(_lock) = page_states1.lock() {
// TODO: lock.anime.
}
future::ready(())
})
.await;
};
});
if let Ok(lock) = page_states.try_lock() {
use supergfxctl::pci_device::Device;
let dev = Device::find().unwrap();
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(())
}
fn base_notification<T>(message: &str, data: &T) -> Notification
where
T: Display,
{
let mut notif = Notification::new();
notif
.summary(NOTIF_HEADER)
.body(&format!("{message} {data}"))
.timeout(2000)
//.hint(Hint::Resident(true))
.hint(Hint::Category("device".into()));
notif
}
fn do_notification<T>(message: &str, data: &T) -> Result<NotificationHandle>
where
T: Display,
{
Ok(base_notification(message, data).show()?)
}
fn ac_power_notification(message: &str, on: &bool) -> Result<NotificationHandle> {
let data = if *on {
"plugged".to_owned()
} else {
"unplugged".to_owned()
};
Ok(base_notification(message, &data).show()?)
}
fn do_thermal_notif(message: &str, profile: &Profile) -> Result<NotificationHandle> {
let icon = match profile {
Profile::Balanced => "asus_notif_yellow",
Profile::Performance => "asus_notif_red",
Profile::Quiet => "asus_notif_green",
};
let profile: &str = (*profile).into();
let mut notif = base_notification(message, &profile.to_uppercase());
Ok(notif.icon(icon).show()?)
}
fn do_gpu_status_notif(message: &str, data: &GfxPower) -> Result<NotificationHandle> {
// eww
let mut notif = base_notification(message, &<&str>::from(data).to_owned());
let icon = match data {
GfxPower::Suspended => "asus_notif_blue",
GfxPower::Off => "asus_notif_green",
GfxPower::AsusDisabled => "asus_notif_white",
GfxPower::AsusMuxDiscreet | GfxPower::Active => "asus_notif_red",
GfxPower::Unknown => "gpu-integrated",
};
notif.icon(icon);
Ok(Notification::show(&notif)?)
}
fn do_gfx_action_notif<T>(message: &str, data: &T) -> Result<()>
where
T: Display,
{
let mut notif = base_notification(message, data);
notif.action("gnome-session-quit", "Logout");
notif.urgency(Urgency::Critical);
notif.timeout(3000);
notif.icon("dialog-warning");
notif.hint(Hint::Transient(true));
let handle = notif.show()?;
handle.wait_for_action(|id| {
if id == "gnome-session-quit" {
let mut cmd = Command::new("gnome-session-quit");
cmd.spawn().ok();
} else if id == "__closed" {
// TODO: cancel the switching
}
});
Ok(())
}
/// Actual `GpuMode` unused as data is never correct until switched by reboot
fn do_mux_notification(message: &str, _: &GpuMode) -> Result<NotificationHandle> {
let mut notif = base_notification(message, &"");
notif.urgency(Urgency::Critical);
notif.icon("system-reboot-symbolic");
notif.hint(Hint::Transient(true));
Ok(notif.show()?)
}
@@ -1,14 +1,9 @@
use egui::{RichText, Ui}; use egui::{RichText, Ui};
use rog_platform::supported::SupportedFunctions; use rog_platform::supported::SupportedFunctions;
use crate::{page_states::PageDataStates, RogDbusClientBlocking}; use crate::system_state::SystemState;
pub fn anime_power_group( pub fn anime_power_group(_supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) {
_supported: &SupportedFunctions,
states: &mut PageDataStates,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui,
) {
ui.heading("AniMe Matrix Settings"); ui.heading("AniMe Matrix Settings");
ui.label("Options are incomplete. Awake + Boot should work"); ui.label("Options are incomplete. Awake + Boot should work");
@@ -43,7 +38,9 @@ pub fn anime_power_group(
}); });
ui.horizontal_wrapped(|ui| { ui.horizontal_wrapped(|ui| {
if ui.checkbox(&mut states.anime.boot, "Enable").changed() { if ui.checkbox(&mut states.anime.boot, "Enable").changed() {
dbus.proxies() states
.asus_dbus
.proxies()
.anime() .anime()
.set_boot_on_off(states.anime.boot) .set_boot_on_off(states.anime.boot)
.map_err(|err| { .map_err(|err| {
@@ -54,7 +51,9 @@ pub fn anime_power_group(
}); });
ui.horizontal_wrapped(|ui| { ui.horizontal_wrapped(|ui| {
if ui.checkbox(&mut states.anime.awake, "Enable").changed() { if ui.checkbox(&mut states.anime.awake, "Enable").changed() {
dbus.proxies() states
.asus_dbus
.proxies()
.anime() .anime()
.set_on_off(states.anime.awake) .set_on_off(states.anime.awake)
.map_err(|err| { .map_err(|err| {
+71 -14
View File
@@ -1,13 +1,17 @@
use std::sync::atomic::Ordering;
use egui::Ui; 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.heading("ROG GUI Settings");
// ui.label("Options are incomplete. Awake + Boot should work"); // ui.label("Options are incomplete. Awake + Boot should work");
let mut enabled_notifications = if let Ok(lock) = states.enabled_notifications.lock() {
lock.clone()
} else {
Default::default()
};
if ui if ui
.checkbox(&mut config.run_in_background, "Run in Background") .checkbox(&mut config.run_in_background, "Run in Background")
.clicked() .clicked()
@@ -15,17 +19,70 @@ pub fn app_settings(config: &mut Config, states: &mut PageDataStates, ui: &mut U
.checkbox(&mut config.startup_in_background, "Startup Hidden") .checkbox(&mut config.startup_in_background, "Startup Hidden")
.clicked() .clicked()
|| ui || ui
.checkbox(&mut config.enable_notifications, "Enable Notifications") .checkbox(
&mut enabled_notifications.all_enabled,
"Enable Notifications",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_notify_gfx_status,
"Enable dGPU status notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_notify_dgpu_disable,
"Enable dGPU disablement notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_notify_egpu_enable,
"Enable eGPU enablement notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_notify_mains_online,
"Enable mains (AC) power notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_notify_charge_control_end_threshold,
"Enable charge threshold notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_notify_profile,
"Enable profile change notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_notify_panel_od,
"Enable panel overdrive notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_notify_post_boot_sound,
"Enable BIOS post sound notification",
)
.clicked() .clicked()
{ {
states if let Ok(mut lock) = states.enabled_notifications.lock() {
.notifs_enabled // Replace inner content before save
.store(config.enable_notifications, Ordering::SeqCst); *lock = enabled_notifications;
config
.save() config
.map_err(|err| { .save(&lock)
states.error = Some(err.to_string()); .map_err(|err| {
}) states.error = Some(err.to_string());
.ok(); })
.ok();
}
} }
} }
+6 -9
View File
@@ -7,16 +7,12 @@ use egui::{RichText, Ui};
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour, Speed}; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour, Speed};
use rog_platform::supported::SupportedFunctions; use rog_platform::supported::SupportedFunctions;
use crate::{ use crate::system_state::{AuraState, SystemState};
page_states::{AuraState, PageDataStates},
RogDbusClientBlocking,
};
pub fn aura_modes_group( pub fn aura_modes_group(
supported: &SupportedFunctions, supported: &SupportedFunctions,
states: &mut PageDataStates, states: &mut SystemState,
freq: &mut Arc<AtomicU8>, freq: &mut Arc<AtomicU8>,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui, ui: &mut Ui,
) { ) {
let mut changed = false; let mut changed = false;
@@ -172,8 +168,7 @@ pub fn aura_modes_group(
ui.separator(); ui.separator();
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| { ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
if ui.add(egui::Button::new("Cancel")).clicked() { if ui.add(egui::Button::new("Cancel")).clicked() {
let notif = states.aura.was_notified.clone(); match AuraState::new(supported, &states.asus_dbus) {
match AuraState::new(notif, supported, dbus) {
Ok(a) => states.aura.modes = a.modes, Ok(a) => states.aura.modes = a.modes,
Err(e) => states.error = Some(e.to_string()), Err(e) => states.error = Some(e.to_string()),
} }
@@ -202,7 +197,9 @@ pub fn aura_modes_group(
if changed { if changed {
states.aura.current_mode = selected; states.aura.current_mode = selected;
dbus.proxies() states
.asus_dbus
.proxies()
.led() .led()
.set_led_mode(states.aura.modes.get(&selected).unwrap()) .set_led_mode(states.aura.modes.get(&selected).unwrap())
.map_err(|err| { .map_err(|err| {
+16 -25
View File
@@ -5,32 +5,22 @@ use rog_aura::{
}; };
use rog_platform::supported::SupportedFunctions; use rog_platform::supported::SupportedFunctions;
use crate::{page_states::PageDataStates, RogDbusClientBlocking}; use crate::system_state::SystemState;
pub fn aura_power_group( pub fn aura_power_group(supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) {
supported: &SupportedFunctions,
states: &mut PageDataStates,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui,
) {
ui.heading("LED settings"); ui.heading("LED settings");
match supported.keyboard_led.prod_id { match supported.keyboard_led.prod_id {
AuraDevice::X1854 | AuraDevice::X1869 | AuraDevice::X1866 => { 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::X19B6 => aura_power2(supported, states, ui),
AuraDevice::Tuf => aura_power1(supported, states, dbus, ui), AuraDevice::Tuf => aura_power1(supported, states, ui),
AuraDevice::Unknown => {} AuraDevice::Unknown => {}
} }
} }
fn aura_power1( fn aura_power1(supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) {
supported: &SupportedFunctions,
states: &mut PageDataStates,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui,
) {
let enabled_states = &mut states.aura.enabled; let enabled_states = &mut states.aura.enabled;
let mut boot = enabled_states.x1866.contains(&AuraDev1866::Boot); let mut boot = enabled_states.x1866.contains(&AuraDev1866::Boot);
let mut sleep = enabled_states.x1866.contains(&AuraDev1866::Sleep); let mut sleep = enabled_states.x1866.contains(&AuraDev1866::Sleep);
@@ -144,7 +134,9 @@ fn aura_power1(
x19b6: vec![], x19b6: vec![],
}; };
// build data to send // build data to send
dbus.proxies() states
.asus_dbus
.proxies()
.led() .led()
.set_leds_power(options, enable) .set_leds_power(options, enable)
.map_err(|err| { .map_err(|err| {
@@ -193,7 +185,9 @@ fn aura_power1(
x19b6: vec![], x19b6: vec![],
}; };
// build data to send // build data to send
dbus.proxies() states
.asus_dbus
.proxies()
.led() .led()
.set_leds_power(options, enable) .set_leds_power(options, enable)
.map_err(|err| { .map_err(|err| {
@@ -207,12 +201,7 @@ fn aura_power1(
} }
} }
fn aura_power2( fn aura_power2(supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) {
supported: &SupportedFunctions,
states: &mut PageDataStates,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui,
) {
let enabled_states = &mut states.aura.enabled; let enabled_states = &mut states.aura.enabled;
let has_logo = supported let has_logo = supported
.keyboard_led .keyboard_led
@@ -331,7 +320,9 @@ fn aura_power2(
x19b6: data, x19b6: data,
}; };
// build data to send // build data to send
dbus.proxies() states
.asus_dbus
.proxies()
.led() .led()
.set_leds_power(options, enable) .set_leds_power(options, enable)
.map_err(|err| { .map_err(|err| {
+61 -23
View File
@@ -2,16 +2,12 @@ use egui::{plot::Points, Ui};
use rog_platform::supported::SupportedFunctions; use rog_platform::supported::SupportedFunctions;
use rog_profiles::{FanCurvePU, Profile}; use rog_profiles::{FanCurvePU, Profile};
use crate::{ use crate::{system_state::FanCurvesState, RogDbusClientBlocking};
page_states::{FanCurvesState, ProfilesState},
RogDbusClientBlocking,
};
pub fn fan_graphs( pub fn fan_graphs(
supported: &SupportedFunctions, supported: &SupportedFunctions,
profiles: &mut ProfilesState,
curves: &mut FanCurvesState, curves: &mut FanCurvesState,
dbus: &RogDbusClientBlocking, dbus: &RogDbusClientBlocking<'_>,
do_error: &mut Option<String>, do_error: &mut Option<String>,
ui: &mut Ui, ui: &mut Ui,
) { ) {
@@ -36,14 +32,14 @@ pub fn fan_graphs(
}; };
ui.horizontal_wrapped(|ui| { ui.horizontal_wrapped(|ui| {
for a in curves.curves.iter() { for a in &curves.curves {
item(*a.0, ui); item(*a.0, ui);
} }
}); });
let curve = curves.curves.get_mut(&curves.show_curve).unwrap(); let curve = curves.curves.get_mut(&curves.show_curve).unwrap();
use egui::plot::{Line, Plot, PlotPoints}; use egui::plot::{Line, Plot};
let data = if curves.show_graph == FanCurvePU::CPU { let data = if curves.show_graph == FanCurvePU::CPU {
&mut curve.cpu &mut curve.cpu
@@ -51,14 +47,40 @@ pub fn fan_graphs(
&mut curve.gpu &mut curve.gpu
}; };
let points = data.temp.iter().enumerate().map(|(idx, x)| { let mut points: Vec<[f64; 2]> = data
let x = *x as f64; .temp
let y = ((data.pwm[idx] as u32) * 100 / 255) as f64; .iter()
[x, y] .enumerate()
}); .map(|(idx, x)| {
let x = *x as f64;
let y = ((data.pwm[idx] as u32) * 100 / 255) as f64;
[x, y]
})
.collect();
let line = Line::new(PlotPoints::from_iter(points.clone())).width(2.0); for i in 0..points.len() - 1 {
let points = Points::new(PlotPoints::from_iter(points)).radius(3.0); if i > 0 && i < points.len() - 1 {
if points[i][0] < points[i - 1][0] {
points[i][0] = points[i - 1][0] + 1.0;
data.temp[i] = points[i - 1][0] as u8;
}
if points[i][0] >= points[i + 1][0] {
points[i + 1][0] = points[i][0] + 1.0;
data.temp[i + 1] = points[i][0] as u8;
}
if points[i][1] < points[i - 1][1] {
points[i][1] = points[i - 1][1] + 1.0;
data.pwm[i] = (points[i - 1][1] * 255.0 / 100.0 + 1.0).floor() as u8;
}
if points[i][1] >= points[i + 1][1] {
points[i + 1][1] = points[i][1] + 1.0;
data.pwm[i + 1] = (points[i][1] * 255.0 / 100.0 + 1.0).floor() as u8;
}
}
}
let line = Line::new(points.clone()).width(2.0);
let points = Points::new(points).radius(3.0);
Plot::new("fan_curves") Plot::new("fan_curves")
.view_aspect(1.666) .view_aspect(1.666)
@@ -85,7 +107,7 @@ pub fn fan_graphs(
let mut idx = 0; let mut idx = 0;
if let Some(point) = plot_ui.pointer_coordinate() { if let Some(point) = plot_ui.pointer_coordinate() {
let mut x: i32 = 255; let mut x: i32 = point.x as i32;
for (i, n) in data.temp.iter().enumerate() { for (i, n) in data.temp.iter().enumerate() {
let tmp = x.min((point.x as i32 - *n as i32).abs()); let tmp = x.min((point.x as i32 - *n as i32).abs());
if tmp < x { if tmp < x {
@@ -107,37 +129,53 @@ pub fn fan_graphs(
} }
} }
plot_ui.line(line); plot_ui.line(line);
plot_ui.points(points) plot_ui.points(points);
}); });
let mut set = false; let mut set = false;
let mut clear = false;
let mut reset = false; let mut reset = false;
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| { ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
set = ui.add(egui::Button::new("Apply Fan-curve")).clicked(); set = ui.add(egui::Button::new("Apply Profile")).clicked();
reset = ui.add(egui::Button::new("Reset Profile")).clicked(); clear = ui.add(egui::Button::new("Clear Profile Changes")).clicked();
reset = ui.add(egui::Button::new("Factory Reset Profile")).clicked();
}); });
if set { if set {
dbus.proxies() dbus.proxies()
.profile() .profile()
.set_fan_curve(profiles.current, data.clone()) .set_fan_curve(curves.show_curve, data.clone())
.map_err(|err| { .map_err(|err| {
*do_error = Some(err.to_string()); *do_error = Some(err.to_string());
}) })
.ok(); .ok();
} }
if clear {
if let Ok(curve) = dbus
.proxies()
.profile()
.fan_curve_data(curves.show_curve)
.map_err(|err| {
*do_error = Some(err.to_string());
})
{
if let Some(value) = curves.curves.get_mut(&curves.show_curve) {
*value = curve;
}
}
}
if reset { if reset {
dbus.proxies() dbus.proxies()
.profile() .profile()
.reset_profile_curves(profiles.current) .reset_profile_curves(curves.show_curve)
.map_err(|err| { .map_err(|err| {
*do_error = Some(err.to_string()); *do_error = Some(err.to_string());
}) })
.ok(); .ok();
let notif = curves.was_notified.clone(); match FanCurvesState::new(supported, dbus) {
match FanCurvesState::new(notif, supported, dbus) {
Ok(f) => *curves = f, Ok(f) => *curves = f,
Err(e) => *do_error = Some(e.to_string()), Err(e) => *do_error = Some(e.to_string()),
} }
@@ -1,7 +1,7 @@
use egui::{Align, Color32, Vec2}; use egui::{Align, Color32, Vec2};
use rog_aura::{keys::KeyShape, layouts::KeyLayout, AuraModeNum}; use rog_aura::{keys::KeyShape, layouts::KeyLayout, AuraModeNum};
use crate::page_states::AuraState; use crate::system_state::AuraState;
pub fn keyboard( pub fn keyboard(
ui: &mut egui::Ui, ui: &mut egui::Ui,
+21 -16
View File
@@ -1,9 +1,9 @@
use crate::{page_states::PageDataStates, RogDbusClientBlocking}; use crate::system_state::SystemState;
use egui::Ui; use egui::Ui;
use rog_platform::{platform::GpuMode, supported::SupportedFunctions}; use rog_platform::{platform::GpuMode, supported::SupportedFunctions};
use rog_profiles::Profile; 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"); ui.heading("Platform profile");
let mut changed = false; let mut changed = false;
@@ -17,13 +17,15 @@ pub fn platform_profile(states: &mut PageDataStates, dbus: &RogDbusClientBlockin
}; };
ui.horizontal_wrapped(|ui| { ui.horizontal_wrapped(|ui| {
for a in states.profiles.list.iter() { for a in &states.profiles.list {
item(*a, ui); item(*a, ui);
} }
}); });
if changed { if changed {
dbus.proxies() states
.asus_dbus
.proxies()
.profile() .profile()
.set_active_profile(states.profiles.current) .set_active_profile(states.profiles.current)
.map_err(|err| { .map_err(|err| {
@@ -33,21 +35,18 @@ pub fn platform_profile(states: &mut PageDataStates, dbus: &RogDbusClientBlockin
}; };
} }
pub fn rog_bios_group( pub fn rog_bios_group(supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) {
supported: &SupportedFunctions,
states: &mut PageDataStates,
dbus: &mut RogDbusClientBlocking,
ui: &mut Ui,
) {
ui.heading("Bios options"); 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") .text("Charging limit")
.step_by(1.0); .step_by(1.0);
if ui.add(slider).drag_released() { if ui.add(slider).drag_released() {
dbus.proxies() states
.asus_dbus
.proxies()
.charge() .charge()
.set_charge_control_end_threshold(states.charge_limit as u8) .set_charge_control_end_threshold(states.power_state.charge_limit)
.map_err(|err| { .map_err(|err| {
states.error = Some(err.to_string()); states.error = Some(err.to_string());
}) })
@@ -62,7 +61,9 @@ pub fn rog_bios_group(
)) ))
.changed() .changed()
{ {
dbus.proxies() states
.asus_dbus
.proxies()
.rog_bios() .rog_bios()
.set_post_boot_sound(states.bios.post_sound) .set_post_boot_sound(states.bios.post_sound)
.map_err(|err| { .map_err(|err| {
@@ -79,7 +80,9 @@ pub fn rog_bios_group(
)) ))
.changed() .changed()
{ {
dbus.proxies() states
.asus_dbus
.proxies()
.rog_bios() .rog_bios()
.set_panel_od(states.bios.panel_overdrive) .set_panel_od(states.bios.panel_overdrive)
.map_err(|err| { .map_err(|err| {
@@ -114,7 +117,9 @@ pub fn rog_bios_group(
}); });
if changed { if changed {
dbus.proxies() states
.asus_dbus
.proxies()
.rog_bios() .rog_bios()
.set_gpu_mux_mode(states.bios.dedicated_gfx) .set_gpu_mux_mode(states.bios.dedicated_gfx)
.map_err(|err| { .map_err(|err| {
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::{Page, RogApp}; use crate::{Page, RogApp};
impl<'a> RogApp<'a> { impl RogApp {
pub fn side_panel(&mut self, ctx: &egui::Context) { pub fn side_panel(&mut self, ctx: &egui::Context) {
egui::SidePanel::left("side_panel") egui::SidePanel::left("side_panel")
.resizable(false) .resizable(false)
+1 -1
View File
@@ -2,7 +2,7 @@ use egui::{vec2, Align2, FontId, Id, Sense};
use crate::{RogApp, VERSION}; use crate::{RogApp, VERSION};
impl<'a> RogApp<'a> { impl RogApp {
pub fn top_bar(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { pub fn top_bar(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
// The top panel is often a good place for a menu bar: // The top panel is often a good place for a menu bar:
-2
View File
@@ -15,5 +15,3 @@ 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" }
zbus.workspace = true zbus.workspace = true
zbus_macros.workspace = true
zvariant.workspace = true
+2 -2
View File
@@ -81,7 +81,7 @@ impl<'a> RogDbusClientBlocking<'a> {
Ok((RogDbusClientBlocking { proxies }, conn)) Ok((RogDbusClientBlocking { proxies }, conn))
} }
pub fn proxies(&self) -> &DbusProxiesBlocking { pub fn proxies(&self) -> &DbusProxiesBlocking<'_> {
&self.proxies &self.proxies
} }
} }
@@ -150,7 +150,7 @@ impl<'a> RogDbusClient<'a> {
Ok((RogDbusClient { proxies }, conn)) Ok((RogDbusClient { proxies }, conn))
} }
pub fn proxies(&self) -> &DbusProxies { pub fn proxies(&self) -> &DbusProxies<'_> {
&self.proxies &self.proxies
} }
} }
+1 -8
View File
@@ -1,5 +1,5 @@
use rog_anime::{AnimeDataBuffer, AnimePowerStates}; use rog_anime::{AnimeDataBuffer, AnimePowerStates};
use zbus_macros::dbus_proxy; use zbus::dbus_proxy;
#[dbus_proxy( #[dbus_proxy(
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
@@ -7,33 +7,26 @@ use zbus_macros::dbus_proxy;
)] )]
trait Anime { trait Anime {
/// Set whether the AniMe will show boot, suspend, or off animations /// Set whether the AniMe will show boot, suspend, or off animations
#[inline]
fn set_boot_on_off(&self, status: bool) -> zbus::Result<()>; fn set_boot_on_off(&self, status: bool) -> zbus::Result<()>;
/// Set the global AniMe brightness /// Set the global AniMe brightness
#[inline]
fn set_brightness(&self, bright: f32) -> zbus::Result<()>; fn set_brightness(&self, bright: f32) -> zbus::Result<()>;
/// Set whether the AniMe is displaying images/data /// Set whether the AniMe is displaying images/data
#[inline]
fn set_on_off(&self, status: bool) -> zbus::Result<()>; fn set_on_off(&self, status: bool) -> zbus::Result<()>;
/// Writes a data stream of length. Will force system thread to exit until it is restarted /// Writes a data stream of length. Will force system thread to exit until it is restarted
#[inline]
fn write(&self, input: AnimeDataBuffer) -> zbus::Result<()>; fn write(&self, input: AnimeDataBuffer) -> zbus::Result<()>;
/// Get status of if the AniMe LEDs are on /// Get status of if the AniMe LEDs are on
#[inline]
#[dbus_proxy(property)] #[dbus_proxy(property)]
fn awake_enabled(&self) -> zbus::Result<bool>; fn awake_enabled(&self) -> zbus::Result<bool>;
/// Get the status of if factory system-status animations are enabled /// Get the status of if factory system-status animations are enabled
#[inline]
#[dbus_proxy(property)] #[dbus_proxy(property)]
fn boot_enabled(&self) -> zbus::Result<bool>; fn boot_enabled(&self) -> zbus::Result<bool>;
/// Notify listeners of the status of AniMe LED power and factory system-status animations /// Notify listeners of the status of AniMe LED power and factory system-status animations
#[inline]
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn power_states(&self, data: AnimePowerStates) -> zbus::Result<()>; fn power_states(&self, data: AnimePowerStates) -> zbus::Result<()>;
} }
+1 -15
View File
@@ -21,8 +21,8 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use zbus::dbus_proxy;
use zbus::{blocking::Connection, Result}; use zbus::{blocking::Connection, Result};
use zbus_macros::dbus_proxy;
use rog_aura::{usb::AuraPowerDev, AuraEffect, AuraModeNum, LedBrightness, PerKeyRaw}; use rog_aura::{usb::AuraPowerDev, AuraEffect, AuraModeNum, LedBrightness, PerKeyRaw};
@@ -34,60 +34,46 @@ const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 F
)] )]
trait Led { trait Led {
/// NextLedMode method /// NextLedMode method
#[inline]
fn next_led_mode(&self) -> zbus::Result<()>; fn next_led_mode(&self) -> zbus::Result<()>;
/// PrevLedMode method /// PrevLedMode method
#[inline]
fn prev_led_mode(&self) -> zbus::Result<()>; fn prev_led_mode(&self) -> zbus::Result<()>;
/// Toggle to next led brightness /// Toggle to next led brightness
#[inline]
fn next_led_brightness(&self) -> zbus::Result<()>; fn next_led_brightness(&self) -> zbus::Result<()>;
/// Toggle to previous led brightness /// Toggle to previous led brightness
#[inline]
fn prev_led_brightness(&self) -> zbus::Result<()>; fn prev_led_brightness(&self) -> zbus::Result<()>;
/// SetBrightness method /// SetBrightness method
#[inline]
fn set_brightness(&self, brightness: LedBrightness) -> zbus::Result<()>; fn set_brightness(&self, brightness: LedBrightness) -> zbus::Result<()>;
/// SetLedMode method /// SetLedMode method
#[inline]
fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>; fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>;
#[inline]
fn set_leds_power(&self, options: AuraPowerDev, enabled: bool) -> zbus::Result<()>; fn set_leds_power(&self, options: AuraPowerDev, enabled: bool) -> zbus::Result<()>;
#[inline]
fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()>; fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()>;
/// NotifyLed signal /// NotifyLed signal
#[inline]
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>; fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>;
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
#[inline]
fn notify_power_states(&self, data: AuraPowerDev) -> zbus::Result<()>; fn notify_power_states(&self, data: AuraPowerDev) -> zbus::Result<()>;
/// LedBrightness property /// LedBrightness property
#[inline]
#[dbus_proxy(property)] #[dbus_proxy(property)]
fn led_brightness(&self) -> zbus::Result<i16>; fn led_brightness(&self) -> zbus::Result<i16>;
/// LedMode property /// LedMode property
#[inline]
fn led_mode(&self) -> zbus::Result<AuraModeNum>; fn led_mode(&self) -> zbus::Result<AuraModeNum>;
/// LedModes property /// LedModes property
#[inline]
fn led_modes(&self) -> zbus::Result<BTreeMap<AuraModeNum, AuraEffect>>; fn led_modes(&self) -> zbus::Result<BTreeMap<AuraModeNum, AuraEffect>>;
// As property doesn't work for AuraPowerDev (complexity of serialization?) // As property doesn't work for AuraPowerDev (complexity of serialization?)
// #[dbus_proxy(property)] // #[dbus_proxy(property)]
#[inline]
fn leds_enabled(&self) -> zbus::Result<AuraPowerDev>; fn leds_enabled(&self) -> zbus::Result<AuraPowerDev>;
} }
+1 -15
View File
@@ -20,7 +20,7 @@
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use rog_platform::platform::GpuMode; use rog_platform::platform::GpuMode;
use zbus_macros::dbus_proxy; use zbus::dbus_proxy;
#[dbus_proxy( #[dbus_proxy(
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
@@ -28,62 +28,48 @@ use zbus_macros::dbus_proxy;
)] )]
trait RogBios { trait RogBios {
/// DgpuDisable method /// DgpuDisable method
#[inline]
fn dgpu_disable(&self) -> zbus::Result<bool>; fn dgpu_disable(&self) -> zbus::Result<bool>;
/// EgpuEnable method /// EgpuEnable method
#[inline]
fn egpu_enable(&self) -> zbus::Result<bool>; fn egpu_enable(&self) -> zbus::Result<bool>;
/// GpuMuxMode method /// GpuMuxMode method
#[inline]
fn gpu_mux_mode(&self) -> zbus::Result<GpuMode>; fn gpu_mux_mode(&self) -> zbus::Result<GpuMode>;
/// PanelOd method /// PanelOd method
#[inline]
fn panel_od(&self) -> zbus::Result<bool>; fn panel_od(&self) -> zbus::Result<bool>;
/// PostBootSound method /// PostBootSound method
#[inline]
fn post_boot_sound(&self) -> zbus::Result<i16>; fn post_boot_sound(&self) -> zbus::Result<i16>;
/// SetDgpuDisable method /// SetDgpuDisable method
#[inline]
fn set_dgpu_disable(&self, disable: bool) -> zbus::Result<()>; fn set_dgpu_disable(&self, disable: bool) -> zbus::Result<()>;
/// SetEgpuEnable method /// SetEgpuEnable method
#[inline]
fn set_egpu_enable(&self, enable: bool) -> zbus::Result<()>; fn set_egpu_enable(&self, enable: bool) -> zbus::Result<()>;
/// SetGpuMuxMode method /// SetGpuMuxMode method
#[inline]
fn set_gpu_mux_mode(&self, mode: GpuMode) -> zbus::Result<()>; fn set_gpu_mux_mode(&self, mode: GpuMode) -> zbus::Result<()>;
/// SetPanelOd method /// SetPanelOd method
#[inline]
fn set_panel_od(&self, overdrive: bool) -> zbus::Result<()>; fn set_panel_od(&self, overdrive: bool) -> zbus::Result<()>;
/// SetPostBootSound method /// SetPostBootSound method
#[inline]
fn set_post_boot_sound(&self, on: bool) -> zbus::Result<()>; fn set_post_boot_sound(&self, on: bool) -> zbus::Result<()>;
/// NotifyDgpuDisable signal /// NotifyDgpuDisable signal
#[inline]
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_dgpu_disable(&self, disable: bool) -> zbus::Result<()>; fn notify_dgpu_disable(&self, disable: bool) -> zbus::Result<()>;
/// NotifyEgpuEnable signal /// NotifyEgpuEnable signal
#[inline]
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_egpu_enable(&self, enable: bool) -> zbus::Result<()>; fn notify_egpu_enable(&self, enable: bool) -> zbus::Result<()>;
/// NotifyGpuMuxMode signal /// NotifyGpuMuxMode signal
#[inline]
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_gpu_mux_mode(&self, mode: GpuMode) -> zbus::Result<()>; fn notify_gpu_mux_mode(&self, mode: GpuMode) -> zbus::Result<()>;
/// NotifyPanelOd signal /// NotifyPanelOd signal
#[inline]
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_panel_od(&self, overdrive: bool) -> zbus::Result<()>; fn notify_panel_od(&self, overdrive: bool) -> zbus::Result<()>;
+1 -6
View File
@@ -19,7 +19,7 @@
//! //!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use zbus_macros::dbus_proxy; use zbus::dbus_proxy;
#[dbus_proxy( #[dbus_proxy(
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
@@ -27,24 +27,19 @@ use zbus_macros::dbus_proxy;
)] )]
trait Power { trait Power {
/// charge_control_end_threshold method /// charge_control_end_threshold method
#[inline]
fn charge_control_end_threshold(&self) -> zbus::Result<u8>; fn charge_control_end_threshold(&self) -> zbus::Result<u8>;
/// MainsOnline method /// MainsOnline method
#[inline]
fn mains_online(&self) -> zbus::Result<bool>; fn mains_online(&self) -> zbus::Result<bool>;
/// set_charge_control_end_threshold method /// set_charge_control_end_threshold method
#[inline]
fn set_charge_control_end_threshold(&self, limit: u8) -> zbus::Result<()>; fn set_charge_control_end_threshold(&self, limit: u8) -> zbus::Result<()>;
/// NotifyCharge signal /// NotifyCharge signal
#[inline]
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_charge_control_end_threshold(&self, limit: u8) -> zbus::Result<u8>; fn notify_charge_control_end_threshold(&self, limit: u8) -> zbus::Result<u8>;
/// NotifyMainsOnline signal /// NotifyMainsOnline signal
#[inline]
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_mains_online(&self, on: bool) -> zbus::Result<()>; fn notify_mains_online(&self, on: bool) -> zbus::Result<()>;
} }
+1 -12
View File
@@ -23,7 +23,7 @@ use rog_profiles::{
fan_curve_set::{CurveData, FanCurveSet}, fan_curve_set::{CurveData, FanCurveSet},
Profile, Profile,
}; };
use zbus_macros::dbus_proxy; use zbus::dbus_proxy;
#[dbus_proxy( #[dbus_proxy(
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
@@ -31,55 +31,44 @@ use zbus_macros::dbus_proxy;
)] )]
trait Profile { trait Profile {
/// Get the fan-curve data for the currently active Profile /// Get the fan-curve data for the currently active Profile
#[inline]
fn fan_curve_data(&self, profile: Profile) -> zbus::Result<FanCurveSet>; fn fan_curve_data(&self, profile: Profile) -> zbus::Result<FanCurveSet>;
/// Fetch the active profile name /// Fetch the active profile name
#[inline]
fn active_profile(&self) -> zbus::Result<Profile>; fn active_profile(&self) -> zbus::Result<Profile>;
/// Get a list of profiles that have fan-curves enabled. /// Get a list of profiles that have fan-curves enabled.
#[inline]
fn enabled_fan_profiles(&self) -> zbus::Result<Vec<Profile>>; fn enabled_fan_profiles(&self) -> zbus::Result<Vec<Profile>>;
/// Toggle to next platform_profile. Names provided by `Profiles`. /// Toggle to next platform_profile. Names provided by `Profiles`.
/// If fan-curves are supported will also activate a fan curve for profile. /// If fan-curves are supported will also activate a fan curve for profile.
#[inline]
fn next_profile(&self) -> zbus::Result<()>; fn next_profile(&self) -> zbus::Result<()>;
/// Fetch profile names /// Fetch profile names
#[inline]
fn profiles(&self) -> zbus::Result<Vec<Profile>>; fn profiles(&self) -> zbus::Result<Vec<Profile>>;
/// Set this platform_profile name as active /// Set this platform_profile name as active
#[inline]
fn set_active_profile(&self, profile: Profile) -> zbus::Result<()>; fn set_active_profile(&self, profile: Profile) -> zbus::Result<()>;
/// Set a profile fan curve enabled status. Will also activate a fan curve. /// Set a profile fan curve enabled status. Will also activate a fan curve.
#[inline]
fn set_fan_curve_enabled(&self, profile: Profile, enabled: bool) -> zbus::Result<()>; fn set_fan_curve_enabled(&self, profile: Profile, enabled: bool) -> zbus::Result<()>;
/// Set the fan curve for the specified profile, or the profile the user is /// Set the fan curve for the specified profile, or the profile the user is
/// currently in if profile == None. Will also activate the fan curve. /// currently in if profile == None. Will also activate the fan curve.
#[inline]
fn set_fan_curve(&self, profile: Profile, curve: CurveData) -> zbus::Result<()>; fn set_fan_curve(&self, profile: Profile, curve: CurveData) -> zbus::Result<()>;
/// Reset the stored (self) and device curve to the defaults of the platform. /// Reset the stored (self) and device curve to the defaults of the platform.
/// ///
/// Each platform_profile has a different default and the defualt can be read /// Each platform_profile has a different default and the defualt can be read
/// only for the currently active profile. /// only for the currently active profile.
#[inline]
fn set_active_curve_to_defaults(&self) -> zbus::Result<()>; fn set_active_curve_to_defaults(&self) -> zbus::Result<()>;
/// Reset the stored (self) and device curve to the defaults of the platform. /// Reset the stored (self) and device curve to the defaults of the platform.
/// ///
/// Each platform_profile has a different default and the defualt can be read /// Each platform_profile has a different default and the defualt can be read
/// only for the currently active profile. /// only for the currently active profile.
#[inline]
fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()>; fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()>;
/// NotifyProfile signal /// NotifyProfile signal
#[inline]
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
async fn notify_profile(&self, profile: Profile) -> zbus::Result<Profile>; async fn notify_profile(&self, profile: Profile) -> zbus::Result<Profile>;
} }
+1 -2
View File
@@ -20,7 +20,7 @@
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. //! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use rog_platform::supported::SupportedFunctions; use rog_platform::supported::SupportedFunctions;
use zbus_macros::dbus_proxy; use zbus::dbus_proxy;
#[dbus_proxy( #[dbus_proxy(
interface = "org.asuslinux.Daemon", interface = "org.asuslinux.Daemon",
@@ -28,6 +28,5 @@ use zbus_macros::dbus_proxy;
)] )]
trait Supported { trait Supported {
/// SupportedFunctions method /// SupportedFunctions method
#[inline]
fn supported_functions(&self) -> zbus::Result<SupportedFunctions>; fn supported_functions(&self) -> zbus::Result<SupportedFunctions>;
} }
+2 -2
View File
@@ -1,5 +1,6 @@
[package] [package]
name = "rog_platform" name = "rog_platform"
license = "MPL-2.0"
version.workspace = true version.workspace = true
edition = "2021" edition = "2021"
@@ -8,8 +9,7 @@ log.workspace = true
rog_aura = { path = "../rog-aura" } rog_aura = { path = "../rog-aura" }
serde.workspace = true serde.workspace = true
serde_derive.workspace = true serde_derive.workspace = true
zvariant.workspace = true zbus.workspace = true
zvariant_derive.workspace = true
sysfs-class.workspace = true sysfs-class.workspace = true
concat-idents.workspace = true concat-idents.workspace = true
udev.workspace = true udev.workspace = true
+1 -1
View File
@@ -23,7 +23,7 @@ pub enum PlatformError {
impl fmt::Display for PlatformError { impl fmt::Display for PlatformError {
// This trait requires `fmt` with this exact signature. // This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
PlatformError::ParseVendor => write!(f, "Parse gfx vendor error"), PlatformError::ParseVendor => write!(f, "Parse gfx vendor error"),
PlatformError::ParseNum => write!(f, "Parse number error"), PlatformError::ParseNum => write!(f, "Parse number error"),
+5 -5
View File
@@ -19,7 +19,7 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub(crate) fn to_device(sys_path: &Path) -> Result<Device> { pub(crate) fn to_device(sys_path: &Path) -> Result<Device> {
Device::from_syspath(sys_path) Device::from_syspath(sys_path)
.map_err(|e| PlatformError::Udev("Couldn't transform syspath to device".to_string(), e)) .map_err(|e| PlatformError::Udev("Couldn't transform syspath to device".to_owned(), e))
} }
pub fn has_attr(device: &Device, attr_name: &str) -> bool { pub fn has_attr(device: &Device, attr_name: &str) -> bool {
@@ -39,7 +39,7 @@ pub fn read_attr_bool(device: &Device, attr_name: &str) -> Result<bool> {
} }
return Ok(true); return Ok(true);
} }
Err(PlatformError::AttrNotFound(attr_name.to_string())) Err(PlatformError::AttrNotFound(attr_name.to_owned()))
} }
pub fn write_attr_bool(device: &mut Device, attr: &str, value: bool) -> Result<()> { pub fn write_attr_bool(device: &mut Device, attr: &str, value: bool) -> Result<()> {
@@ -53,7 +53,7 @@ pub fn read_attr_u8(device: &Device, attr_name: &str) -> Result<u8> {
let tmp = value.to_string_lossy(); let tmp = value.to_string_lossy();
return tmp.parse::<u8>().map_err(|_| PlatformError::ParseNum); return tmp.parse::<u8>().map_err(|_| PlatformError::ParseNum);
} }
Err(PlatformError::AttrNotFound(attr_name.to_string())) Err(PlatformError::AttrNotFound(attr_name.to_owned()))
} }
pub fn write_attr_u8(device: &mut Device, attr: &str, value: u8) -> Result<()> { pub fn write_attr_u8(device: &mut Device, attr: &str, value: u8) -> Result<()> {
@@ -71,14 +71,14 @@ pub fn read_attr_u8_array(device: &Device, attr_name: &str) -> Result<Vec<u8>> {
.collect(); .collect();
return Ok(tmp); return Ok(tmp);
} }
Err(PlatformError::AttrNotFound(attr_name.to_string())) Err(PlatformError::AttrNotFound(attr_name.to_owned()))
} }
pub fn write_attr_u8_array(device: &mut Device, attr: &str, values: &[u8]) -> Result<()> { pub fn write_attr_u8_array(device: &mut Device, attr: &str, values: &[u8]) -> Result<()> {
let tmp: String = values.iter().map(|v| format!("{} ", v)).collect(); let tmp: String = values.iter().map(|v| format!("{} ", v)).collect();
let tmp = tmp.trim(); let tmp = tmp.trim();
device device
.set_attribute_value(attr, &tmp) .set_attribute_value(attr, tmp)
.map_err(|e| PlatformError::IoPath(attr.into(), e)) .map_err(|e| PlatformError::IoPath(attr.into(), e))
} }
+9 -8
View File
@@ -2,7 +2,7 @@ use std::{fmt::Display, path::PathBuf, str::FromStr};
use log::{info, warn}; use log::{info, warn};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use zvariant::Type; use zbus::zvariant::Type;
use crate::{ use crate::{
attr_bool, attr_u8, attr_bool, attr_u8,
@@ -11,12 +11,12 @@ use crate::{
}; };
/// The "platform" device provides access to things like: /// The "platform" device provides access to things like:
/// - dgpu_disable /// - `dgpu_disable`
/// - egpu_enable /// - `egpu_enable`
/// - panel_od /// - `panel_od`
/// - gpu_mux /// - `gpu_mux`
/// - keyboard_mode, set keyboard RGB mode and speed /// - `keyboard_mode`, set keyboard RGB mode and speed
/// - keyboard_state, set keyboard power states /// - `keyboard_state`, set keyboard power states
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone)] #[derive(Debug, PartialEq, Eq, PartialOrd, Clone)]
pub struct AsusPlatform { pub struct AsusPlatform {
path: PathBuf, path: PathBuf,
@@ -65,12 +65,13 @@ impl AsusPlatform {
attr_u8!("platform_profile", pp_path); attr_u8!("platform_profile", pp_path);
} }
#[derive(Serialize, Deserialize, Type, Debug, PartialEq, Eq, Clone, Copy)] #[derive(Serialize, Deserialize, Default, Type, Debug, PartialEq, Eq, Clone, Copy)]
pub enum GpuMode { pub enum GpuMode {
Discrete, Discrete,
Optimus, Optimus,
Integrated, Integrated,
Egpu, Egpu,
#[default]
Error, Error,
NotSupported, NotSupported,
} }

Some files were not shown because too many files have changed in this diff Show More