commit 5f81577b83ecc61bf1d24c550f028b74a3881c96 Author: Marko Korhonen Date: Sun Jan 19 21:33:52 2020 +0200 Initial commit Signed-off-by: Marko Korhonen diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6ecf30d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,188 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lqsd" +version = "0.1.0" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "toml" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "xdg" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" +"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3fed685 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "lqsd" +version = "0.1.0" +authors = ["Marko Korhonen "] +edition = "2018" +publish = false +description = "Dims your screen smoothly" +repository = "https://git.reekynet.com/ReekyMarko/lqsd" +license = "MIT" + +[dependencies] +clap = "2.33.0" +xdg = "2.2.0" +toml = "0.5.6" +serde = {version = "1.0.104", features = ["derive"]} diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..c438f14 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,31 @@ +extern crate clap; +use clap::{App, Arg}; + +pub fn get_args() -> clap::ArgMatches<'static> { + App::new("LiQuid Screen Dim") + .version(env!("CARGO_PKG_VERSION")) + .author(env!("CARGO_PKG_AUTHORS")) + .about(env!("CARGO_PKG_DESCRIPTION")) + .arg( + Arg::with_name("dim") + .long("dim") + .short("d") + .takes_value(false) + .help("Dims the screen to idle level set in configuration"), + ) + .arg( + Arg::with_name("resume") + .long("resume") + .short("r") + .takes_value(false) + .help("Sets the backlight to the value it was before dimming"), + ) + .arg( + Arg::with_name("config") + .long("config") + .short("c") + .takes_value(true) + .help("Sets a custom config file"), + ) + .get_matches() +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..fac77c0 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,52 @@ +use super::fs; +use super::Config; +use std::path::PathBuf; +use xdg::BaseDirectories; + +extern crate xdg; + +fn default_config() -> Config { + Config { + resume_file_path: PathBuf::from("/tmp/lqsd-resume"), + idle_level: 0, + dim_speed: 50, + resume_speed: 25, + } +} + +fn xdg_config() -> PathBuf { + BaseDirectories::with_prefix("lqsd") + .expect("cannot create configuration directory") + .place_config_file("config.toml") + .unwrap() +} + +pub fn load_xdg() -> Config { + let path = xdg_config(); + + if !path.exists() { + println!( + "{} does not exist, writing default configuration", + path.display() + ); + match fs::write(&path, toml::to_string(&default_config()).unwrap()) { + Ok(()) => println!("Default config saved to {}", path.display()), + Err(err) => eprintln!("Failed to write default config: {}", err), + }; + default_config() + } else { + let toml = fs::read(&path).unwrap(); + let config: Config = toml::from_str(&toml).unwrap(); + config + } +} + +pub fn load_user(path: PathBuf) -> Config { + if !path.exists() { + panic!("{} does not exist", path.display()); + } else { + let toml = fs::read(&path).unwrap(); + let config: Config = toml::from_str(&toml).unwrap(); + config + } +} diff --git a/src/fs.rs b/src/fs.rs new file mode 100644 index 0000000..c2e0408 --- /dev/null +++ b/src/fs.rs @@ -0,0 +1,22 @@ +use std::fs::{remove_file, File}; +use std::io::prelude::*; +use std::path::PathBuf; + +pub fn write(path: &PathBuf, contents: String) -> std::io::Result<()> { + let mut file = File::create(path)?; + file.write_all(contents.as_bytes())?; + file.sync_data()?; + Ok(()) +} + +pub fn read(path: &PathBuf) -> std::io::Result { + let mut file = File::open(path)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + Ok(contents) +} + +pub fn remove(path: &PathBuf) -> std::io::Result<()> { + remove_file(path)?; + Ok(()) +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..1b5ebe1 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,88 @@ +extern crate clap; + +mod cli; +mod config; +mod fs; + +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use std::process::Command; +use std::{thread, time}; + +#[derive(Deserialize, Serialize)] +pub struct Config { + resume_file_path: PathBuf, + idle_level: i32, + dim_speed: u64, + resume_speed: u64, +} + +fn transition(w_brightness: i32, speed: time::Duration) { + let c_brightness = get_brightness(); + println!("Transitioning from {}% to {}%", c_brightness, w_brightness); + + if c_brightness < w_brightness { + for n in c_brightness..w_brightness { + if n != c_brightness { + set_brightness(n); + thread::sleep(speed); + } + } + } else { + for n in (w_brightness..c_brightness).rev() { + if n != c_brightness { + set_brightness(n); + thread::sleep(speed); + } + } + } +} + +fn set_brightness(brightness: i32) { + Command::new("light") + .args(&["-S", &brightness.to_string()]) + .spawn() + .expect("Failed to execute command 'light'"); +} + +fn get_brightness() -> i32 { + let output = Command::new("light") + .arg("-G") + .output() + .expect("Failed to execute command 'light'"); + + let string = String::from_utf8_lossy(&output.stdout); + let float: f32 = string.trim().parse().unwrap(); + float.round() as i32 +} + +fn main() { + let args = cli::get_args(); + let conf: Config; + + if args.is_present("config") { + let config_path = PathBuf::from(args.value_of("config").unwrap()); + conf = config::load_user(config_path); + } else { + conf = config::load_xdg(); + } + let dim_speed = time::Duration::from_millis(conf.dim_speed); + let resume_speed = time::Duration::from_millis(conf.resume_speed); + + if args.is_present("dim") { + let current_brightness = get_brightness().to_string(); + match fs::write(&conf.resume_file_path, current_brightness) { + Ok(()) => println!("Current brightness written to resume file"), + Err(err) => eprintln!("Error writing brightness to resume file: {}", err), + } + transition(conf.idle_level, dim_speed); + } + if args.is_present("resume") { + let old_brightness: i32 = fs::read(&conf.resume_file_path).unwrap().parse().unwrap(); + transition(old_brightness, resume_speed); + match fs::remove(&conf.resume_file_path) { + Ok(()) => println!("Resume file removed"), + Err(err) => eprintln!("Failed to remove resume file: {}", err), + } + } +}