diff --git a/src/gui.rs b/src/gui.rs index 80ca088..7a56a0a 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1633,20 +1633,40 @@ impl App { let profile_path = self.path.clone(); let allow = self.allow_layout; // Compile the profile's window_match patterns once, outside the - // poll loop. If a pattern is malformed we treat it as "not - // configured" rather than crashing the auto-apply thread. + // poll loop. Malformed patterns are logged as a warning rather + // than silently treated as "no pattern" — the latter would make + // a typo in the YAML fall back to firing on ANY client, which + // is the exact bug we fixed in 7c94417. let class_pat = self .profile .window_match .class .as_deref() - .and_then(|p| regex::Regex::new(p).ok()); + .and_then(|p| match regex::Regex::new(p) { + Ok(re) => Some(re), + Err(e) => { + tracing::warn!( + "arm_auto_apply: invalid window_match.class regex {:?}: {}", + p, e + ); + None + } + }); let title_pat = self .profile .window_match .title .as_deref() - .and_then(|p| regex::Regex::new(p).ok()); + .and_then(|p| match regex::Regex::new(p) { + Ok(re) => Some(re), + Err(e) => { + tracing::warn!( + "arm_auto_apply: invalid window_match.title regex {:?}: {}", + p, e + ); + None + } + }); let any_pattern = class_pat.is_some() || title_pat.is_some(); std::thread::Builder::new() .name("enboxer-auto-apply".into()) diff --git a/src/session.rs b/src/session.rs index 9527ee3..5a9bbf6 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1022,7 +1022,20 @@ async fn execute(actions: Vec, slots: &[(u32, Client)]) -> Result<()> { }; for id in ids { if let Some((_, c)) = slots.iter().find(|(s, _)| *s == id) { - hypr::deliver_key(c, &key, parsed_state).await?; + // Per-slot failures must NOT abort the rest of the + // chain. For example, a smart_interact (CTM on -> Alt+J + // -> sleep -> CTM off) must keep going through every + // captured slot even if one wlr-keyboard barf means + // Alt+J never lands on that client — otherwise CTM + // can stay on for the survivors and the user has to + // manually reset it. + if let Err(e) = + hypr::deliver_key(c, &key, parsed_state).await + { + tracing::warn!( + "deliver_key slot {id} key {key:?} failed: {e}" + ); + } } } }