diff options
| author | TheAngusMcFire <43189215+TheAngusMcFire@users.noreply.github.com> | 2024-07-05 06:55:04 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-05 04:55:04 +0000 |
| commit | a56e4ff436cc4f36d7cda89e985d51e37f0b4f78 (patch) | |
| tree | 30b5b4b5385173c72042d64ec73660b9f85098d2 | |
| parent | 9dcc9160b3b4be6c44672e8579e1e7107453c8b7 (diff) | |
| download | niri-a56e4ff436cc4f36d7cda89e985d51e37f0b4f78.tar.gz niri-a56e4ff436cc4f36d7cda89e985d51e37f0b4f78.tar.bz2 niri-a56e4ff436cc4f36d7cda89e985d51e37f0b4f78.zip | |
Added Commnads to focus windows or Monitors above/below the active window (#497)
* Implement focus-window-up/down-or-monitor calls
* Fixed wrong naming of focus-window-or-monitor commands
* fix copy pase errors for focusing direction
* Fixed wrong behaviour when the current workspace is empty
* Cleanup navigation code to reduce complexity
* Fix wrong comments and add testcases for FocusWindowOrMonitorUp/Down
---------
Co-authored-by: Christian Rieger <christian.rieger@student.tugraz.at>
| -rw-r--r-- | niri-config/src/lib.rs | 4 | ||||
| -rw-r--r-- | niri-ipc/src/lib.rs | 4 | ||||
| -rw-r--r-- | src/input/mod.rs | 34 | ||||
| -rw-r--r-- | src/layout/mod.rs | 59 |
4 files changed, 101 insertions, 0 deletions
diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index 1d2bfc63..39d78522 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -949,6 +949,8 @@ pub enum Action { FocusColumnLast, FocusColumnRightOrFirst, FocusColumnLeftOrLast, + FocusWindowOrMonitorUp, + FocusWindowOrMonitorDown, FocusColumnOrMonitorLeft, FocusColumnOrMonitorRight, FocusWindowDown, @@ -1027,6 +1029,8 @@ impl From<niri_ipc::Action> for Action { niri_ipc::Action::FocusColumnLast => Self::FocusColumnLast, niri_ipc::Action::FocusColumnRightOrFirst => Self::FocusColumnRightOrFirst, niri_ipc::Action::FocusColumnLeftOrLast => Self::FocusColumnLeftOrLast, + niri_ipc::Action::FocusWindowOrMonitorUp => Self::FocusWindowOrMonitorUp, + niri_ipc::Action::FocusWindowOrMonitorDown => Self::FocusWindowOrMonitorDown, niri_ipc::Action::FocusColumnOrMonitorLeft => Self::FocusColumnOrMonitorLeft, niri_ipc::Action::FocusColumnOrMonitorRight => Self::FocusColumnOrMonitorRight, niri_ipc::Action::FocusWindowDown => Self::FocusWindowDown, diff --git a/niri-ipc/src/lib.rs b/niri-ipc/src/lib.rs index 572b4a83..931898bd 100644 --- a/niri-ipc/src/lib.rs +++ b/niri-ipc/src/lib.rs @@ -120,6 +120,10 @@ pub enum Action { FocusColumnRightOrFirst, /// Focus the next column to the left, looping if at start. FocusColumnLeftOrLast, + /// Focus the window or the monitor above. + FocusWindowOrMonitorUp, + /// Focus the window or the monitor below. + FocusWindowOrMonitorDown, /// Focus the column or the monitor to the left. FocusColumnOrMonitorLeft, /// Focus the column or the monitor to the right. diff --git a/src/input/mod.rs b/src/input/mod.rs index 5e775b03..2a1073f9 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -596,6 +596,40 @@ impl State { // FIXME: granular self.niri.queue_redraw_all(); } + Action::FocusWindowOrMonitorUp => { + if let Some(output) = self.niri.output_up() { + if self.niri.layout.focus_window_up_or_output(&output) + && !self.maybe_warp_cursor_to_focus_centered() + { + self.move_cursor_to_output(&output); + } else { + self.maybe_warp_cursor_to_focus(); + } + } else { + self.niri.layout.focus_up(); + self.maybe_warp_cursor_to_focus(); + } + + // FIXME: granular + self.niri.queue_redraw_all(); + } + Action::FocusWindowOrMonitorDown => { + if let Some(output) = self.niri.output_down() { + if self.niri.layout.focus_window_down_or_output(&output) + && !self.maybe_warp_cursor_to_focus_centered() + { + self.move_cursor_to_output(&output); + } else { + self.maybe_warp_cursor_to_focus(); + } + } else { + self.niri.layout.focus_down(); + self.maybe_warp_cursor_to_focus(); + } + + // FIXME: granular + self.niri.queue_redraw_all(); + } Action::FocusColumnOrMonitorLeft => { if let Some(output) = self.niri.output_left() { if self.niri.layout.focus_column_left_or_output(&output) diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 8fabba6a..e93a2556 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1264,6 +1264,43 @@ impl<W: LayoutElement> Layout<W> { monitor.focus_column_left_or_last(); } + pub fn focus_window_up_or_output(&mut self, output: &Output) -> bool { + if let Some(monitor) = self.active_monitor() { + let workspace = monitor.active_workspace(); + + if !workspace.columns.is_empty() { + let curr_idx = workspace.columns[workspace.active_column_idx].active_tile_idx; + let new_idx = curr_idx.saturating_sub(1); + if curr_idx != new_idx { + workspace.focus_up(); + return false; + } + } + } + + self.focus_output(output); + true + } + + pub fn focus_window_down_or_output(&mut self, output: &Output) -> bool { + if let Some(monitor) = self.active_monitor() { + let workspace = monitor.active_workspace(); + + if !workspace.columns.is_empty() { + let column = &workspace.columns[workspace.active_column_idx]; + let curr_idx = column.active_tile_idx; + let new_idx = min(column.active_tile_idx + 1, column.tiles.len() - 1); + if curr_idx != new_idx { + workspace.focus_down(); + return false; + } + } + } + + self.focus_output(output); + true + } + pub fn focus_column_left_or_output(&mut self, output: &Output) -> bool { if let Some(monitor) = self.active_monitor() { let workspace = monitor.active_workspace(); @@ -2728,6 +2765,8 @@ mod tests { FocusColumnLast, FocusColumnRightOrFirst, FocusColumnLeftOrLast, + FocusWindowOrMonitorUp(#[proptest(strategy = "1..=2u8")] u8), + FocusWindowOrMonitorDown(#[proptest(strategy = "1..=2u8")] u8), FocusColumnOrMonitorLeft(#[proptest(strategy = "1..=2u8")] u8), FocusColumnOrMonitorRight(#[proptest(strategy = "1..=2u8")] u8), FocusWindowDown, @@ -3055,6 +3094,22 @@ mod tests { Op::FocusColumnLast => layout.focus_column_last(), Op::FocusColumnRightOrFirst => layout.focus_column_right_or_first(), Op::FocusColumnLeftOrLast => layout.focus_column_left_or_last(), + Op::FocusWindowOrMonitorUp(id) => { + let name = format!("output{id}"); + let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else { + return; + }; + + layout.focus_window_up_or_output(&output); + } + Op::FocusWindowOrMonitorDown(id) => { + let name = format!("output{id}"); + let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else { + return; + }; + + layout.focus_window_down_or_output(&output); + } Op::FocusColumnOrMonitorLeft(id) => { let name = format!("output{id}"); let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else { @@ -3299,6 +3354,8 @@ mod tests { Op::FocusColumnRight, Op::FocusColumnRightOrFirst, Op::FocusColumnLeftOrLast, + Op::FocusWindowOrMonitorUp(0), + Op::FocusWindowOrMonitorDown(1), Op::FocusColumnOrMonitorLeft(0), Op::FocusColumnOrMonitorRight(1), Op::FocusWindowUp, @@ -3476,6 +3533,8 @@ mod tests { Op::FocusColumnRight, Op::FocusColumnRightOrFirst, Op::FocusColumnLeftOrLast, + Op::FocusWindowOrMonitorUp(0), + Op::FocusWindowOrMonitorDown(1), Op::FocusColumnOrMonitorLeft(0), Op::FocusColumnOrMonitorRight(1), Op::FocusWindowUp, |
