From 3d9d5689c711a274d89b6389018b12cc37d4829e Mon Sep 17 00:00:00 2001 From: Alexander Mohr Date: Sun, 13 Jul 2025 01:09:36 +0200 Subject: [PATCH] improve key handler construction --- Cargo.lock | 1 + examples/worf-warden/Cargo.toml | 2 +- examples/worf-warden/src/main.rs | 24 ++++++++++---- worf/src/lib/config.rs | 28 ++++++++-------- worf/src/lib/gui.rs | 57 +++++++++++++------------------- 5 files changed, 58 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 081c27a..4daf2d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2923,6 +2923,7 @@ dependencies = [ name = "worf-warden" version = "0.1.0" dependencies = [ + "clap", "env_logger", "log", "serde", diff --git a/examples/worf-warden/Cargo.toml b/examples/worf-warden/Cargo.toml index 02f88f1..8f57a8a 100644 --- a/examples/worf-warden/Cargo.toml +++ b/examples/worf-warden/Cargo.toml @@ -8,4 +8,4 @@ worf = {path = "../../worf"} env_logger = "0.11.8" log = "0.4.27" serde = { version = "1.0.219", features = ["derive"] } - +clap = { version = "4.5.40", features = ["derive"] } diff --git a/examples/worf-warden/src/main.rs b/examples/worf-warden/src/main.rs index 1cfbc15..d47b63a 100644 --- a/examples/worf-warden/src/main.rs +++ b/examples/worf-warden/src/main.rs @@ -1,3 +1,4 @@ +use clap::Parser; use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, @@ -395,19 +396,28 @@ struct WardenConfig { custom_auto_types: HashMap, } +#[derive(Debug, Parser, Clone)] +struct WardenArgs { + /// Configuration file for worf warden + #[clap(long = "warden-config")] + warden_config: Option, + + #[command(flatten)] + worf: Config, +} + fn main() -> Result<(), String> { env_logger::Builder::new() .parse_filters(&env::var("RUST_LOG").unwrap_or_else(|_| "error".to_owned())) .format_timestamp_micros() .init(); - let args = config::parse_args(); - let worf_config = Arc::new(RwLock::new( - config::load_worf_config(Some(&args)).unwrap_or(args.clone()), - )); + let mut cfg = WardenArgs::parse(); + cfg.worf = config::load_worf_config(Some(&cfg.worf)).unwrap_or(cfg.worf); - let warden_config: WardenConfig = config::load_config(Some(&args), "worf", "warden") - .map_err(|e| format!("failed to parse warden config {e}"))?; + let warden_config: WardenConfig = + config::load_config(cfg.warden_config.as_deref(), "worf", "warden") + .map_err(|e| format!("failed to parse warden config {e}"))?; if !groups().contains("input") { log::error!( @@ -421,6 +431,8 @@ fn main() -> Result<(), String> { log::error!("Failed to start ydotool daemon: {e}"); } + let worf_config = Arc::new(RwLock::new(cfg.worf.clone())); + // todo eventually use a propper rust client for this, for now rbw is good enough let provider = Arc::new(Mutex::new(PasswordProvider::new( &worf_config.read().unwrap(), diff --git a/worf/src/lib/config.rs b/worf/src/lib/config.rs index a0ba267..73de12e 100644 --- a/worf/src/lib/config.rs +++ b/worf/src/lib/config.rs @@ -945,13 +945,16 @@ fn style_path(full_path: Option<&String>) -> Result { vec![dirs::config_dir()], &PathBuf::from("worf").join("style.css"), ); - resolve_path(full_path, alternative_paths.into_iter().collect()) + resolve_path( + full_path.map(std::string::String::as_str), + alternative_paths.into_iter().collect(), + ) } /// # Errors /// /// Will return Err when it cannot resolve any path or no style is found -pub fn conf_path(full_path: Option<&String>, folder: &str, name: &str) -> Result { +pub fn conf_path(full_path: Option<&str>, folder: &str, name: &str) -> Result { let alternative_paths = path_alternatives(vec![dirs::config_dir()], &PathBuf::from(folder).join(name)); resolve_path(full_path, alternative_paths.into_iter().collect()) @@ -971,10 +974,7 @@ pub fn path_alternatives(base_paths: Vec>, sub_path: &PathBuf) - /// # Errors /// /// Will return `Err` if it is not able to find any valid path -pub fn resolve_path( - full_path: Option<&String>, - alternatives: Vec, -) -> Result { +pub fn resolve_path(full_path: Option<&str>, alternatives: Vec) -> Result { log::debug!("resolving path for {full_path:?}, with alternatives: {alternatives:?}"); full_path .map(PathBuf::from) @@ -988,6 +988,7 @@ pub fn resolve_path( .ok_or(Error::MissingFile) } +/// Load the worf config from disk /// # Errors /// /// Will return Err when it @@ -996,7 +997,11 @@ pub fn resolve_path( /// * no config file exists /// * config file and args cannot be merged pub fn load_worf_config(args_opt: Option<&Config>) -> Result { - let mut config = load_config(args_opt, "worf", "config")?; + let mut config = load_config( + args_opt.as_ref().and_then(|c| c.cfg_path.as_deref()), + "worf", + "config", + )?; if let Some(args) = args_opt { let merge_result = merge_config_with_args(&mut config, args) .map_err(|e| Error::ParsingError(format!("{e}")))?; @@ -1006,6 +1011,7 @@ pub fn load_worf_config(args_opt: Option<&Config>) -> Result { } } +/// Load any config from disk /// # Errors /// /// Will return Err when it @@ -1014,15 +1020,11 @@ pub fn load_worf_config(args_opt: Option<&Config>) -> Result { /// * no config file exists /// * config file and args cannot be merged pub fn load_config( - args_opt: Option<&Config>, + path: Option<&str>, folder: &str, name: &str, ) -> Result { - let config_path = conf_path( - args_opt.as_ref().and_then(|c| c.cfg_path.as_ref()), - folder, - name, - ); + let config_path = conf_path(path, folder, name); match config_path { Ok(path) => { log::debug!("loading config from {}", path.display()); diff --git a/worf/src/lib/gui.rs b/worf/src/lib/gui.rs index ad621c4..00fc8b0 100644 --- a/worf/src/lib/gui.rs +++ b/worf/src/lib/gui.rs @@ -984,42 +984,31 @@ fn setup_key_event_handler( meta: &Rc>, custom_keys: Option<&CustomKeys>, ) { - // handle keys as soon as possible - // Remove old handler, use only one for both window and search - let key_controller_window = EventControllerKey::new(); - key_controller_window.set_propagation_phase(gtk4::PropagationPhase::Capture); - let ui_clone = Rc::clone(ui_elements); - let meta_clone = Rc::clone(meta); - let keys_clone = custom_keys.cloned(); - key_controller_window.connect_key_pressed(move |_, key_value, key_code, modifier| { - handle_key_press( - &ui_clone, - &meta_clone, - key_value, - key_code, - modifier, - keys_clone.as_ref(), - ) - }); + fn connect_key_handler< + T: gtk4::prelude::ObjectExt + Clone + 'static + WidgetExt, + Menu: Clone + 'static + Send, + >( + widget: &T, + ui: &Rc>, + meta: &Rc>, + keys: Option, + ) { + let controller = EventControllerKey::new(); + controller.set_propagation_phase(gtk4::PropagationPhase::Capture); - ui_elements.window.add_controller(key_controller_window); + let ui = Rc::clone(ui); + let meta = Rc::clone(meta); + controller.connect_key_pressed(move |_, key_value, key_code, modifier| { + handle_key_press(&ui, &meta, key_value, key_code, modifier, keys.as_ref()) + }); + widget.add_controller(controller.clone()); + } - let key_controller_search = EventControllerKey::new(); - key_controller_search.set_propagation_phase(gtk4::PropagationPhase::Capture); - let ui_clone2 = Rc::clone(ui_elements); - let meta_clone2 = Rc::clone(meta); - let keys_clone2 = custom_keys.cloned(); - key_controller_search.connect_key_pressed(move |_, key_value, key_code, modifier| { - handle_key_press( - &ui_clone2, - &meta_clone2, - key_value, - key_code, - modifier, - keys_clone2.as_ref(), - ) - }); - ui_elements.search.add_controller(key_controller_search); + // Setup window controller + connect_key_handler(&ui_elements.window, ui_elements, meta, custom_keys.cloned()); + + // Setup search controller + connect_key_handler(&ui_elements.search, ui_elements, meta, custom_keys.cloned()); } fn is_key_match(