mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-21 02:01:55 +07:00
Implement clicking on tab to switch
This commit is contained in:
+5
-2
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user