diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b5b96d4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +name: CI + +on: + workflow_dispatch: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + name: "Build and Test" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rui314/setup-mold@v1 + - uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libdbus-1-dev libusb-dev libhidapi-dev libhidapi-hidraw0 pkg-config libudev-dev libgtk-3-dev + version: 1.0 + - name: "Install Rust" + uses: dtolnay/rust-toolchain@stable + - name: "Cache cargo" + uses: Swatinem/rust-cache@v2 + - name: Build + working-directory: ./razer_control_gui + run: cargo build --verbose + - name: Run tests + working-directory: ./razer_control_gui + run: cargo test --verbose + + install: + # This assumes that the worker will be using systemctl + name: "Install on Github Worker" + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v4 + - uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libdbus-1-dev libusb-dev libhidapi-dev libhidapi-hidraw0 pkg-config libudev-dev libgtk-3-dev + version: 1.0 + - name: "Install" + working-directory: ./razer_control_gui + # According to this, sudo sould run ok: https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#administrative-privileges + run: ./install.sh install + - name: "Check installation" + working-directory: ./razer_control_gui + run: ../ci-helpers/check-installation.sh diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index b83d0a3..0000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Rust - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: rui314/setup-mold@v1 - - uses: awalsh128/cache-apt-pkgs-action@latest - with: - packages: libdbus-1-dev libusb-dev libhidapi-dev libhidapi-hidraw0 pkg-config libudev-dev libgtk-3-dev - version: 1.0 - - - name: "Install Rust" - uses: dtolnay/rust-toolchain@stable - - name: "Cache cargo" - uses: Swatinem/rust-cache@v2 - - name: Build - working-directory: ./razer_control_gui - run: cargo build --verbose - - name: Run tests - working-directory: ./razer_control_gui - run: cargo test --verbose diff --git a/NOTES.md b/NOTES.md deleted file mode 100644 index 5f6117d..0000000 --- a/NOTES.md +++ /dev/null @@ -1 +0,0 @@ -# Useful notes diff --git a/ci-helpers/check-installation.sh b/ci-helpers/check-installation.sh new file mode 100755 index 0000000..fcf9d4b --- /dev/null +++ b/ci-helpers/check-installation.sh @@ -0,0 +1,32 @@ +set -o errexit +set -o nounset +set -o pipefail + +check_file() { + if [ ! -e $1 ]; then + echo "File \"$1\" does not exist." + exit 1 + fi +} + +echo "Checking the existence of the necessary files..." +# Daemon +check_file "$HOME/.local/share/razercontrol" +check_file "/usr/share/razercontrol/daemon" +check_file "/usr/share/razercontrol/laptops.json" +check_file "/etc/udev/rules.d/99-hidraw-permissions.rules" +# CLI +check_file "/usr/bin/razer-cli" +# GUI +check_file "/usr/bin/razer-settings" +check_file "/usr/share/applications/razer-settings.desktop" +echo "All files are present" + +printf "Checking that the service is enabled: " +systemctl --user is-enabled razercontrol.service + +echo "Checking files on the path" +printf -- "- " && which razer-cli +printf -- "- " && which razer-settings + +echo "Done!" diff --git a/razer_control_gui/Cargo.lock b/razer_control_gui/Cargo.lock index 4cd204e..c206837 100644 --- a/razer_control_gui/Cargo.lock +++ b/razer_control_gui/Cargo.lock @@ -2,25 +2,35 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" -version = "0.6.5" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" [[package]] name = "anstyle-parse" @@ -213,6 +223,29 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -604,6 +637,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "indexmap" version = "2.2.6" @@ -614,6 +653,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" version = "1.0.9" @@ -651,6 +696,12 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "memchr" version = "2.7.2" @@ -859,6 +910,35 @@ dependencies = [ "getrandom", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "rustc_version" version = "0.4.0" @@ -936,10 +1016,12 @@ dependencies = [ "bincode", "clap", "dbus", + "env_logger", "glib 0.19.7", "gtk", "hidapi", "lazy_static", + "log", "rand", "serde", "serde-big-array", diff --git a/razer_control_gui/Cargo.toml b/razer_control_gui/Cargo.toml index 3c69bf9..1963d99 100644 --- a/razer_control_gui/Cargo.toml +++ b/razer_control_gui/Cargo.toml @@ -9,11 +9,11 @@ edition = "2018" [[bin]] name = "razer-cli" -path = "src/cli.rs" +path = "src/cli/cli.rs" [[bin]] name = "daemon" -path = "src/daemon.rs" +path = "src/daemon/daemon.rs" [[bin]] name = "razer-settings" @@ -38,3 +38,5 @@ serde-big-array = "0.5.1" clap = { version = "4.4.13", features = ["derive"] } gtk = "0.18.1" glib = "0.19.7" +log = "0.4.22" +env_logger = "0.11.5" diff --git a/razer_control_gui/README.md b/razer_control_gui/README.md index 27f5cec..2b7ff69 100644 --- a/razer_control_gui/README.md +++ b/razer_control_gui/README.md @@ -1,55 +1,89 @@ # Experimental code in here! ## Current features -* Full background daemon - Auto load state on machine startup based on last configuration -* CLI and GUI application for adjusting basic settings + +- Full background daemon - Auto load state on machine startup based on last configuration +- CLI and GUI application for adjusting basic settings ![](Screenshoot.png) ## Installing + +### Compiling from source + 1. Install cargo or rustc 2. add `libdbus-1-dev libusb-dev libhidapi-dev libhidapi-hidraw0 pkg-config libudev-dev libgtk-3-dev` packages (or equivelent) 3. run `./install.sh install` as a normal user 4. reboot 5. Enjoy! +### Nixos flake installation + +1. Add this flake to your inputs using + +``` +inputs.razerdaemon.url = "github:JosuGZ/razer-laptop-control"; +``` + +2. Import the razerdaemon module where your inputs are in scope + +``` +imports = [ + inputs.razerdaemon.nixosModules.default +]; +``` + +3. Enable the exposed nixos option using + +``` +services.razer-laptop-control.enable = true; +``` + ## Usage of CLI Application + ``` -razer-cli +razer-cli ``` ### action -* read - Read an attribute (get its current state) - No additional args are supplied -* write - Write an attribute, and save it to configuration - See below for argument counts + +- read - Read an attribute (get its current state) - No additional args are supplied +- write - Write an attribute, and save it to configuration - See below for argument counts ### attribute -* fan - Fan RPM. ARG: 0 = Auto, anything else is interpreted as a litteral RPM -* power - Power mode. ARG: 0 = Balanced, 1 = Gaming, 2 = Creator, 4 = Custom -* brightness - Change brightness of the keyboard -* logo - change logo state (for models with logo): 0 = off, 1 = on, 2 = breathing -* sync - sync light effect for battery/ac -* standard_effect - effects predefined in keyboard controller -* colour - Keyboard colour. ARGS: R G B channels, each channel is set from 0 to 255 + +- fan - Fan RPM. ARG: 0 = Auto, anything else is interpreted as a litteral RPM +- power - Power mode. ARG: 0 = Balanced, 1 = Gaming, 2 = Creator, 4 = Custom +- brightness - Change brightness of the keyboard +- logo - change logo state (for models with logo): 0 = off, 1 = on, 2 = breathing +- sync - sync light effect for battery/ac +- standard_effect - effects predefined in keyboard controller +- colour - Keyboard colour. ARGS: R G B channels, each channel is set from 0 to 255 ### power_state -* ac -* bat + +- ac +- bat #### standard_effects - * 'off' - * 'wave' - PARAMS: - * 'reactive' - PARAMS: - * 'breathing' - PARAMS: [Red] [Green] [Blue] [Red] [Green] [Blue] - * 'spectrum' - * 'static' - PARAMS: - * 'starlight' - PARAMS: [Red] [Green] [Blue] [Red] [Green] [Blue] + +- 'off' +- 'wave' - PARAMS: +- 'reactive' - PARAMS: +- 'breathing' - PARAMS: [Red] [Green] [Blue] [Red] [Green] [Blue] +- 'spectrum' +- 'static' - PARAMS: +- 'starlight' - PARAMS: [Red] [Green] [Blue] [Red] [Green] [Blue] #### custom power control + Custom power control take two more parameters: cpu boost and gpu boost -* 0 - low power -* 1 - normal -* 2 - high -* 3 - boost (only for CPU and only for Advanced 2020 model and Studio Edition) + +- 0 - low power +- 1 - normal +- 2 - high +- 3 - boost (only for CPU and only for Advanced 2020 model and Studio Edition) + ``` razer-cli write power ac 4 3 2 ``` diff --git a/razer_control_gui/data/devices/laptops.json b/razer_control_gui/data/devices/laptops.json index b28ea45..7015605 100644 --- a/razer_control_gui/data/devices/laptops.json +++ b/razer_control_gui/data/devices/laptops.json @@ -4,140 +4,140 @@ "name": "Blade 15 2016", "vid": "1532", "pid": "0224", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2018 15 advanced", "vid": "1532", "pid": "0233", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2018 15 base", "vid": "1532", "pid": "023B", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2018 15 Mercury edition", "vid": "1532", "pid": "0240", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2019 15 base", "vid": "1532", "pid": "0246", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2019 15 advanced", "vid": "1532", "pid": "023A", - "features": ["creator_mode"], + "features": ["logo", "creator_mode"], "fan": [3500, 5300] }, { "name": "Blade 2019 15 Mercury edition", "vid": "1532", "pid": "0245", - "features": ["creator_mode"], + "features": ["logo", "creator_mode"], "fan": [3500, 5300] }, { "name": "Blade 2020 15 base", "vid": "1532", "pid": "0255", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2020 15 advanced", "vid": "1532", "pid": "0253", - "features": ["creator_mode", "boost"], + "features": ["logo", "creator_mode", "boost"], "fan": [3500, 5300] }, { "name": "Blade 2017 stealth", "vid": "1532", "pid": "022D", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "late Blade 2017 stealth", "vid": "1532", "pid": "0232", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2019 stealth", "vid": "1532", "pid": "0239", - "features": [], + "features": ["logo"], "fan": [3500, 5300] }, { "name": "Blade 2019 stealth (With GTX)", "vid": "1532", "pid": "024A", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2020 stealth", "vid": "1532", "pid": "0252", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2020 pro", "vid": "1532", "pid": "0256", - "features": [], + "features": ["logo"], "fan": [3500, 5300] }, { "name": "Blade 2019 pro", "vid": "1532", "pid": "0234", - "features": [], + "features": ["logo"], "fan": [3500, 5300] }, { "name": "Blade 2018 pro FHD", "vid": "1532", "pid": "022F", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2017 pro", "vid": "1532", "pid": "0225", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2017 pro", "vid": "1532", "pid": "0210", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade QHD", "vid": "1532", "pid": "020F", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { @@ -151,98 +151,105 @@ "name": "Blade 2021 15 base", "vid": "1532", "pid": "026F", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 14 2021", "vid": "1532", "pid": "0270", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade 2021 15 advanced", "vid": "1532", "pid": "0276", - "features": ["boost"], + "features": ["logo", "boost"], "fan": [3500, 5000] }, { "name": "Blade late 2021 15 advanced", "vid": "1532", "pid": "026D", - "features": ["boost"], + "features": ["logo", "boost"], "fan": [3500, 5000] }, { "name": "Blade late 2021 15 base", "vid": "1532", "pid": "027A", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade early 2022 15 advanced", "vid": "1532", "pid": "028A", - "features": ["boost", "bho"], + "features": ["logo", "boost", "bho"], "fan": [3500, 5000] }, { "name": "Blade 2022 17", "vid": "1532", "pid": "028B", - "features": ["boost"], + "features": ["logo", "boost"], "fan": [3500, 5000] }, { "name": "Blade 2022 14", "vid": "1532", "pid": "028C", - "features": ["boost", "bho"], + "features": ["logo", "boost", "bho"], "fan": [3500, 5000] }, { "name": "Blade late 2020 stealth", "vid": "1532", "pid": "0259", - "features": [], + "features": ["logo"], "fan": [3500, 5000] }, { "name": "Blade late 16", "vid": "1532", "pid": "029F", - "features": ["boost", "bho"], + "features": ["logo", "boost", "bho"], "fan": [2200, 5000] }, { "name": "Blade 2023 14", "vid": "1532", "pid": "029D", - "features": ["boost", "bho"], + "features": ["logo", "boost", "bho"], "fan": [2200, 5000] }, { "name": "Blade Early 2021 17 pro", "vid": "1532", "pid": "026E", - "features": ["boost"], + "features": ["logo", "boost"], "fan": [2300, 4300] }, { "name": "Blade 2024 14", "vid": "1532", "pid": "02b6", - "features": ["boost", "bho"], + "features": ["logo", "boost", "bho"], "fan": [2200, 5000] }, { "name": "Blade Mid 2021 17 pro", "vid": "1532", "pid": "0279", - "features": ["boost"], + "features": ["logo", "boost"], "fan": [2300, 4300] - } + }, + { + "name": "Razer Blade 18 2023", + "vid": "1532", + "pid": "02a0", + "features": ["logo", "boost", "bho"], + "fan": [2200, 5000] + } ] diff --git a/razer_control_gui/data/udev/99-hidraw-permissions.rules b/razer_control_gui/data/udev/99-hidraw-permissions.rules index 5743509..a034c22 100644 --- a/razer_control_gui/data/udev/99-hidraw-permissions.rules +++ b/razer_control_gui/data/udev/99-hidraw-permissions.rules @@ -1 +1 @@ -KERNEL=="hidraw*", ATTRS{idProduct}=="020f|0210|0224|0225|022d|022f|0232|0233|0234|0239|023a|023b|0240|0245|0246|024a|0252|0253|0255|0256|026a|026f|0270|0276|026d|027a|028a|028b|028c|0259|029f|029d|026e|02b6|0279|", ATTRS{idVendor}=="1532", MODE="0666", TAG+="uaccess" +KERNEL=="hidraw*", ATTRS{idProduct}=="020f|0210|0224|0225|022d|022f|0232|0233|0234|0239|023a|023b|0240|0245|0246|024a|0252|0253|0255|0256|026a|026f|0270|0276|026d|027a|028a|028b|028c|0259|029f|029d|026e|02b6|0279|02a0|", ATTRS{idVendor}=="1532", MODE="0666", TAG+="uaccess" diff --git a/razer_control_gui/src/cli.rs b/razer_control_gui/src/cli/cli.rs similarity index 99% rename from razer_control_gui/src/cli.rs rename to razer_control_gui/src/cli/cli.rs index 5fd6aad..121359a 100644 --- a/razer_control_gui/src/cli.rs +++ b/razer_control_gui/src/cli/cli.rs @@ -1,3 +1,4 @@ +#[path = "../comms.rs"] mod comms; use clap::{error::ErrorKind, CommandFactory, Parser, Subcommand, ValueEnum}; diff --git a/razer_control_gui/src/battery.rs b/razer_control_gui/src/daemon/battery.rs similarity index 100% rename from razer_control_gui/src/battery.rs rename to razer_control_gui/src/daemon/battery.rs diff --git a/razer_control_gui/src/config.rs b/razer_control_gui/src/daemon/config.rs similarity index 100% rename from razer_control_gui/src/config.rs rename to razer_control_gui/src/daemon/config.rs diff --git a/razer_control_gui/src/daemon.rs b/razer_control_gui/src/daemon/daemon.rs similarity index 85% rename from razer_control_gui/src/daemon.rs rename to razer_control_gui/src/daemon/daemon.rs index 76e5de0..1013c26 100644 --- a/razer_control_gui/src/daemon.rs +++ b/razer_control_gui/src/daemon/daemon.rs @@ -1,25 +1,29 @@ +use std::io::{Read, Write}; +use std::os::unix::net::UnixStream; +use std::sync::Mutex; +use std::thread::{self, JoinHandle}; +use std::time; + +use log::*; +use lazy_static::lazy_static; +use signal_hook::iterator::Signals; +use signal_hook::consts::{SIGINT, SIGTERM}; +use dbus::blocking::Connection; +use dbus::{Message, arg}; + +#[path = "../comms.rs"] mod comms; mod config; -// mod driver_sysfs; mod kbd; mod device; -use crate::kbd::Effect; -// use bincode::Options; -use lazy_static::lazy_static; -use signal_hook::{iterator::Signals, consts::SIGINT, consts::SIGTERM}; -// use std::io::prelude::*; -use std::io::{Read, Write}; -use std::os::unix::net::UnixStream; -use dbus::{blocking::Connection, arg}; -use dbus::Message; -use std::sync::Mutex; -use std::{thread, time}; mod battery; mod dbus_mutter_displayconfig; mod dbus_mutter_idlemonitor; mod screensaver; mod login1; +use crate::kbd::Effect; + lazy_static! { static ref EFFECT_MANAGER: Mutex = Mutex::new(kbd::EffectManager::new()); // static ref CONFIG: Mutex = { @@ -39,6 +43,7 @@ lazy_static! { // Main function for daemon fn main() { setup_panic_hook(); + init_logging(); if let Ok(mut d) = DEV_MANAGER.lock() { d.discover_devices(); @@ -60,7 +65,7 @@ fn main() { let proxy_ac = dbus_system.with_proxy("org.freedesktop.UPower", "/org/freedesktop/UPower/devices/line_power_AC0", time::Duration::from_millis(5000)); use battery::OrgFreedesktopUPowerDevice; if let Ok(online) = proxy_ac.online() { - println!("Online AC0: {:?}", online); + info!("AC0 online: {:?}", online); d.set_ac_state(online); d.restore_standard_effect(); if let Ok(json) = config::Configuration::read_effects_file() { @@ -79,16 +84,60 @@ fn main() { } } + start_keyboard_animator_task(); + start_screensaver_monitor_task(); + start_battery_monitor_task(); + let clean_thread = start_shutdown_task(); + + if let Some(listener) = comms::create() { + for stream in listener.incoming() { + match stream { + Ok(stream) => handle_data(stream), + Err(_) => {} // Don't care about this + } + } + } else { + eprintln!("Could not create Unix socket!"); + std::process::exit(1); + } + clean_thread.join().unwrap(); +} + +/// Installs a custom panic hook to perform cleanup when the daemon crashes +fn setup_panic_hook() { + let default_panic_hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |info| { + error!("Something went wrong! Removing the socket path"); + if std::fs::metadata(comms::SOCKET_PATH).is_ok() { + std::fs::remove_file(comms::SOCKET_PATH).unwrap(); + } + default_panic_hook(info); + })); +} + +fn init_logging() { + let mut builder = env_logger::Builder::from_default_env(); + builder.target(env_logger::Target::Stderr); + builder.filter_level(log::LevelFilter::Info); + builder.format_timestamp_millis(); + builder.parse_env("RAZER_LAPTOP_CONTROL_LOG"); + builder.init(); +} + +/// Handles keyboard animations +pub fn start_keyboard_animator_task() -> JoinHandle<()> { // Start the keyboard animator thread, - thread::spawn(move || { + thread::spawn(|| { loop { if let Some(laptop) = DEV_MANAGER.lock().unwrap().get_device() { EFFECT_MANAGER.lock().unwrap().update(laptop); } - std::thread::sleep(std::time::Duration::from_millis(kbd::ANIMATION_SLEEP_MS)); + thread::sleep(std::time::Duration::from_millis(kbd::ANIMATION_SLEEP_MS)); } - }); + }) +} +fn start_screensaver_monitor_task() -> JoinHandle<()> { thread::spawn(move || { let dbus_session = Connection::new_session() .expect("failed to connect to D-Bus session bus"); @@ -149,16 +198,37 @@ fn main() { } } - }); + }) +} +fn start_battery_monitor_task() -> JoinHandle<()> { thread::spawn(move || { let dbus_system = Connection::new_system() - .expect("failed to connect to D-Bus system bus"); - let proxy_ac = dbus_system.with_proxy("org.freedesktop.UPower", "/org/freedesktop/UPower/devices/line_power_AC0", time::Duration::from_millis(5000)); + .expect("should be able to connect to D-Bus system bus"); + info!("Connected to the system D-Bus"); + + let proxy_ac = dbus_system.with_proxy( + "org.freedesktop.UPower", + "/org/freedesktop/UPower/devices/line_power_AC0", + time::Duration::from_millis(5000) + ); + + let proxy_battery = dbus_system.with_proxy( + "org.freedesktop.UPower", + "/org/freedesktop/UPower/devices/battery_BAT0", + time::Duration::from_millis(5000) + ); + + let proxy_login = dbus_system.with_proxy( + "org.freedesktop.login1", + "/org/freedesktop/login1", + time::Duration::from_millis(5000) + ); + let _id = proxy_ac.match_signal(|h: battery::OrgFreedesktopDBusPropertiesPropertiesChanged, _: &Connection, _: &Message| { let online: Option<&bool> = arg::prop_cast(&h.changed_properties, "Online"); if let Some(online) = online { - println!("Online AC0: {:?}", online); + info!("AC0 online: {:?}", online); if let Ok(mut d) = DEV_MANAGER.lock() { d.set_ac_state(*online); } @@ -166,22 +236,16 @@ fn main() { true }); - let proxy_battery = dbus_system.with_proxy("org.freedesktop.UPower", "/org/freedesktop/UPower/devices/battery_BAT0", time::Duration::from_millis(5000)); - // use battery::OrgFreedesktopUPowerDevice; - // if let Ok(perc) = proxy_battery.percentage() { - // println!("battery percentage: {:.1}", perc); - // } let _id = proxy_battery.match_signal(|h: battery::OrgFreedesktopDBusPropertiesPropertiesChanged, _: &Connection, _: &Message| { let perc: Option<&f64> = arg::prop_cast(&h.changed_properties, "Percentage"); if let Some(perc) = perc { - println!("battery percentage: {:.1}", perc); + info!("Battery percentage: {:.1}", perc); } true }); - let proxy_login = dbus_system.with_proxy("org.freedesktop.login1", "/org/freedesktop/login1", time::Duration::from_millis(5000)); let _id = proxy_login.match_signal(|h: login1::OrgFreedesktopLogin1ManagerPrepareForSleep, _: &Connection, _: &Message| { - println!("PrepareForSleep {:?}", h.start); + info!("PrepareForSleep {:?}", h.start); if let Ok(mut d) = DEV_MANAGER.lock() { d.set_ac_state_get(); if h.start { @@ -192,52 +256,28 @@ fn main() { } true }); - // use login1::OrgFreedesktopLogin1ManagerPrepareForSleep; + loop { dbus_system.process(time::Duration::from_millis(1000)).unwrap(); } - }); + }) +} - // Signal handler - cleanup if we are told to exit - let mut signals = Signals::new([SIGINT, SIGTERM]).unwrap(); - let clean_thread = thread::spawn(move || { +/// Monitors signals and stops the daemon when receiving one +pub fn start_shutdown_task() -> JoinHandle<()> { + thread::spawn(|| { + let mut signals = Signals::new([SIGINT, SIGTERM]).unwrap(); let _ = signals.forever().next(); // If we reach this point, we have a signal and it is time to exit println!("Received signal, cleaning up"); let json = EFFECT_MANAGER.lock().unwrap().save(); - if let Err(e) = config::Configuration::write_effects_save(json) { - eprintln!("Error write config {:?}", e); + if let Err(error) = config::Configuration::write_effects_save(json) { + error!("Error writing config {}", error); } if std::fs::metadata(comms::SOCKET_PATH).is_ok() { std::fs::remove_file(comms::SOCKET_PATH).unwrap(); } std::process::exit(0); - }); - - - if let Some(listener) = comms::create() { - for stream in listener.incoming() { - match stream { - Ok(stream) => handle_data(stream), - Err(_) => {} // Don't care about this - } - } - } else { - eprintln!("Could not create Unix socket!"); - std::process::exit(1); - } - clean_thread.join().unwrap(); -} - -/// Installs a custom panic hook to perform cleanup when the daemon crashes -fn setup_panic_hook() { - let default_panic_hook = std::panic::take_hook(); - std::panic::set_hook(Box::new(move |info| { - println!("Something went wrong! Removing the socket path"); - if std::fs::metadata(comms::SOCKET_PATH).is_ok() { - std::fs::remove_file(comms::SOCKET_PATH).unwrap(); - } - default_panic_hook(info); - })); + }) } fn handle_data(mut stream: UnixStream) { diff --git a/razer_control_gui/src/dbus_mutter_displayconfig.rs b/razer_control_gui/src/daemon/dbus_mutter_displayconfig.rs similarity index 100% rename from razer_control_gui/src/dbus_mutter_displayconfig.rs rename to razer_control_gui/src/daemon/dbus_mutter_displayconfig.rs diff --git a/razer_control_gui/src/dbus_mutter_idlemonitor.rs b/razer_control_gui/src/daemon/dbus_mutter_idlemonitor.rs similarity index 100% rename from razer_control_gui/src/dbus_mutter_idlemonitor.rs rename to razer_control_gui/src/daemon/dbus_mutter_idlemonitor.rs diff --git a/razer_control_gui/src/device.rs b/razer_control_gui/src/daemon/device.rs similarity index 100% rename from razer_control_gui/src/device.rs rename to razer_control_gui/src/daemon/device.rs diff --git a/razer_control_gui/src/kbd/board.rs b/razer_control_gui/src/daemon/kbd/board.rs similarity index 100% rename from razer_control_gui/src/kbd/board.rs rename to razer_control_gui/src/daemon/kbd/board.rs diff --git a/razer_control_gui/src/kbd/effects.rs b/razer_control_gui/src/daemon/kbd/effects.rs similarity index 100% rename from razer_control_gui/src/kbd/effects.rs rename to razer_control_gui/src/daemon/kbd/effects.rs diff --git a/razer_control_gui/src/kbd/mod.rs b/razer_control_gui/src/daemon/kbd/mod.rs similarity index 100% rename from razer_control_gui/src/kbd/mod.rs rename to razer_control_gui/src/daemon/kbd/mod.rs diff --git a/razer_control_gui/src/login1.rs b/razer_control_gui/src/daemon/login1.rs similarity index 100% rename from razer_control_gui/src/login1.rs rename to razer_control_gui/src/daemon/login1.rs diff --git a/razer_control_gui/src/screensaver.rs b/razer_control_gui/src/daemon/screensaver.rs similarity index 100% rename from razer_control_gui/src/screensaver.rs rename to razer_control_gui/src/daemon/screensaver.rs diff --git a/razer_control_gui/src/lib.rs b/razer_control_gui/src/lib.rs index 16f315f..b6ed620 100644 --- a/razer_control_gui/src/lib.rs +++ b/razer_control_gui/src/lib.rs @@ -23,4 +23,8 @@ impl SupportedDevice { self.has_feature("boost") } + pub fn has_logo(&self) -> bool { + self.has_feature("logo") + } + } diff --git a/razer_control_gui/src/razer-settings/razer-settings.rs b/razer_control_gui/src/razer-settings/razer-settings.rs index c442e9e..ccb5bc6 100644 --- a/razer_control_gui/src/razer-settings/razer-settings.rs +++ b/razer_control_gui/src/razer-settings/razer-settings.rs @@ -298,6 +298,7 @@ fn main() { .default_width(640) .default_height(480) .title("Razer Settings") + .window_position(gtk::WindowPosition::Center) .build(); let ac_settings_page = make_page(true, device.clone()); @@ -360,7 +361,6 @@ fn main() { } fn make_page(ac: bool, device: SupportedDevice) -> SettingsPage { - let logo = get_logo(ac); let fan_speed = get_fan_speed(ac).or_crash("Error reading fan speed"); let brightness = get_brightness(ac).or_crash("Error reading brightness"); let power = get_power(ac); @@ -373,7 +373,8 @@ fn make_page(ac: bool, device: SupportedDevice) -> SettingsPage { let settings_page = SettingsPage::new(); // Logo section - if let Some(logo) = logo { + if device.has_logo() { + let logo = get_logo(ac).or_crash("Error reading logo"); let settings_section = settings_page.add_section(Some("Logo")); let label = Label::new(Some("Turn on logo")); let logo_options = ComboBoxText::new();