srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/core/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/core/src')
-rw-r--r--crates/core/src/lib.rs1
-rw-r--r--crates/core/src/manager/lock.rs34
-rw-r--r--crates/core/src/manager/mod.rs29
3 files changed, 63 insertions, 1 deletions
diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs
index e9d31a5..9a2c3bc 100644
--- a/crates/core/src/lib.rs
+++ b/crates/core/src/lib.rs
@@ -19,6 +19,7 @@ pub use layout::{Layout, MasterStackLayout, NoOpLayout, TilingConfig};
pub use lock_config::LockConfig;
pub use manager::{CaptureRequest, ColorFilter, Direction, WindowManager};
pub use monitor::{Monitor, MonitorId};
+pub use manager::KeyBinding;
pub use placement::{centered_in, PlacementConfig, SmartPlacement, SnapZoneKind, MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH, SNAP_FLYOUT_EDGE};
pub use regex::Regex;
pub use rules::{WindowMatch, WindowRule, WindowRuleActions};
diff --git a/crates/core/src/manager/lock.rs b/crates/core/src/manager/lock.rs
index 15c0a9f..ecea5fe 100644
--- a/crates/core/src/manager/lock.rs
+++ b/crates/core/src/manager/lock.rs
@@ -52,6 +52,18 @@ impl WindowManager {
std::mem::take(&mut self.refresh_requested)
}
+ /// Records the combos the backend was given at startup, so
+ /// `KeyBinding::grabbed` can be answered. Called once, from `main.rs`,
+ /// right where that same list is handed to the platform.
+ pub fn set_grabbed_keys(&mut self, combos: &[String]) {
+ self.grabbed_keys = combos.iter().cloned().collect();
+ }
+
+ /// Whether `combo` is one the backend actually grabs.
+ pub fn is_grabbed(&self, combo: &str) -> bool {
+ self.grabbed_keys.contains(combo)
+ }
+
/// Records that `key` was set live to `value_json`. See
/// `live_settings`' own doc comment.
///
@@ -83,6 +95,28 @@ mod tests {
}
#[test]
+ fn only_the_combos_handed_to_the_backend_count_as_grabbed() {
+ // The whole point of the flag: a binding added after startup is
+ // registered by the config engine but never grabbed, so pressing it
+ // goes to the focused client instead.
+ let mut wm = WindowManager::new();
+ assert!(!wm.is_grabbed("Mod4+Return"), "nothing grabbed before startup records a set");
+ wm.set_grabbed_keys(&["Mod4+Return".to_string(), "Ctrl+Mod4+l".to_string()]);
+ assert!(wm.is_grabbed("Mod4+Return"));
+ assert!(wm.is_grabbed("Ctrl+Mod4+l"));
+ assert!(!wm.is_grabbed("Ctrl+Shift+Mod4+F9"), "added since startup: bound, not grabbed");
+ }
+
+ #[test]
+ fn recording_the_grabbed_set_again_replaces_it_rather_than_accumulating() {
+ let mut wm = WindowManager::new();
+ wm.set_grabbed_keys(&["Mod4+a".to_string()]);
+ wm.set_grabbed_keys(&["Mod4+b".to_string()]);
+ assert!(!wm.is_grabbed("Mod4+a"), "the previous set must not linger");
+ assert!(wm.is_grabbed("Mod4+b"));
+ }
+
+ #[test]
fn drain_refresh_request_is_true_once_then_false() {
let mut wm = WindowManager::new();
assert!(!wm.drain_refresh_request(), "nothing requested yet");
diff --git a/crates/core/src/manager/mod.rs b/crates/core/src/manager/mod.rs
index a225220..64cf5c3 100644
--- a/crates/core/src/manager/mod.rs
+++ b/crates/core/src/manager/mod.rs
@@ -85,6 +85,29 @@ struct ResizeState {
/// state and layout policy. Backends (X11, Wayland, ...) drive this via
/// `add_window`/`remove_window`/input events, and apply the `Rect`s it
/// computes back onto real surfaces.
+/// One key binding, as reported by `srd keybindings`.
+#[derive(Debug, Clone)]
+pub struct KeyBinding {
+ /// Canonical form (`"Ctrl+Mod4+l"`), which is what a real keypress is
+ /// matched against - not necessarily how it was written in the config.
+ pub combo: String,
+ /// `srd.bind`'s optional third argument, empty when it gave none.
+ pub description: String,
+ /// Whether the compositor actually intercepts this key.
+ ///
+ /// `main.rs` hands the backend one combo list, once, before connecting:
+ /// the X11 backend turns it into `XGrabKey` calls and the Wayland one
+ /// into its intercept set. A reload re-registers the *actions* but
+ /// cannot re-register the grabs, so a combination added to the config
+ /// since startup is bound as far as the config engine is concerned and
+ /// still goes straight to the focused client when pressed.
+ ///
+ /// Reported here so a launcher or cheat-sheet can say so rather than
+ /// listing a shortcut that silently does nothing - which is exactly
+ /// the failure this field exists to make visible.
+ pub grabbed: bool,
+}
+
pub struct WindowManager {
windows: HashMap<WindowId, Window>,
order: Vec<WindowId>,
@@ -449,7 +472,10 @@ pub struct WindowManager {
/// Asked for as whether "our bindings show in ags's launcher": they
/// could not, because nothing published them anywhere a client could
/// read.
- pub keybindings: Vec<(String, String)>,
+ pub keybindings: Vec<KeyBinding>,
+ /// The exact combo list handed to the backend at startup, which is the
+ /// only set it ever grabs - see `KeyBinding::grabbed`.
+ grabbed_keys: std::collections::HashSet<String>,
/// Set by `request_refresh`, drained by the main loop. Same
/// cross-boundary queued-request shape as `lock_requested`.
refresh_requested: bool,
@@ -640,6 +666,7 @@ impl WindowManager {
theme: ThemeConfig::default(),
lock: LockConfig::default(),
keybindings: Vec::new(),
+ grabbed_keys: std::collections::HashSet::new(),
maximize_covers_dock: true,
refresh_requested: false,
live_settings: std::collections::BTreeMap::new(),