improve key handler construction

This commit is contained in:
Alexander Mohr 2025-07-13 01:09:36 +02:00
parent b63b02830a
commit 3d9d5689c7
5 changed files with 58 additions and 54 deletions

1
Cargo.lock generated
View file

@ -2923,6 +2923,7 @@ dependencies = [
name = "worf-warden" name = "worf-warden"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap",
"env_logger", "env_logger",
"log", "log",
"serde", "serde",

View file

@ -8,4 +8,4 @@ worf = {path = "../../worf"}
env_logger = "0.11.8" env_logger = "0.11.8"
log = "0.4.27" log = "0.4.27"
serde = { version = "1.0.219", features = ["derive"] } serde = { version = "1.0.219", features = ["derive"] }
clap = { version = "4.5.40", features = ["derive"] }

View file

@ -1,3 +1,4 @@
use clap::Parser;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
collections::HashMap, collections::HashMap,
@ -395,19 +396,28 @@ struct WardenConfig {
custom_auto_types: HashMap<String, String>, custom_auto_types: HashMap<String, String>,
} }
#[derive(Debug, Parser, Clone)]
struct WardenArgs {
/// Configuration file for worf warden
#[clap(long = "warden-config")]
warden_config: Option<String>,
#[command(flatten)]
worf: Config,
}
fn main() -> Result<(), String> { fn main() -> Result<(), String> {
env_logger::Builder::new() env_logger::Builder::new()
.parse_filters(&env::var("RUST_LOG").unwrap_or_else(|_| "error".to_owned())) .parse_filters(&env::var("RUST_LOG").unwrap_or_else(|_| "error".to_owned()))
.format_timestamp_micros() .format_timestamp_micros()
.init(); .init();
let args = config::parse_args(); let mut cfg = WardenArgs::parse();
let worf_config = Arc::new(RwLock::new( cfg.worf = config::load_worf_config(Some(&cfg.worf)).unwrap_or(cfg.worf);
config::load_worf_config(Some(&args)).unwrap_or(args.clone()),
));
let warden_config: WardenConfig = config::load_config(Some(&args), "worf", "warden") let warden_config: WardenConfig =
.map_err(|e| format!("failed to parse warden config {e}"))?; config::load_config(cfg.warden_config.as_deref(), "worf", "warden")
.map_err(|e| format!("failed to parse warden config {e}"))?;
if !groups().contains("input") { if !groups().contains("input") {
log::error!( log::error!(
@ -421,6 +431,8 @@ fn main() -> Result<(), String> {
log::error!("Failed to start ydotool daemon: {e}"); 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 // todo eventually use a propper rust client for this, for now rbw is good enough
let provider = Arc::new(Mutex::new(PasswordProvider::new( let provider = Arc::new(Mutex::new(PasswordProvider::new(
&worf_config.read().unwrap(), &worf_config.read().unwrap(),

View file

@ -945,13 +945,16 @@ fn style_path(full_path: Option<&String>) -> Result<PathBuf, Error> {
vec![dirs::config_dir()], vec![dirs::config_dir()],
&PathBuf::from("worf").join("style.css"), &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 /// # Errors
/// ///
/// Will return Err when it cannot resolve any path or no style is found /// 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<PathBuf, Error> { pub fn conf_path(full_path: Option<&str>, folder: &str, name: &str) -> Result<PathBuf, Error> {
let alternative_paths = let alternative_paths =
path_alternatives(vec![dirs::config_dir()], &PathBuf::from(folder).join(name)); path_alternatives(vec![dirs::config_dir()], &PathBuf::from(folder).join(name));
resolve_path(full_path, alternative_paths.into_iter().collect()) resolve_path(full_path, alternative_paths.into_iter().collect())
@ -971,10 +974,7 @@ pub fn path_alternatives(base_paths: Vec<Option<PathBuf>>, sub_path: &PathBuf) -
/// # Errors /// # Errors
/// ///
/// Will return `Err` if it is not able to find any valid path /// Will return `Err` if it is not able to find any valid path
pub fn resolve_path( pub fn resolve_path(full_path: Option<&str>, alternatives: Vec<PathBuf>) -> Result<PathBuf, Error> {
full_path: Option<&String>,
alternatives: Vec<PathBuf>,
) -> Result<PathBuf, Error> {
log::debug!("resolving path for {full_path:?}, with alternatives: {alternatives:?}"); log::debug!("resolving path for {full_path:?}, with alternatives: {alternatives:?}");
full_path full_path
.map(PathBuf::from) .map(PathBuf::from)
@ -988,6 +988,7 @@ pub fn resolve_path(
.ok_or(Error::MissingFile) .ok_or(Error::MissingFile)
} }
/// Load the worf config from disk
/// # Errors /// # Errors
/// ///
/// Will return Err when it /// Will return Err when it
@ -996,7 +997,11 @@ pub fn resolve_path(
/// * no config file exists /// * no config file exists
/// * config file and args cannot be merged /// * config file and args cannot be merged
pub fn load_worf_config(args_opt: Option<&Config>) -> Result<Config, Error> { pub fn load_worf_config(args_opt: Option<&Config>) -> Result<Config, Error> {
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 { if let Some(args) = args_opt {
let merge_result = merge_config_with_args(&mut config, args) let merge_result = merge_config_with_args(&mut config, args)
.map_err(|e| Error::ParsingError(format!("{e}")))?; .map_err(|e| Error::ParsingError(format!("{e}")))?;
@ -1006,6 +1011,7 @@ pub fn load_worf_config(args_opt: Option<&Config>) -> Result<Config, Error> {
} }
} }
/// Load any config from disk
/// # Errors /// # Errors
/// ///
/// Will return Err when it /// Will return Err when it
@ -1014,15 +1020,11 @@ pub fn load_worf_config(args_opt: Option<&Config>) -> Result<Config, Error> {
/// * no config file exists /// * no config file exists
/// * config file and args cannot be merged /// * config file and args cannot be merged
pub fn load_config<T: DeserializeOwned>( pub fn load_config<T: DeserializeOwned>(
args_opt: Option<&Config>, path: Option<&str>,
folder: &str, folder: &str,
name: &str, name: &str,
) -> Result<T, Error> { ) -> Result<T, Error> {
let config_path = conf_path( let config_path = conf_path(path, folder, name);
args_opt.as_ref().and_then(|c| c.cfg_path.as_ref()),
folder,
name,
);
match config_path { match config_path {
Ok(path) => { Ok(path) => {
log::debug!("loading config from {}", path.display()); log::debug!("loading config from {}", path.display());

View file

@ -984,42 +984,31 @@ fn setup_key_event_handler<T: Clone + 'static + Send>(
meta: &Rc<MetaData<T>>, meta: &Rc<MetaData<T>>,
custom_keys: Option<&CustomKeys>, custom_keys: Option<&CustomKeys>,
) { ) {
// handle keys as soon as possible fn connect_key_handler<
// Remove old handler, use only one for both window and search T: gtk4::prelude::ObjectExt + Clone + 'static + WidgetExt,
let key_controller_window = EventControllerKey::new(); Menu: Clone + 'static + Send,
key_controller_window.set_propagation_phase(gtk4::PropagationPhase::Capture); >(
let ui_clone = Rc::clone(ui_elements); widget: &T,
let meta_clone = Rc::clone(meta); ui: &Rc<UiElements<Menu>>,
let keys_clone = custom_keys.cloned(); meta: &Rc<MetaData<Menu>>,
key_controller_window.connect_key_pressed(move |_, key_value, key_code, modifier| { keys: Option<CustomKeys>,
handle_key_press( ) {
&ui_clone, let controller = EventControllerKey::new();
&meta_clone, controller.set_propagation_phase(gtk4::PropagationPhase::Capture);
key_value,
key_code,
modifier,
keys_clone.as_ref(),
)
});
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(); // Setup window controller
key_controller_search.set_propagation_phase(gtk4::PropagationPhase::Capture); connect_key_handler(&ui_elements.window, ui_elements, meta, custom_keys.cloned());
let ui_clone2 = Rc::clone(ui_elements);
let meta_clone2 = Rc::clone(meta); // Setup search controller
let keys_clone2 = custom_keys.cloned(); connect_key_handler(&ui_elements.search, ui_elements, meta, 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);
} }
fn is_key_match( fn is_key_match(