Add allow-when-locked=true spawn bind property

This commit is contained in:
Ivan Molodetskikh
2024-04-19 10:49:46 +04:00
parent 0b93c46ce8
commit 914237fa11
5 changed files with 63 additions and 15 deletions
+33 -4
View File
@@ -739,6 +739,7 @@ pub struct Bind {
pub key: Key, pub key: Key,
pub action: Action, pub action: Action,
pub cooldown: Option<Duration>, pub cooldown: Option<Duration>,
pub allow_when_locked: bool,
} }
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
@@ -1564,7 +1565,7 @@ where
&val.literal, &val.literal,
"argument", "argument",
"no arguments expected for this node", "no arguments expected for this node",
)) ));
} }
let key = node let key = node
@@ -1573,6 +1574,8 @@ where
.map_err(|e| DecodeError::conversion(&node.node_name, e.wrap_err("invalid keybind")))?; .map_err(|e| DecodeError::conversion(&node.node_name, e.wrap_err("invalid keybind")))?;
let mut cooldown = None; let mut cooldown = None;
let mut allow_when_locked = false;
let mut allow_when_locked_node = None;
for (name, val) in &node.properties { for (name, val) in &node.properties {
match &***name { match &***name {
"cooldown-ms" => { "cooldown-ms" => {
@@ -1580,6 +1583,10 @@ where
knuffel::traits::DecodeScalar::decode(val, ctx)?, knuffel::traits::DecodeScalar::decode(val, ctx)?,
)); ));
} }
"allow-when-locked" => {
allow_when_locked = knuffel::traits::DecodeScalar::decode(val, ctx)?;
allow_when_locked_node = Some(name);
}
name_str => { name_str => {
ctx.emit_error(DecodeError::unexpected( ctx.emit_error(DecodeError::unexpected(
name, name,
@@ -1599,6 +1606,7 @@ where
key, key,
action: Action::Spawn(vec![]), action: Action::Spawn(vec![]),
cooldown: None, cooldown: None,
allow_when_locked: false,
}; };
if let Some(child) = children.next() { if let Some(child) = children.next() {
@@ -1610,11 +1618,24 @@ where
)); ));
} }
match Action::decode_node(child, ctx) { match Action::decode_node(child, ctx) {
Ok(action) => Ok(Self { Ok(action) => {
if !matches!(action, Action::Spawn(_)) {
if let Some(node) = allow_when_locked_node {
ctx.emit_error(DecodeError::unexpected(
node,
"property",
"allow-when-locked can only be set on spawn binds",
));
}
}
Ok(Self {
key, key,
action, action,
cooldown, cooldown,
}), allow_when_locked,
})
}
Err(e) => { Err(e) => {
ctx.emit_error(e); ctx.emit_error(e);
Ok(dummy) Ok(dummy)
@@ -1922,7 +1943,7 @@ mod tests {
} }
binds { binds {
Mod+T { spawn "alacritty"; } Mod+T allow-when-locked=true { spawn "alacritty"; }
Mod+Q { close-window; } Mod+Q { close-window; }
Mod+Shift+H { focus-monitor-left; } Mod+Shift+H { focus-monitor-left; }
Mod+Ctrl+Shift+L { move-window-to-monitor-right; } Mod+Ctrl+Shift+L { move-window-to-monitor-right; }
@@ -2131,6 +2152,7 @@ mod tests {
}, },
action: Action::Spawn(vec!["alacritty".to_owned()]), action: Action::Spawn(vec!["alacritty".to_owned()]),
cooldown: None, cooldown: None,
allow_when_locked: true,
}, },
Bind { Bind {
key: Key { key: Key {
@@ -2139,6 +2161,7 @@ mod tests {
}, },
action: Action::CloseWindow, action: Action::CloseWindow,
cooldown: None, cooldown: None,
allow_when_locked: false,
}, },
Bind { Bind {
key: Key { key: Key {
@@ -2147,6 +2170,7 @@ mod tests {
}, },
action: Action::FocusMonitorLeft, action: Action::FocusMonitorLeft,
cooldown: None, cooldown: None,
allow_when_locked: false,
}, },
Bind { Bind {
key: Key { key: Key {
@@ -2155,6 +2179,7 @@ mod tests {
}, },
action: Action::MoveWindowToMonitorRight, action: Action::MoveWindowToMonitorRight,
cooldown: None, cooldown: None,
allow_when_locked: false,
}, },
Bind { Bind {
key: Key { key: Key {
@@ -2163,6 +2188,7 @@ mod tests {
}, },
action: Action::ConsumeWindowIntoColumn, action: Action::ConsumeWindowIntoColumn,
cooldown: None, cooldown: None,
allow_when_locked: false,
}, },
Bind { Bind {
key: Key { key: Key {
@@ -2171,6 +2197,7 @@ mod tests {
}, },
action: Action::FocusWorkspace(1), action: Action::FocusWorkspace(1),
cooldown: None, cooldown: None,
allow_when_locked: false,
}, },
Bind { Bind {
key: Key { key: Key {
@@ -2179,6 +2206,7 @@ mod tests {
}, },
action: Action::Quit(true), action: Action::Quit(true),
cooldown: None, cooldown: None,
allow_when_locked: false,
}, },
Bind { Bind {
key: Key { key: Key {
@@ -2187,6 +2215,7 @@ mod tests {
}, },
action: Action::FocusWorkspaceDown, action: Action::FocusWorkspaceDown,
cooldown: Some(Duration::from_millis(150)), cooldown: Some(Duration::from_millis(150)),
allow_when_locked: false,
}, },
]), ]),
debug: DebugConfig { debug: DebugConfig {
+4 -2
View File
@@ -263,8 +263,10 @@ binds {
// Mod+T { spawn "bash" "-c" "notify-send hello && exec alacritty"; } // Mod+T { spawn "bash" "-c" "notify-send hello && exec alacritty"; }
// Example volume keys mappings for PipeWire & WirePlumber. // Example volume keys mappings for PipeWire & WirePlumber.
XF86AudioRaiseVolume { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1+"; } // The allow-when-locked=true property makes them work even when the session is locked.
XF86AudioLowerVolume { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1-"; } XF86AudioRaiseVolume allow-when-locked=true { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1+"; }
XF86AudioLowerVolume allow-when-locked=true { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1-"; }
XF86AudioMute allow-when-locked=true { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; }
Mod+Q { close-window; } Mod+Q { close-window; }
+13 -5
View File
@@ -297,12 +297,12 @@ impl State {
pub fn handle_bind(&mut self, bind: Bind) { pub fn handle_bind(&mut self, bind: Bind) {
let Some(cooldown) = bind.cooldown else { let Some(cooldown) = bind.cooldown else {
self.do_action(bind.action); self.do_action(bind.action, bind.allow_when_locked);
return; return;
}; };
// Check this first so that it doesn't trigger the cooldown. // Check this first so that it doesn't trigger the cooldown.
if self.niri.is_locked() && !allowed_when_locked(&bind.action) { if self.niri.is_locked() && !(bind.allow_when_locked || allowed_when_locked(&bind.action)) {
return; return;
} }
@@ -323,13 +323,13 @@ impl State {
.unwrap(); .unwrap();
entry.insert(token); entry.insert(token);
self.do_action(bind.action); self.do_action(bind.action, bind.allow_when_locked);
} }
} }
} }
pub fn do_action(&mut self, action: Action) { pub fn do_action(&mut self, action: Action, allow_when_locked: bool) {
if self.niri.is_locked() && !allowed_when_locked(&action) { if self.niri.is_locked() && !(allow_when_locked || allowed_when_locked(&action)) {
return; return;
} }
@@ -1844,6 +1844,7 @@ fn should_intercept_key(
}, },
action, action,
cooldown: None, cooldown: None,
allow_when_locked: false,
}); });
} }
} }
@@ -1892,6 +1893,7 @@ fn find_bind(
}, },
action, action,
cooldown: None, cooldown: None,
allow_when_locked: false,
}); });
} }
@@ -2174,6 +2176,7 @@ mod tests {
}, },
action: Action::CloseWindow, action: Action::CloseWindow,
cooldown: None, cooldown: None,
allow_when_locked: false,
}]); }]);
let comp_mod = CompositorMod::Super; let comp_mod = CompositorMod::Super;
@@ -2306,6 +2309,7 @@ mod tests {
}, },
action: Action::CloseWindow, action: Action::CloseWindow,
cooldown: None, cooldown: None,
allow_when_locked: false,
}, },
Bind { Bind {
key: Key { key: Key {
@@ -2314,6 +2318,7 @@ mod tests {
}, },
action: Action::FocusColumnLeft, action: Action::FocusColumnLeft,
cooldown: None, cooldown: None,
allow_when_locked: false,
}, },
Bind { Bind {
key: Key { key: Key {
@@ -2322,6 +2327,7 @@ mod tests {
}, },
action: Action::FocusWindowDown, action: Action::FocusWindowDown,
cooldown: None, cooldown: None,
allow_when_locked: false,
}, },
Bind { Bind {
key: Key { key: Key {
@@ -2330,6 +2336,7 @@ mod tests {
}, },
action: Action::FocusWindowUp, action: Action::FocusWindowUp,
cooldown: None, cooldown: None,
allow_when_locked: false,
}, },
Bind { Bind {
key: Key { key: Key {
@@ -2338,6 +2345,7 @@ mod tests {
}, },
action: Action::FocusColumnRight, action: Action::FocusColumnRight,
cooldown: None, cooldown: None,
allow_when_locked: false,
}, },
]); ]);
+1 -1
View File
@@ -156,7 +156,7 @@ fn process(ctx: &ClientCtx, buf: &str) -> anyhow::Result<Response> {
Request::Action(action) => { Request::Action(action) => {
let action = niri_config::Action::from(action); let action = niri_config::Action::from(action);
ctx.event_loop.insert_idle(move |state| { ctx.event_loop.insert_idle(move |state| {
state.do_action(action); state.do_action(action, false);
}); });
Response::Handled Response::Handled
} }
+9
View File
@@ -113,6 +113,15 @@ binds {
} }
``` ```
Spawn bindings have a special `allow-when-locked=true` property that makes them work even while the session is locked:
```
binds {
// This mute bind will work even when the session is locked.
XF86AudioMute allow-when-locked=true { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; }
}
```
Currently, niri *does not* use a shell to run commands, which means that you need to manually separate arguments. Currently, niri *does not* use a shell to run commands, which means that you need to manually separate arguments.
``` ```