Implement clicking on tab to switch

This commit is contained in:
Ivan Molodetskikh
2025-02-10 13:12:53 +03:00
parent 963ff14ed0
commit 6942ecc13a
6 changed files with 97 additions and 12 deletions
+5 -2
View File
@@ -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
}
+46 -1
View File
@@ -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;
+21
View File
@@ -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,
+3 -1
View File
@@ -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
}
+11 -7
View File
@@ -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> {
+11 -1
View File
@@ -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;