diff --git a/Cargo.lock b/Cargo.lock index f28bd56..ff897ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -260,7 +260,6 @@ dependencies = [ "bscreensaver-command", "bscreensaver-util", "clap", - "humantime", "log", "nix", "xcb", @@ -333,6 +332,7 @@ dependencies = [ "anyhow", "clap", "env_logger", + "humantime", "lazy_static", "libc", "toml", @@ -1088,9 +1088,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] diff --git a/dialog-gtk3/src/main.rs b/dialog-gtk3/src/main.rs index 7f2ab13..734e21b 100644 --- a/dialog-gtk3/src/main.rs +++ b/dialog-gtk3/src/main.rs @@ -6,7 +6,7 @@ use gtk::{prelude::*, Button, Entry, Label, Plug, Window}; use log::{debug, error, warn}; use std::{io::{self, Write}, process::{exit, Command}, rc::Rc, thread, time::Duration}; -use bscreensaver_util::{init_logging, load_configuration}; +use bscreensaver_util::{init_logging, settings::Configuration}; const DIALOG_UPDATE_INTERVAL: Duration = Duration::from_millis(100); const DIALOG_TIMEOUT: Duration = Duration::from_secs(60); @@ -14,21 +14,11 @@ const DIALOG_TIMEOUT: Duration = Duration::from_secs(60); fn main() -> anyhow::Result<()> { init_logging("BSCREENSAVER_DIALOG_GTK3_LOG"); - let config_tomls = load_configuration()?; - let mut config_tomls_iter = config_tomls.into_iter().rev(); - let mut new_login_command: Option> = loop { - if let Some(config_toml) = config_tomls_iter.next() { - if let Some(nlc) = config_toml.get("new-login-command") - .and_then(|nlc| nlc.as_str().map(|s| s.to_string())) - .map(|nlc| shell_words::split(&nlc)) - .transpose()? - { - break Some(nlc); - } - } else { - break None; - } - }; + let mut config = Configuration::load()?; + let new_login_command = config.new_login_command + .take() + .map(|nlc| shell_words::split(&nlc)) + .transpose()?; let standalone = std::env::var("BSCREENSAVER_DIALOG_STANDALONE").is_ok(); @@ -224,7 +214,7 @@ fn main() -> anyhow::Result<()> { .build(); vbox.pack_start(&hbox, true, true, 2); - if let Some(new_login_command) = new_login_command.take() { + if let Some(new_login_command) = new_login_command { let new_login_button = Button::builder() .label("New Login") .build(); diff --git a/locker/Cargo.toml b/locker/Cargo.toml index 588af98..3d75898 100644 --- a/locker/Cargo.toml +++ b/locker/Cargo.toml @@ -17,7 +17,6 @@ anyhow = "1" clap = "3" bscreensaver-command = { path = "../command" } bscreensaver-util = { path = "../util" } -humantime = "2" log = "0.4" nix = "0.23" # git source needed until extension event error resolution fix is released diff --git a/locker/src/main.rs b/locker/src/main.rs index d6100df..5ae1beb 100644 --- a/locker/src/main.rs +++ b/locker/src/main.rs @@ -1,7 +1,6 @@ #![feature(linux_pidfd)] #![feature(option_result_contains)] -use anyhow::anyhow; use clap::{Arg, Command as ClapCommand}; use log::{debug, error, info, trace, warn}; use nix::{ @@ -29,50 +28,11 @@ use xcb::{randr, x, xinput, Xid}; use xcb_xembed::embedder::Embedder; use bscreensaver_command::{BCommand, create_command_window}; -use bscreensaver_util::*; +use bscreensaver_util::{*, settings::Configuration}; const BLANKED_ARG: &str = "blanked"; const LOCKED_ARG: &str = "locked"; -#[derive(Debug, Clone, Copy)] -enum DialogBackend { - Gtk3, -} - -impl DialogBackend { - pub fn binary_name(&self) -> &str { - match self { - Self::Gtk3 => "bscreensaver-dialog-gtk3", - } - } -} - -impl TryFrom<&str> for DialogBackend { - type Error = anyhow::Error; - fn try_from(value: &str) -> Result { - match value { - "gtk3" => Ok(Self::Gtk3), - other => Err(anyhow!("'{}' is not a valid dialog backend (valid: 'gtk3')", other)), - } - } -} - -struct Configuration { - lock_timeout: Duration, - blank_before_locking: Duration, - dialog_backend: DialogBackend, -} - -impl Default for Configuration { - fn default() -> Self { - Self { - lock_timeout: Duration::from_secs(60 * 10), - blank_before_locking: Duration::ZERO, - dialog_backend: DialogBackend::Gtk3, - } - } -} - #[derive(Clone, Copy)] struct Monitor { pub root: x::Window, @@ -132,7 +92,7 @@ macro_rules! maybe_add_fd { fn main() -> anyhow::Result<()> { init_logging("BSCREENSAVER_LOG"); - let config = parse_config()?; + let config = Configuration::load()?; let args = ClapCommand::new("Blanks and locks the screen after a period of time") .author(env!("CARGO_PKG_AUTHORS")) @@ -275,32 +235,6 @@ fn main() -> anyhow::Result<()> { } } -fn parse_config() -> anyhow::Result { - use humantime::parse_duration; - - let mut config = Configuration::default(); - for config_toml in load_configuration()? { - config.lock_timeout = match config_toml.get("lock-timeout") { - None => config.lock_timeout, - Some(val) => parse_duration(val.as_str().ok_or(anyhow!("'lock-timeout' must be a duration string like '10m' or '90s'"))?)?, - }; - config.blank_before_locking = match config_toml.get("blank-before-locking") { - None => config.blank_before_locking, - Some(val) => parse_duration(val.as_str().ok_or(anyhow!("'blank-before-locking' must be a duration string like '10m' or '90s'"))?)?, - }; - config.dialog_backend = match config_toml.get("dialog-backend") { - None => config.dialog_backend, - Some(val) => DialogBackend::try_from(val.as_str().ok_or(anyhow!("'dialog-backend' must be a string"))?)?, - }; - - if config.blank_before_locking >= config.lock_timeout { - Err(anyhow!("'blank-before-locking' cannot be greater than 'lock-timeout'"))? - } - } - - Ok(config) -} - fn init_signals() -> anyhow::Result { let sigs = { let mut s = SigSet::empty(); diff --git a/util/Cargo.toml b/util/Cargo.toml index b7c3a30..3b5af4f 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" anyhow = "1" clap = "3" env_logger = "0.9" +humantime = "2" lazy_static = "1" libc = "0.2" toml = "0.5" diff --git a/util/src/lib.rs b/util/src/lib.rs index 330c97d..0794f6d 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -1,7 +1,8 @@ -use std::{ffi::CStr, fs::File, io::{self, Read}, path::PathBuf}; -use toml::Value; +use std::{ffi::CStr, io}; use xcb::x; +pub mod settings; + pub const BSCREENSAVER_WM_CLASS: &[u8] = b"bscreensaver\0Bscreensaver\0"; pub fn init_logging(env_name: &str) { @@ -11,23 +12,6 @@ pub fn init_logging(env_name: &str) { .init(); } -fn parse_config_toml(config_path: &PathBuf) -> anyhow::Result { - let mut f = File::open(config_path)?; - let mut config = String::new(); - f.read_to_string(&mut config)?; - drop(f); - - let config_toml = config.parse::()?; - Ok(config_toml) -} - -pub fn load_configuration() -> anyhow::Result> { - xdg::BaseDirectories::new()? - .find_config_files("bscreensaver/bscreensaver.toml") - .map(|config_path| parse_config_toml(&config_path)) - .collect() -} - pub fn create_atom(conn: &xcb::Connection, name: &[u8]) -> xcb::Result { let cookie = conn.send_request(&x::InternAtom { only_if_exists: false, diff --git a/util/src/settings.rs b/util/src/settings.rs new file mode 100644 index 0000000..2c1b869 --- /dev/null +++ b/util/src/settings.rs @@ -0,0 +1,94 @@ +use anyhow::anyhow; +use std::{fs::File, io::Read, path::PathBuf, time::Duration}; +use toml::Value; + +#[derive(Debug, Clone, Copy)] +pub enum DialogBackend { + Gtk3, +} + +impl DialogBackend { + pub fn binary_name(&self) -> &str { + match self { + Self::Gtk3 => "bscreensaver-dialog-gtk3", + } + } +} + +impl TryFrom<&str> for DialogBackend { + type Error = anyhow::Error; + fn try_from(value: &str) -> Result { + match value { + "gtk3" => Ok(Self::Gtk3), + other => Err(anyhow!("'{}' is not a valid dialog backend (valid: 'gtk3')", other)), + } + } +} + +#[derive(Debug, Clone)] +pub struct Configuration { + pub lock_timeout: Duration, + pub blank_before_locking: Duration, + pub dialog_backend: DialogBackend, + pub new_login_command: Option, +} + +impl Configuration { + pub fn load() -> anyhow::Result { + use humantime::parse_duration; + + let config_tomls = xdg::BaseDirectories::new()? + .find_config_files("bscreensaver/bscreensaver.toml") + .map(|config_path| parse_config_toml(&config_path)) + .collect::, _>>()?; + + let mut config = Configuration::default(); + + for config_toml in config_tomls { + config.lock_timeout = match config_toml.get("lock-timeout") { + None => config.lock_timeout, + Some(val) => parse_duration(val.as_str().ok_or(anyhow!("'lock-timeout' must be a duration string like '10m' or '90s'"))?)?, + }; + config.blank_before_locking = match config_toml.get("blank-before-locking") { + None => config.blank_before_locking, + Some(val) => parse_duration(val.as_str().ok_or(anyhow!("'blank-before-locking' must be a duration string like '10m' or '90s'"))?)?, + }; + config.dialog_backend = match config_toml.get("dialog-backend") { + None => config.dialog_backend, + Some(val) => DialogBackend::try_from(val.as_str().ok_or(anyhow!("'dialog-backend' must be a string"))?)?, + }; + config.new_login_command = match config_toml.get("new-login-command") { + None => config.new_login_command, + Some(val) => val.as_str().map(|s| s.to_string()), + }; + } + + if config.blank_before_locking >= config.lock_timeout { + Err(anyhow!("'blank-before-locking' cannot be greater than 'lock-timeout'")) + } else { + Ok(config) + } + } +} + +fn parse_config_toml(config_path: &PathBuf) -> anyhow::Result { + let mut f = File::open(config_path)?; + let mut config = String::new(); + f.read_to_string(&mut config)?; + drop(f); + + let config_toml = config.parse::()?; + Ok(config_toml) +} + +impl Default for Configuration { + fn default() -> Self { + Self { + lock_timeout: Duration::from_secs(60 * 10), + blank_before_locking: Duration::ZERO, + dialog_backend: DialogBackend::Gtk3, + new_login_command: None, + } + } +} +