diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-05 17:18:21 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-05 17:25:51 +0300 |
| commit | c41f93a468c4d04e16f8c89736cc48cd4ab4c623 (patch) | |
| tree | 3f6e8fb315550288b4e293e873b13dbf2d421486 /src | |
| parent | 900da597e4d3d09ad4c4ddc3ba2abf58c4886ec9 (diff) | |
| download | niri-c41f93a468c4d04e16f8c89736cc48cd4ab4c623.tar.gz niri-c41f93a468c4d04e16f8c89736cc48cd4ab4c623.tar.bz2 niri-c41f93a468c4d04e16f8c89736cc48cd4ab4c623.zip | |
Add focus-window-top/bottom/down-or-top/up-or-bottom actions
Diffstat (limited to 'src')
| -rw-r--r-- | src/input/mod.rs | 28 | ||||
| -rw-r--r-- | src/layout/floating.rs | 20 | ||||
| -rw-r--r-- | src/layout/mod.rs | 28 | ||||
| -rw-r--r-- | src/layout/monitor.rs | 16 | ||||
| -rw-r--r-- | src/layout/scrolling.rs | 24 | ||||
| -rw-r--r-- | src/layout/tests.rs | 8 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 28 |
7 files changed, 152 insertions, 0 deletions
diff --git a/src/input/mod.rs b/src/input/mod.rs index b6eb0e3d..9f5f363c 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -987,6 +987,34 @@ impl State { // FIXME: granular self.niri.queue_redraw_all(); } + Action::FocusWindowTop => { + self.niri.layout.focus_window_top(); + self.maybe_warp_cursor_to_focus(); + self.niri.layer_shell_on_demand_focus = None; + // FIXME: granular + self.niri.queue_redraw_all(); + } + Action::FocusWindowBottom => { + self.niri.layout.focus_window_bottom(); + self.maybe_warp_cursor_to_focus(); + self.niri.layer_shell_on_demand_focus = None; + // FIXME: granular + self.niri.queue_redraw_all(); + } + Action::FocusWindowDownOrTop => { + self.niri.layout.focus_window_down_or_top(); + self.maybe_warp_cursor_to_focus(); + self.niri.layer_shell_on_demand_focus = None; + // FIXME: granular + self.niri.queue_redraw_all(); + } + Action::FocusWindowUpOrBottom => { + self.niri.layout.focus_window_up_or_bottom(); + self.maybe_warp_cursor_to_focus(); + self.niri.layer_shell_on_demand_focus = None; + // FIXME: granular + self.niri.queue_redraw_all(); + } Action::MoveWindowToWorkspaceDown => { self.niri.layout.move_to_workspace_down(); self.maybe_warp_cursor_to_focus(); diff --git a/src/layout/floating.rs b/src/layout/floating.rs index b908d920..15c99e87 100644 --- a/src/layout/floating.rs +++ b/src/layout/floating.rs @@ -833,6 +833,26 @@ impl<W: LayoutElement> FloatingSpace<W> { } } + pub fn focus_topmost(&mut self) { + let result = self + .tiles_with_offsets() + .min_by(|(_, pos_a), (_, pos_b)| f64::total_cmp(&pos_a.y, &pos_b.y)); + if let Some((tile, _)) = result { + let id = tile.window().id().clone(); + self.activate_window(&id); + } + } + + pub fn focus_bottommost(&mut self) { + let result = self + .tiles_with_offsets() + .max_by(|(_, pos_a), (_, pos_b)| f64::total_cmp(&pos_a.y, &pos_b.y)); + if let Some((tile, _)) = result { + let id = tile.window().id().clone(); + self.activate_window(&id); + } + } + fn move_to(&mut self, idx: usize, new_pos: Point<f64, Logical>, animate: bool) { if animate { self.move_and_animate(idx, new_pos); diff --git a/src/layout/mod.rs b/src/layout/mod.rs index f60e3192..45c5ffce 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1949,6 +1949,34 @@ impl<W: LayoutElement> Layout<W> { monitor.focus_window_or_workspace_up(); } + pub fn focus_window_top(&mut self) { + let Some(monitor) = self.active_monitor() else { + return; + }; + monitor.focus_window_top(); + } + + pub fn focus_window_bottom(&mut self) { + let Some(monitor) = self.active_monitor() else { + return; + }; + monitor.focus_window_bottom(); + } + + pub fn focus_window_down_or_top(&mut self) { + let Some(monitor) = self.active_monitor() else { + return; + }; + monitor.focus_window_down_or_top(); + } + + pub fn focus_window_up_or_bottom(&mut self) { + let Some(monitor) = self.active_monitor() else { + return; + }; + monitor.focus_window_up_or_bottom(); + } + pub fn move_to_workspace_up(&mut self) { let Some(monitor) = self.active_monitor() else { return; diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs index 310121b5..37f5fb94 100644 --- a/src/layout/monitor.rs +++ b/src/layout/monitor.rs @@ -493,6 +493,22 @@ impl<W: LayoutElement> Monitor<W> { } } + pub fn focus_window_top(&mut self) { + self.active_workspace().focus_window_top(); + } + + pub fn focus_window_bottom(&mut self) { + self.active_workspace().focus_window_bottom(); + } + + pub fn focus_window_down_or_top(&mut self) { + self.active_workspace().focus_window_down_or_top(); + } + + pub fn focus_window_up_or_bottom(&mut self) { + self.active_workspace().focus_window_up_or_bottom(); + } + pub fn move_to_workspace_up(&mut self) { let source_workspace_idx = self.active_workspace_idx; diff --git a/src/layout/scrolling.rs b/src/layout/scrolling.rs index d90150d8..07890284 100644 --- a/src/layout/scrolling.rs +++ b/src/layout/scrolling.rs @@ -1422,6 +1422,22 @@ impl<W: LayoutElement> ScrollingSpace<W> { } } + pub fn focus_top(&mut self) { + if self.columns.is_empty() { + return; + } + + self.columns[self.active_column_idx].focus_top() + } + + pub fn focus_bottom(&mut self) { + if self.columns.is_empty() { + return; + } + + self.columns[self.active_column_idx].focus_bottom() + } + fn move_column_to(&mut self, new_idx: usize) { if self.active_column_idx == new_idx { return; @@ -3616,6 +3632,14 @@ impl<W: LayoutElement> Column<W> { true } + fn focus_top(&mut self) { + self.active_tile_idx = 0; + } + + fn focus_bottom(&mut self) { + self.active_tile_idx = self.tiles.len() - 1; + } + fn move_up(&mut self) -> bool { let new_idx = self.active_tile_idx.saturating_sub(1); if self.active_tile_idx == new_idx { diff --git a/src/layout/tests.rs b/src/layout/tests.rs index e39b3ca5..b08b1de0 100644 --- a/src/layout/tests.rs +++ b/src/layout/tests.rs @@ -380,6 +380,10 @@ enum Op { FocusWindowOrWorkspaceDown, FocusWindowOrWorkspaceUp, FocusWindow(#[proptest(strategy = "1..=5usize")] usize), + FocusWindowTop, + FocusWindowBottom, + FocusWindowDownOrTop, + FocusWindowUpOrBottom, MoveColumnLeft, MoveColumnRight, MoveColumnToFirst, @@ -924,6 +928,10 @@ impl Op { Op::FocusWindowOrWorkspaceDown => layout.focus_window_or_workspace_down(), Op::FocusWindowOrWorkspaceUp => layout.focus_window_or_workspace_up(), Op::FocusWindow(id) => layout.activate_window(&id), + Op::FocusWindowTop => layout.focus_window_top(), + Op::FocusWindowBottom => layout.focus_window_bottom(), + Op::FocusWindowDownOrTop => layout.focus_window_down_or_top(), + Op::FocusWindowUpOrBottom => layout.focus_window_up_or_bottom(), Op::MoveColumnLeft => layout.move_left(), Op::MoveColumnRight => layout.move_right(), Op::MoveColumnToFirst => layout.move_column_to_first(), diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index c4cad666..680e5e4c 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -896,6 +896,34 @@ impl<W: LayoutElement> Workspace<W> { } } + pub fn focus_window_top(&mut self) { + if self.floating_is_active.get() { + self.floating.focus_topmost(); + } else { + self.scrolling.focus_top(); + } + } + + pub fn focus_window_bottom(&mut self) { + if self.floating_is_active.get() { + self.floating.focus_bottommost(); + } else { + self.scrolling.focus_bottom(); + } + } + + pub fn focus_window_down_or_top(&mut self) { + if !self.focus_down() { + self.focus_window_top(); + } + } + + pub fn focus_window_up_or_bottom(&mut self) { + if !self.focus_up() { + self.focus_window_bottom(); + } + } + pub fn move_left(&mut self) -> bool { if self.floating_is_active.get() { self.floating.move_left(); |
