diff options
| -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 | 53 |
4 files changed, 95 insertions, 0 deletions
diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index b766072b..f1bd0afe 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -946,6 +946,8 @@ pub enum Action { FocusColumnLast, FocusColumnRightOrFirst, FocusColumnLeftOrLast, + FocusColumnOrMonitorLeft, + FocusColumnOrMonitorRight, FocusWindowDown, FocusWindowUp, FocusWindowDownOrColumnLeft, @@ -1022,6 +1024,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::FocusColumnOrMonitorLeft => Self::FocusColumnOrMonitorLeft, + niri_ipc::Action::FocusColumnOrMonitorRight => Self::FocusColumnOrMonitorRight, niri_ipc::Action::FocusWindowDown => Self::FocusWindowDown, niri_ipc::Action::FocusWindowUp => Self::FocusWindowUp, niri_ipc::Action::FocusWindowDownOrColumnLeft => Self::FocusWindowDownOrColumnLeft, diff --git a/niri-ipc/src/lib.rs b/niri-ipc/src/lib.rs index 72e050e4..4db883e5 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 column or the monitor to the left. + FocusColumnOrMonitorLeft, + /// Focus the column or the monitor to the right. + FocusColumnOrMonitorRight, /// Focus the window below. FocusWindowDown, /// Focus the window above. diff --git a/src/input/mod.rs b/src/input/mod.rs index 59a4b436..5e775b03 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::FocusColumnOrMonitorLeft => { + if let Some(output) = self.niri.output_left() { + if self.niri.layout.focus_column_left_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_left(); + self.maybe_warp_cursor_to_focus(); + } + + // FIXME: granular + self.niri.queue_redraw_all(); + } + Action::FocusColumnOrMonitorRight => { + if let Some(output) = self.niri.output_right() { + if self.niri.layout.focus_column_right_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_right(); + self.maybe_warp_cursor_to_focus(); + } + + // FIXME: granular + self.niri.queue_redraw_all(); + } Action::FocusWindowDown => { self.niri.layout.focus_down(); self.maybe_warp_cursor_to_focus(); diff --git a/src/layout/mod.rs b/src/layout/mod.rs index b74ef729..8fabba6a 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1264,6 +1264,37 @@ impl<W: LayoutElement> Layout<W> { monitor.focus_column_left_or_last(); } + pub fn focus_column_left_or_output(&mut self, output: &Output) -> bool { + if let Some(monitor) = self.active_monitor() { + let workspace = monitor.active_workspace(); + let curr_idx = workspace.active_column_idx; + + if !workspace.columns.is_empty() && curr_idx != 0 { + monitor.focus_left(); + return false; + } + } + + self.focus_output(output); + true + } + + pub fn focus_column_right_or_output(&mut self, output: &Output) -> bool { + if let Some(monitor) = self.active_monitor() { + let workspace = monitor.active_workspace(); + let curr_idx = workspace.active_column_idx; + let columns = &workspace.columns; + + if !workspace.columns.is_empty() && curr_idx != columns.len() - 1 { + monitor.focus_right(); + return false; + } + } + + self.focus_output(output); + true + } + pub fn focus_down(&mut self) { let Some(monitor) = self.active_monitor() else { return; @@ -2697,6 +2728,8 @@ mod tests { FocusColumnLast, FocusColumnRightOrFirst, FocusColumnLeftOrLast, + FocusColumnOrMonitorLeft(#[proptest(strategy = "1..=2u8")] u8), + FocusColumnOrMonitorRight(#[proptest(strategy = "1..=2u8")] u8), FocusWindowDown, FocusWindowUp, FocusWindowDownOrColumnLeft, @@ -3022,6 +3055,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::FocusColumnOrMonitorLeft(id) => { + let name = format!("output{id}"); + let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else { + return; + }; + + layout.focus_column_left_or_output(&output); + } + Op::FocusColumnOrMonitorRight(id) => { + let name = format!("output{id}"); + let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else { + return; + }; + + layout.focus_column_right_or_output(&output); + } Op::FocusWindowDown => layout.focus_down(), Op::FocusWindowUp => layout.focus_up(), Op::FocusWindowDownOrColumnLeft => layout.focus_down_or_left(), @@ -3250,6 +3299,8 @@ mod tests { Op::FocusColumnRight, Op::FocusColumnRightOrFirst, Op::FocusColumnLeftOrLast, + Op::FocusColumnOrMonitorLeft(0), + Op::FocusColumnOrMonitorRight(1), Op::FocusWindowUp, Op::FocusWindowUpOrColumnLeft, Op::FocusWindowUpOrColumnRight, @@ -3425,6 +3476,8 @@ mod tests { Op::FocusColumnRight, Op::FocusColumnRightOrFirst, Op::FocusColumnLeftOrLast, + Op::FocusColumnOrMonitorLeft(0), + Op::FocusColumnOrMonitorRight(1), Op::FocusWindowUp, Op::FocusWindowUpOrColumnLeft, Op::FocusWindowUpOrColumnRight, |
