The `seq_inhibit` flag toggles whether swayrd disables LRU updates
during window cycling command sequences. When the flag is set to `false`
(the default) windows are locked-in to the LRU as long as they remain
focused long enough. When the flag is `true` any window cycling command
is considered to start a sequence during which no LRU updates are
performed. The sequence ends upon reception of any
non-window-cycling-command (and the window with the focus at that point
in time is immediately locked-in).
---
README.md | 19 +++++++++++++
swayr/src/cmds.rs | 66 +++++++++++++++++++++------------------------
swayr/src/config.rs | 22 ++++++++++++++-
swayr/src/daemon.rs | 20 +++++++++++---
4 files changed, 87 insertions(+), 40 deletions(-)
diff --git a/README.md b/README.md
index 82b6c24..a589ce1 100644
--- a/README.md
@@ -388,6 +388,7 @@ lockin_delay = 750
[misc]
auto_nop_delay = 3000
seq_inhibit = false
```
In the following, all sections are explained.
@@ -534,6 +535,24 @@ A more elegant solution using a key release binding is discussed at the end of
the [Usage](#swayr-usage) section. However, that requires a PR to sway which
has not been merged so far.
The `seq_inhibit` boolean controls how `swayrd` behaves during a _sequence_ of
[window cycling commands](#swayr-cycling-commands).
- When the setting is `true`, `swayrd` will inhibit updates to the window LRU
order while a _sequence_ of window cycling commands is in progress. LRU updates
are reactivated when the _sequence_ ends. A _sequence_ is considered to
have ended when any non-window-cycling-command is received by `swayrd`
(e.g. a `nop` command).
Note: LRU update inhibition also applies to focus changes made outside of
`swayr`, for instance by using sway commands directly.
- When the setting is `false` (the default): `swayrd` will handle focus events
the same way regardless of whether a window cycling sequence is in progress or
not.
Note that the key release binding solution lends itself to using
`seq_inhibit=true`.
### <a id="swayr-version-changes">Version changes</a>
diff --git a/swayr/src/cmds.rs b/swayr/src/cmds.rs
index b830376..a5c8320 100644
--- a/swayr/src/cmds.rs
@@ -287,7 +287,7 @@ impl SwayrCommand {
pub struct ExecSwayrCmdArgs<'a> {
pub cmd: &'a SwayrCommand,
pub focus_data: Option<&'a FocusData>,
pub focus_data: &'a FocusData,
}
impl DisplayFormat for SwayrCommand {
@@ -349,6 +349,7 @@ static SWITCH_TO_MATCHING_DATA: Lazy<Mutex<SwitchToMatchingData>> =
pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
log::info!("Running SwayrCommand {:?}", args.cmd);
let fdata = args.focus_data;
let mut last_command = LAST_COMMAND.lock().expect("Could not lock mutex");
let mut switch_to_matching_data = SWITCH_TO_MATCHING_DATA
@@ -361,12 +362,10 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
switch_to_matching_data.reset(true);
}
let fdata = || args.focus_data.expect("No focus data");
if args.cmd.is_prev_next_window_variant() {
fdata().send(FocusMessage::TickUpdateInhibit);
} else if last_command.is_prev_next_window_variant() {
fdata().send(FocusMessage::TickUpdateActivate);
fdata.send(FocusMessage::TickUpdateInhibit);
} else {
fdata.send(FocusMessage::TickUpdateActivate);
}
match args.cmd {
@@ -380,10 +379,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
switch_to_matching_data.skip_lru = *skip_lru;
switch_to_matching_data.skip_origin = *skip_origin;
switch_to_urgent_or_lru_window(
&mut switch_to_matching_data,
fdata(),
)
switch_to_urgent_or_lru_window(&mut switch_to_matching_data, fdata)
}
SwayrCommand::SwitchToAppOrUrgentOrLRUWindow {
name,
@@ -398,7 +394,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
switch_to_app_or_urgent_or_lru_window(
name,
&mut switch_to_matching_data,
fdata(),
fdata,
)
}
SwayrCommand::SwitchToMarkOrUrgentOrLRUWindow {
@@ -414,7 +410,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
switch_to_mark_or_urgent_or_lru_window(
con_mark,
&mut switch_to_matching_data,
fdata(),
fdata,
)
}
SwayrCommand::SwitchToMatchingOrUrgentOrLRUWindow {
@@ -430,47 +426,45 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
switch_to_matching_or_urgent_or_lru_window(
criteria,
&mut switch_to_matching_data,
fdata(),
fdata,
)
}
SwayrCommand::SwitchWindow => switch_window(fdata()),
SwayrCommand::SwitchWorkspace => switch_workspace(fdata()),
SwayrCommand::SwitchWindow => switch_window(fdata),
SwayrCommand::SwitchWorkspace => switch_workspace(fdata),
SwayrCommand::SwitchOutput => switch_output(),
SwayrCommand::SwitchWorkspaceOrWindow => {
switch_workspace_or_window(fdata())
switch_workspace_or_window(fdata)
}
SwayrCommand::SwitchWorkspaceContainerOrWindow => {
switch_workspace_container_or_window(fdata())
}
SwayrCommand::SwitchTo => switch_to(fdata()),
SwayrCommand::QuitWindow { kill } => quit_window(fdata(), *kill),
SwayrCommand::QuitWorkspaceOrWindow => {
quit_workspace_or_window(fdata())
switch_workspace_container_or_window(fdata)
}
SwayrCommand::SwitchTo => switch_to(fdata),
SwayrCommand::QuitWindow { kill } => quit_window(fdata, *kill),
SwayrCommand::QuitWorkspaceOrWindow => quit_workspace_or_window(fdata),
SwayrCommand::QuitWorkspaceContainerOrWindow => {
quit_workspace_container_or_window(fdata())
quit_workspace_container_or_window(fdata)
}
SwayrCommand::MoveFocusedToWorkspace => {
move_focused_to_workspace(fdata())
move_focused_to_workspace(fdata)
}
SwayrCommand::MoveFocusedTo => move_focused_to(fdata()),
SwayrCommand::SwapFocusedWith => swap_focused_with(fdata()),
SwayrCommand::MoveFocusedTo => move_focused_to(fdata),
SwayrCommand::SwapFocusedWith => swap_focused_with(fdata),
SwayrCommand::NextWindow { windows } => focus_window_in_direction(
Direction::Forward,
windows,
fdata(),
fdata,
always_true,
),
SwayrCommand::PrevWindow { windows } => focus_window_in_direction(
Direction::Backward,
windows,
fdata(),
fdata,
always_true,
),
SwayrCommand::NextTiledWindow { windows } => focus_window_in_direction(
Direction::Forward,
windows,
fdata(),
fdata,
|dn: &t::DisplayNode| {
!dn.node.is_floating()
&& dn.tree.is_child_of_tiled_container(dn.node.id)
@@ -479,7 +473,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
SwayrCommand::PrevTiledWindow { windows } => focus_window_in_direction(
Direction::Backward,
windows,
fdata(),
fdata,
|dn: &t::DisplayNode| {
!dn.node.is_floating()
&& dn.tree.is_child_of_tiled_container(dn.node.id)
@@ -489,7 +483,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
focus_window_in_direction(
Direction::Forward,
windows,
fdata(),
fdata,
|dn: &t::DisplayNode| {
!dn.node.is_floating()
&& dn
@@ -502,7 +496,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
focus_window_in_direction(
Direction::Backward,
windows,
fdata(),
fdata,
|dn: &t::DisplayNode| {
!dn.node.is_floating()
&& dn
@@ -515,7 +509,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
focus_window_in_direction(
Direction::Forward,
windows,
fdata(),
fdata,
|dn: &t::DisplayNode| dn.node.is_floating(),
)
}
@@ -523,7 +517,7 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
focus_window_in_direction(
Direction::Backward,
windows,
fdata(),
fdata,
|dn: &t::DisplayNode| dn.node.is_floating(),
)
}
@@ -531,14 +525,14 @@ pub fn exec_swayr_cmd(args: ExecSwayrCmdArgs) {
focus_window_of_same_layout_in_direction(
Direction::Forward,
windows,
fdata(),
fdata,
)
}
SwayrCommand::PrevWindowOfSameLayout { windows } => {
focus_window_of_same_layout_in_direction(
Direction::Backward,
windows,
fdata(),
fdata,
)
}
SwayrCommand::TileWorkspace { floating } => {
diff --git a/swayr/src/config.rs b/swayr/src/config.rs
index 767bf60..816f972 100644
--- a/swayr/src/config.rs
@@ -60,10 +60,13 @@ pub struct Focus {
lockin_delay: Option<u64>,
}
#[derive(Debug, Serialize, Deserialize, Default)]
#[derive(Debug, Serialize, Deserialize)]
pub struct Misc {
/// Delay after which an automatic Nop command is sent.
auto_nop_delay: Option<u64>,
/// Inhibit LRU updates during sequences of window cycling commands
seq_inhibit: Option<bool>,
}
fn tilde_expand_file_names(file_names: Vec<String>) -> Vec<String> {
@@ -212,6 +215,14 @@ impl Config {
.and_then(|m| m.auto_nop_delay)
.map(Duration::from_millis)
}
pub fn get_misc_seq_inhibit(&self) -> bool {
self.misc
.as_ref()
.and_then(|f| f.seq_inhibit)
.or_else(|| Misc::default().seq_inhibit)
.expect("No misc.seq_inhibit defined.")
}
}
impl Layout {
@@ -329,6 +340,15 @@ impl Default for Focus {
}
}
impl Default for Misc {
fn default() -> Self {
Self {
auto_nop_delay: None,
seq_inhibit: Some(false),
}
}
}
impl Default for Config {
fn default() -> Self {
Config {
diff --git a/swayr/src/daemon.rs b/swayr/src/daemon.rs
index 6be7d8c..50db138 100644
--- a/swayr/src/daemon.rs
@@ -42,6 +42,7 @@ pub fn run_daemon() {
let config = config::load_config();
let lockin_delay = config.get_focus_lockin_delay();
let auto_nop_delay = &config.get_misc_auto_nop_delay();
let seq_inhibit = config.get_misc_seq_inhibit();
{
let fdata = fdata.clone();
@@ -53,7 +54,7 @@ pub fn run_daemon() {
{
let fdata = fdata.clone();
thread::spawn(move || {
focus_lock_in_handler(focus_rx, fdata, lockin_delay);
focus_lock_in_handler(focus_rx, fdata, lockin_delay, seq_inhibit);
});
}
@@ -244,7 +245,7 @@ pub fn serve_client_requests(
log::debug!("Executing auto-nop.");
cmds::exec_swayr_cmd(cmds::ExecSwayrCmdArgs {
cmd: &cmds::SwayrCommand::Nop,
focus_data: Some(&fdata),
focus_data: &fdata,
});
inhibit = true;
}
@@ -287,7 +288,7 @@ fn handle_client_request(mut stream: UnixStream, fdata: &FocusData) {
if let Ok(cmd) = serde_json::from_str::<cmds::SwayrCommand>(&cmd_str) {
cmds::exec_swayr_cmd(cmds::ExecSwayrCmdArgs {
cmd: &cmd,
focus_data: Some(fdata),
focus_data: fdata,
});
} else {
log::error!(
@@ -326,6 +327,7 @@ fn focus_lock_in_handler(
focus_chan: mpsc::Receiver<FocusMessage>,
fdata: FocusData,
lockin_delay: Duration,
seq_inhibit: bool,
) {
// Focus event that has not yet been locked-in to the LRU order
let mut pending_fev: Option<FocusEvent> = None;
@@ -348,6 +350,12 @@ fn focus_lock_in_handler(
};
let mut fev = match fmsg {
FocusMessage::TickUpdateInhibit
| FocusMessage::TickUpdateActivate
if !seq_inhibit =>
{
continue
}
FocusMessage::TickUpdateInhibit => {
inhibit.set();
continue;
@@ -379,6 +387,12 @@ fn focus_lock_in_handler(
};
match fmsg {
FocusMessage::TickUpdateInhibit
| FocusMessage::TickUpdateActivate
if !seq_inhibit =>
{
continue
}
FocusMessage::TickUpdateInhibit => {
// inhibit requested before currently focused container
// was locked-in, set it as pending in case no other
--
2.35.3