diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-10 08:03:39 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-10 07:29:33 -0800 |
| commit | 1d883931b4ae7704128f02fd566486fb02351196 (patch) | |
| tree | 575124aeaa26ee6a0ccff0c55a3facda9dfe9944 /src | |
| parent | b65fad09d8f5253a28ee7ad9d293583641fc2c36 (diff) | |
| download | niri-1d883931b4ae7704128f02fd566486fb02351196.tar.gz niri-1d883931b4ae7704128f02fd566486fb02351196.tar.bz2 niri-1d883931b4ae7704128f02fd566486fb02351196.zip | |
Account for border in contents_under()
Fixes pointer clicks going through window borders to a layer surface below,
also fixes window not getting activated in all cases from a border click.
Diffstat (limited to 'src')
| -rw-r--r-- | src/layout/mod.rs | 38 | ||||
| -rw-r--r-- | src/layout/monitor.rs | 11 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 13 | ||||
| -rw-r--r-- | src/niri.rs | 42 |
4 files changed, 63 insertions, 41 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 01122177..593279b7 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -450,6 +450,20 @@ pub enum AddWindowTarget<'a, W: LayoutElement> { NextTo(&'a W::Id), } +/// Type of the window hit from `window_under()`. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum HitType { + /// The hit is within a window's input region and can be used for sending events to it. + Input { + /// Position of the window's buffer. + win_pos: Point<f64, Logical>, + }, + /// 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, +} + impl<W: LayoutElement> InteractiveMoveState<W> { fn moving(&self) -> Option<&InteractiveMoveData<W>> { match self { @@ -485,6 +499,16 @@ impl ActivateWindow { } } +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 => (), + } + self + } +} + impl Options { fn from_config(config: &Config) -> Self { let layout = &config.layout; @@ -2155,18 +2179,12 @@ impl<W: LayoutElement> Layout<W> { mon.active_window().map(|win| (win, &mon.output)) } - /// Returns the window under the cursor and the position of its toplevel surface within the - /// output. - /// - /// `Some((w, Some(p)))` means that the cursor is within the window's input region and can be - /// used for delivering events to the window. `Some((w, None))` means that the cursor is within - /// the window's activation region, but not within the window's input region. For example, the - /// cursor may be on the window's server-side border. + /// Returns the window under the cursor and the hit type. pub fn window_under( &self, output: &Output, pos_within_output: Point<f64, Logical>, - ) -> Option<(&W, Option<Point<f64, Logical>>)> { + ) -> Option<(&W, HitType)> { let MonitorSet::Normal { monitors, .. } = &self.monitor_set else { return None; }; @@ -2177,9 +2195,9 @@ impl<W: LayoutElement> Layout<W> { if move_.tile.is_in_input_region(pos_within_tile) { let win_pos = tile_pos + move_.tile.buf_loc(); - return Some((move_.tile.window(), Some(win_pos))); + return Some((move_.tile.window(), HitType::Input { win_pos })); } else if move_.tile.is_in_activation_region(pos_within_tile) { - return Some((move_.tile.window(), None)); + return Some((move_.tile.window(), HitType::Activate)); } return None; diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs index ebafad17..53bf5377 100644 --- a/src/layout/monitor.rs +++ b/src/layout/monitor.rs @@ -14,7 +14,7 @@ use super::tile::Tile; use super::workspace::{ OutputId, Workspace, WorkspaceAddWindowTarget, WorkspaceId, WorkspaceRenderElement, }; -use super::{ActivateWindow, LayoutElement, Options}; +use super::{ActivateWindow, HitType, LayoutElement, Options}; use crate::animation::{Animation, Clock}; use crate::input::swipe_tracker::SwipeTracker; use crate::render_helpers::renderer::NiriRenderer; @@ -1007,13 +1007,10 @@ impl<W: LayoutElement> Monitor<W> { Some((ws, bounds.loc)) } - pub fn window_under( - &self, - pos_within_output: Point<f64, Logical>, - ) -> Option<(&W, Option<Point<f64, Logical>>)> { + pub fn window_under(&self, pos_within_output: Point<f64, Logical>) -> Option<(&W, HitType)> { let (ws, offset) = self.workspace_under(pos_within_output)?; - let (win, win_pos) = ws.window_under(pos_within_output - offset)?; - Some((win, win_pos.map(|p| p + offset))) + let (win, hit) = ws.window_under(pos_within_output - offset)?; + Some((win, hit.offset_win_pos(offset))) } pub fn resize_edges_under(&self, pos_within_output: Point<f64, Logical>) -> Option<ResizeEdge> { diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index f005577d..165ae750 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -19,7 +19,9 @@ use super::scrolling::{ ScrollingSpaceRenderElement, }; use super::tile::{Tile, TileRenderSnapshot}; -use super::{ActivateWindow, InteractiveResizeData, LayoutElement, Options, RemovedTile, SizeFrac}; +use super::{ + ActivateWindow, HitType, InteractiveResizeData, LayoutElement, Options, RemovedTile, SizeFrac, +}; use crate::animation::Clock; use crate::niri_render_elements; use crate::render_helpers::renderer::NiriRenderer; @@ -1459,10 +1461,7 @@ impl<W: LayoutElement> Workspace<W> { .start_close_animation_for_tile(renderer, snapshot, tile_size, tile_pos, blocker); } - pub fn window_under( - &self, - pos: Point<f64, Logical>, - ) -> Option<(&W, Option<Point<f64, Logical>>)> { + 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 { @@ -1473,9 +1472,9 @@ impl<W: LayoutElement> Workspace<W> { if tile.is_in_input_region(pos_within_tile) { let win_pos = tile_pos + tile.buf_loc(); - return Some((tile.window(), Some(win_pos))); + return Some((tile.window(), HitType::Input { win_pos })); } else if tile.is_in_activation_region(pos_within_tile) { - return Some((tile.window(), None)); + return Some((tile.window(), HitType::Activate)); } None diff --git a/src/niri.rs b/src/niri.rs index 7e1884be..a7fc872f 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -128,7 +128,7 @@ use crate::layer::mapped::LayerSurfaceRenderElement; use crate::layer::MappedLayer; use crate::layout::tile::TileRenderElement; use crate::layout::workspace::WorkspaceId; -use crate::layout::{Layout, LayoutElement as _, MonitorRenderElement}; +use crate::layout::{HitType, Layout, LayoutElement as _, MonitorRenderElement}; use crate::niri_render_elements; use crate::protocols::foreign_toplevel::{self, ForeignToplevelManagerState}; use crate::protocols::gamma_control::GammaControlManagerState; @@ -450,6 +450,9 @@ pub struct PointContents { // Output under point. pub output: Option<Output>, // Surface under point and its location in the global coordinate space. + // + // Can be `None` even when `window` is set, for example when the pointer is over the niri + // border around the window. pub surface: Option<(WlSurface, Point<f64, Logical>)>, // If surface belongs to a window, this is that window. pub window: Option<Window>, @@ -2693,7 +2696,7 @@ impl Niri { ) }) }) - .map(|(s, l)| (s, (None, Some(l.clone())))) + .map(|(s, l)| (Some(s), (None, Some(l.clone())))) }; let layer_toplevel_under = |layer| layer_surface_under(layer, false); @@ -2702,18 +2705,22 @@ impl Niri { let window_under = || { self.layout .window_under(output, pos_within_output) - .and_then(|(mapped, win_pos_within_output)| { - let win_pos_within_output = win_pos_within_output?; + .map(|(mapped, hit)| { let window = &mapped.window; - window - .surface_under( - pos_within_output - win_pos_within_output, - WindowSurfaceType::ALL, - ) - .map(|(s, pos_within_window)| { - (s, pos_within_window.to_f64() + win_pos_within_output) - }) - .map(|s| (s, (Some(window.clone()), None))) + let surface_and_pos = if let HitType::Input { win_pos } = hit { + let win_pos_within_output = win_pos; + window + .surface_under( + pos_within_output - win_pos_within_output, + WindowSurfaceType::ALL, + ) + .map(|(s, pos_within_window)| { + (s, pos_within_window.to_f64() + win_pos_within_output) + }) + } else { + None + }; + (surface_and_pos, (Some(window.clone()), None)) }) }; @@ -2744,14 +2751,15 @@ impl Niri { .or_else(|| layer_toplevel_under(Layer::Background)); } - let Some(((surface, surface_pos_within_output), (window, layer))) = under else { + let Some((mut surface_and_pos, (window, layer))) = under else { return rv; }; - let surface_loc_in_global_space = - surface_pos_within_output + output_pos_in_global_space.to_f64(); + if let Some((_, surface_pos)) = &mut surface_and_pos { + *surface_pos += output_pos_in_global_space.to_f64(); + } - rv.surface = Some((surface, surface_loc_in_global_space)); + rv.surface = surface_and_pos; rv.window = window; rv.layer = layer; rv |
