diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-10 13:12:53 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-10 07:29:33 -0800 |
| commit | 6942ecc13a40867850fc26429da21603647e8026 (patch) | |
| tree | faa00e99985eb8d24acb09235d93b7fe2822b301 /src | |
| parent | 963ff14ed025eeb5d6785dbcd4c073251ef7a9e9 (diff) | |
| download | niri-6942ecc13a40867850fc26429da21603647e8026.tar.gz niri-6942ecc13a40867850fc26429da21603647e8026.tar.bz2 niri-6942ecc13a40867850fc26429da21603647e8026.zip | |
Implement clicking on tab to switch
Diffstat (limited to 'src')
| -rw-r--r-- | src/layout/mod.rs | 7 | ||||
| -rw-r--r-- | src/layout/scrolling.rs | 47 | ||||
| -rw-r--r-- | src/layout/tab_indicator.rs | 21 | ||||
| -rw-r--r-- | src/layout/tile.rs | 4 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 18 | ||||
| -rw-r--r-- | src/niri.rs | 12 |
6 files changed, 97 insertions, 12 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs index ae338ced..4dec85f6 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -466,7 +466,10 @@ pub enum HitType { /// The hit can activate a window, but it is not in the input region so cannot send events. /// /// For example, this could be clicking on a tile border outside the window. - Activate, + Activate { + /// Whether the hit was on the tab indicator. + is_tab_indicator: bool, + }, } impl<W: LayoutElement> InteractiveMoveState<W> { @@ -515,7 +518,7 @@ impl HitType { pub fn offset_win_pos(mut self, offset: Point<f64, Logical>) -> Self { match &mut self { HitType::Input { win_pos } => *win_pos += offset, - HitType::Activate => (), + HitType::Activate { .. } => (), } self } diff --git a/src/layout/scrolling.rs b/src/layout/scrolling.rs index ab0ad69a..18da2b46 100644 --- a/src/layout/scrolling.rs +++ b/src/layout/scrolling.rs @@ -14,7 +14,7 @@ use super::insert_hint_element::{InsertHintElement, InsertHintRenderElement}; use super::tab_indicator::{TabIndicator, TabIndicatorRenderElement, TabInfo}; use super::tile::{Tile, TileRenderElement, TileRenderSnapshot}; use super::workspace::{InteractiveResize, ResolvedSize}; -use super::{ConfigureIntent, InteractiveResizeData, LayoutElement, Options, RemovedTile}; +use super::{ConfigureIntent, HitType, InteractiveResizeData, LayoutElement, Options, RemovedTile}; use crate::animation::{Animation, Clock}; use crate::input::swipe_tracker::SwipeTracker; use crate::niri_render_elements; @@ -2645,6 +2645,51 @@ impl<W: LayoutElement> ScrollingSpace<W> { rv } + pub fn window_under(&self, pos: Point<f64, Logical>) -> Option<(&W, HitType)> { + // This matches self.tiles_with_render_positions(). + let scale = self.scale; + let view_off = Point::from((-self.view_pos(), 0.)); + for (col, col_x) in self.columns_in_render_order() { + let col_off = Point::from((col_x, 0.)); + let col_render_off = col.render_offset(); + + // Hit the tab indicator. + if col.display_mode == ColumnDisplay::Tabbed && !col.is_fullscreen { + let col_pos = view_off + col_off + col_render_off; + let col_pos = col_pos.to_physical_precise_round(scale).to_logical(scale); + + if let Some(idx) = col.tab_indicator.hit( + col.tab_indicator_area(), + col.tiles.len(), + scale, + pos - col_pos, + ) { + let hit = HitType::Activate { + is_tab_indicator: true, + }; + return Some((col.tiles[idx].window(), hit)); + } + } + + for (tile, tile_off, visible) in col.tiles_in_render_order() { + if !visible { + continue; + } + + let tile_pos = + view_off + col_off + col_render_off + tile_off + tile.render_offset(); + // Round to physical pixels. + let tile_pos = tile_pos.to_physical_precise_round(scale).to_logical(scale); + + if let Some(rv) = HitType::hit_tile(tile, tile_pos, pos) { + return Some(rv); + } + } + } + + None + } + pub fn view_offset_gesture_begin(&mut self, is_touchpad: bool) { if self.columns.is_empty() { return; diff --git a/src/layout/tab_indicator.rs b/src/layout/tab_indicator.rs index 451f2224..ad457386 100644 --- a/src/layout/tab_indicator.rs +++ b/src/layout/tab_indicator.rs @@ -182,6 +182,27 @@ impl TabIndicator { } } + pub fn hit( + &self, + area: Rectangle<f64, Logical>, + tab_count: usize, + scale: f64, + point: Point<f64, Logical>, + ) -> Option<usize> { + if self.config.off { + return None; + } + + let count = tab_count; + if self.config.hide_when_single_tab && count == 1 { + return None; + } + + self.tab_rects(area, count, scale) + .enumerate() + .find_map(|(idx, rect)| rect.contains(point).then_some(idx)) + } + pub fn render( &self, renderer: &mut impl NiriRenderer, diff --git a/src/layout/tile.rs b/src/layout/tile.rs index 7877457b..e3c1cce7 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -658,7 +658,9 @@ impl<W: LayoutElement> Tile<W> { let win_pos = self.buf_loc(); Some(HitType::Input { win_pos }) } else if self.is_in_activation_region(point) { - Some(HitType::Activate) + Some(HitType::Activate { + is_tab_indicator: false, + }) } else { None } diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index b5392644..25d2bb80 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -1475,14 +1475,18 @@ impl<W: LayoutElement> Workspace<W> { } pub fn window_under(&self, pos: Point<f64, Logical>) -> Option<(&W, HitType)> { - self.tiles_with_render_positions() - .find_map(|(tile, tile_pos, visible)| { - if !visible { - return None; - } + // This logic is consistent with tiles_with_render_positions(). + if self.is_floating_visible() { + if let Some(rv) = self + .floating + .tiles_with_render_positions() + .find_map(|(tile, tile_pos)| HitType::hit_tile(tile, tile_pos, pos)) + { + return Some(rv); + } + } - HitType::hit_tile(tile, tile_pos, pos) - }) + self.scrolling.window_under(pos) } pub fn resize_edges_under(&self, pos: Point<f64, Logical>) -> Option<ResizeEdge> { diff --git a/src/niri.rs b/src/niri.rs index 8710493c..4dfaf525 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -5060,7 +5060,17 @@ impl Niri { if let Some(window) = &new_focus.window { if current_focus.window.as_ref() != Some(window) { - let (window, _) = window; + let (window, hit) = window; + + // Don't trigger focus-follows-mouse over the tab indicator. + if matches!( + hit, + HitType::Activate { + is_tab_indicator: true + } + ) { + return; + } if !self.layout.should_trigger_focus_follows_mouse_on(window) { return; |
