mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-23 02:05:33 +07:00
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:
@@ -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,
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user