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>
This commit is contained in:
TheAngusMcFire
2024-07-05 06:55:04 +02:00
committed by GitHub
parent 9dcc9160b3
commit a56e4ff436
4 changed files with 101 additions and 0 deletions
+4
View File
@@ -949,6 +949,8 @@ pub enum Action {
FocusColumnLast, FocusColumnLast,
FocusColumnRightOrFirst, FocusColumnRightOrFirst,
FocusColumnLeftOrLast, FocusColumnLeftOrLast,
FocusWindowOrMonitorUp,
FocusWindowOrMonitorDown,
FocusColumnOrMonitorLeft, FocusColumnOrMonitorLeft,
FocusColumnOrMonitorRight, FocusColumnOrMonitorRight,
FocusWindowDown, FocusWindowDown,
@@ -1027,6 +1029,8 @@ impl From<niri_ipc::Action> for Action {
niri_ipc::Action::FocusColumnLast => Self::FocusColumnLast, niri_ipc::Action::FocusColumnLast => Self::FocusColumnLast,
niri_ipc::Action::FocusColumnRightOrFirst => Self::FocusColumnRightOrFirst, niri_ipc::Action::FocusColumnRightOrFirst => Self::FocusColumnRightOrFirst,
niri_ipc::Action::FocusColumnLeftOrLast => Self::FocusColumnLeftOrLast, 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::FocusColumnOrMonitorLeft => Self::FocusColumnOrMonitorLeft,
niri_ipc::Action::FocusColumnOrMonitorRight => Self::FocusColumnOrMonitorRight, niri_ipc::Action::FocusColumnOrMonitorRight => Self::FocusColumnOrMonitorRight,
niri_ipc::Action::FocusWindowDown => Self::FocusWindowDown, niri_ipc::Action::FocusWindowDown => Self::FocusWindowDown,
+4
View File
@@ -120,6 +120,10 @@ pub enum Action {
FocusColumnRightOrFirst, FocusColumnRightOrFirst,
/// Focus the next column to the left, looping if at start. /// Focus the next column to the left, looping if at start.
FocusColumnLeftOrLast, 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. /// Focus the column or the monitor to the left.
FocusColumnOrMonitorLeft, FocusColumnOrMonitorLeft,
/// Focus the column or the monitor to the right. /// Focus the column or the monitor to the right.
+34
View File
@@ -596,6 +596,40 @@ impl State {
// FIXME: granular // FIXME: granular
self.niri.queue_redraw_all(); 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 => { Action::FocusColumnOrMonitorLeft => {
if let Some(output) = self.niri.output_left() { if let Some(output) = self.niri.output_left() {
if self.niri.layout.focus_column_left_or_output(&output) if self.niri.layout.focus_column_left_or_output(&output)
+59
View File
@@ -1264,6 +1264,43 @@ impl<W: LayoutElement> Layout<W> {
monitor.focus_column_left_or_last(); 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 { pub fn focus_column_left_or_output(&mut self, output: &Output) -> bool {
if let Some(monitor) = self.active_monitor() { if let Some(monitor) = self.active_monitor() {
let workspace = monitor.active_workspace(); let workspace = monitor.active_workspace();
@@ -2728,6 +2765,8 @@ mod tests {
FocusColumnLast, FocusColumnLast,
FocusColumnRightOrFirst, FocusColumnRightOrFirst,
FocusColumnLeftOrLast, FocusColumnLeftOrLast,
FocusWindowOrMonitorUp(#[proptest(strategy = "1..=2u8")] u8),
FocusWindowOrMonitorDown(#[proptest(strategy = "1..=2u8")] u8),
FocusColumnOrMonitorLeft(#[proptest(strategy = "1..=2u8")] u8), FocusColumnOrMonitorLeft(#[proptest(strategy = "1..=2u8")] u8),
FocusColumnOrMonitorRight(#[proptest(strategy = "1..=2u8")] u8), FocusColumnOrMonitorRight(#[proptest(strategy = "1..=2u8")] u8),
FocusWindowDown, FocusWindowDown,
@@ -3055,6 +3094,22 @@ mod tests {
Op::FocusColumnLast => layout.focus_column_last(), Op::FocusColumnLast => layout.focus_column_last(),
Op::FocusColumnRightOrFirst => layout.focus_column_right_or_first(), Op::FocusColumnRightOrFirst => layout.focus_column_right_or_first(),
Op::FocusColumnLeftOrLast => layout.focus_column_left_or_last(), 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) => { Op::FocusColumnOrMonitorLeft(id) => {
let name = format!("output{id}"); let name = format!("output{id}");
let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else { let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else {
@@ -3299,6 +3354,8 @@ mod tests {
Op::FocusColumnRight, Op::FocusColumnRight,
Op::FocusColumnRightOrFirst, Op::FocusColumnRightOrFirst,
Op::FocusColumnLeftOrLast, Op::FocusColumnLeftOrLast,
Op::FocusWindowOrMonitorUp(0),
Op::FocusWindowOrMonitorDown(1),
Op::FocusColumnOrMonitorLeft(0), Op::FocusColumnOrMonitorLeft(0),
Op::FocusColumnOrMonitorRight(1), Op::FocusColumnOrMonitorRight(1),
Op::FocusWindowUp, Op::FocusWindowUp,
@@ -3476,6 +3533,8 @@ mod tests {
Op::FocusColumnRight, Op::FocusColumnRight,
Op::FocusColumnRightOrFirst, Op::FocusColumnRightOrFirst,
Op::FocusColumnLeftOrLast, Op::FocusColumnLeftOrLast,
Op::FocusWindowOrMonitorUp(0),
Op::FocusWindowOrMonitorDown(1),
Op::FocusColumnOrMonitorLeft(0), Op::FocusColumnOrMonitorLeft(0),
Op::FocusColumnOrMonitorRight(1), Op::FocusColumnOrMonitorRight(1),
Op::FocusWindowUp, Op::FocusWindowUp,