diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2025-04-17 11:00:17 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-04-25 02:00:18 -0700 |
| commit | b20dd226c06d16633610bb91f18d02d8f54c5d90 (patch) | |
| tree | 8bff220084abb9f9057a0a30f99314751f5eeb85 /src | |
| parent | acb69c3b4df81ad6869603fda51bc3b0e6b8830c (diff) | |
| download | niri-b20dd226c06d16633610bb91f18d02d8f54c5d90.tar.gz niri-b20dd226c06d16633610bb91f18d02d8f54c5d90.tar.bz2 niri-b20dd226c06d16633610bb91f18d02d8f54c5d90.zip | |
layout: Move insert hint from ScrollingSpace to Monitor
Diffstat (limited to 'src')
| -rw-r--r-- | src/layout/mod.rs | 22 | ||||
| -rw-r--r-- | src/layout/monitor.rs | 119 | ||||
| -rw-r--r-- | src/layout/scrolling.rs | 86 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 21 |
4 files changed, 146 insertions, 102 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 3cdcdc82..d4de5693 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -37,13 +37,13 @@ use std::mem; use std::rc::Rc; use std::time::Duration; -use monitor::MonitorAddWindowTarget; +use monitor::{InsertHint, InsertPosition, MonitorAddWindowTarget}; use niri_config::{ CenterFocusedColumn, Config, CornerRadius, FloatOrInt, PresetSize, Struts, Workspace as WorkspaceConfig, WorkspaceReference, }; use niri_ipc::{ColumnDisplay, PositionChange, SizeChange}; -use scrolling::{Column, ColumnWidth, InsertHint, InsertPosition}; +use scrolling::{Column, ColumnWidth}; use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement; use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture}; use smithay::output::{self, Output}; @@ -2756,9 +2756,10 @@ impl<W: LayoutElement> Layout<W> { fn update_insert_hint(&mut self, output: Option<&Output>) { let _span = tracy_client::span!("Layout::update_insert_hint"); - let _span = tracy_client::span!("Layout::update_insert_hint::clear"); - for ws in self.workspaces_mut() { - ws.clear_insert_hint(); + if let MonitorSet::Normal { monitors, .. } = &mut self.monitor_set { + for mon in monitors { + mon.insert_hint = None; + } } if !matches!(self.interactive_move, Some(InteractiveMoveState::Moving(_))) { @@ -2789,7 +2790,8 @@ impl<W: LayoutElement> Layout<W> { .find(|ws| ws.id() == ws_id) .unwrap(); - let position = ws.get_insert_position(move_.pointer_pos_within_output - geo.loc); + let pos_within_workspace = move_.pointer_pos_within_output - geo.loc; + let position = ws.scrolling_insert_position(pos_within_workspace); let rules = move_.tile.window().rules(); let border_width = move_.tile.effective_border_width().unwrap_or(0.); @@ -2799,7 +2801,8 @@ impl<W: LayoutElement> Layout<W> { radius.expanded_by(border_width as f32) }); - ws.set_insert_hint(InsertHint { + mon.insert_hint = Some(InsertHint { + workspace: ws_id, position, corner_radius, }); @@ -4007,8 +4010,9 @@ impl<W: LayoutElement> Layout<W> { let position = if move_.is_floating { InsertPosition::Floating } else { + let pos_within_workspace = move_.pointer_pos_within_output - ws_geo.loc; let ws = &mut mon.workspaces[ws_idx]; - ws.get_insert_position(move_.pointer_pos_within_output - ws_geo.loc) + ws.scrolling_insert_position(pos_within_workspace) }; (mon, ws_idx, position, ws_geo.loc) @@ -4020,7 +4024,7 @@ impl<W: LayoutElement> Layout<W> { let position = if move_.is_floating { InsertPosition::Floating } else { - ws.get_insert_position(Point::from((0., 0.))) + ws.scrolling_insert_position(Point::from((0., 0.))) }; let ws_id = ws.id(); diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs index 209bfcbf..85646b63 100644 --- a/src/layout/monitor.rs +++ b/src/layout/monitor.rs @@ -3,12 +3,14 @@ use std::iter::zip; use std::rc::Rc; use std::time::Duration; +use niri_config::CornerRadius; use smithay::backend::renderer::element::utils::{ CropRenderElement, Relocate, RelocateRenderElement, }; use smithay::output::Output; use smithay::utils::{Logical, Point, Rectangle, Size}; +use super::insert_hint_element::{InsertHintElement, InsertHintRenderElement}; use super::scrolling::{Column, ColumnWidth}; use super::tile::Tile; use super::workspace::{ @@ -17,6 +19,7 @@ use super::workspace::{ use super::{ActivateWindow, HitType, LayoutElement, Options}; use crate::animation::{Animation, Clock}; use crate::input::swipe_tracker::SwipeTracker; +use crate::niri_render_elements; use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::RenderTarget; use crate::rubber_band::RubberBand; @@ -45,6 +48,12 @@ pub struct Monitor<W: LayoutElement> { pub(super) previous_workspace_id: Option<WorkspaceId>, /// In-progress switch between workspaces. pub(super) workspace_switch: Option<WorkspaceSwitch>, + /// Indication where an interactively-moved window is about to be placed. + pub(super) insert_hint: Option<InsertHint>, + /// Insert hint element for rendering. + insert_hint_element: InsertHintElement, + /// Location to render the insert hint element. + insert_hint_render_loc: Option<InsertHintRenderLoc>, /// Clock for driving animations. pub(super) clock: Clock, /// Configurable properties of the layout. @@ -73,6 +82,26 @@ pub struct WorkspaceSwitchGesture { is_touchpad: bool, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(super) enum InsertPosition { + NewColumn(usize), + InColumn(usize, usize), + Floating, +} + +#[derive(Debug)] +pub(super) struct InsertHint { + pub workspace: WorkspaceId, + pub position: InsertPosition, + pub corner_radius: CornerRadius, +} + +#[derive(Debug, Clone, Copy)] +struct InsertHintRenderLoc { + workspace: WorkspaceId, + location: Point<f64, Logical>, +} + /// Where to put a newly added window. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub enum MonitorAddWindowTarget<'a, W: LayoutElement> { @@ -90,8 +119,14 @@ pub enum MonitorAddWindowTarget<'a, W: LayoutElement> { NextTo(&'a W::Id), } -pub type MonitorRenderElement<R> = - RelocateRenderElement<CropRenderElement<WorkspaceRenderElement<R>>>; +niri_render_elements! { + MonitorInnerRenderElement<R> => { + Workspace = CropRenderElement<WorkspaceRenderElement<R>>, + InsertHint = CropRenderElement<InsertHintRenderElement>, + } +} + +pub type MonitorRenderElement<R> = RelocateRenderElement<MonitorInnerRenderElement<R>>; impl WorkspaceSwitch { pub fn current_idx(&self) -> f64 { @@ -153,6 +188,9 @@ impl<W: LayoutElement> Monitor<W> { workspaces, active_workspace_idx: 0, previous_workspace_id: None, + insert_hint: None, + insert_hint_element: InsertHintElement::new(options.insert_hint), + insert_hint_render_loc: None, workspace_switch: None, clock, options, @@ -677,8 +715,50 @@ impl<W: LayoutElement> Monitor<W> { } pub fn update_render_elements(&mut self, is_active: bool) { - for (ws, _) in self.workspaces_with_render_geo_mut() { + let mut insert_hint_ws_geo = None; + let insert_hint_ws_id = self.insert_hint.as_ref().map(|hint| hint.workspace); + + for (ws, geo) in self.workspaces_with_render_geo_mut() { ws.update_render_elements(is_active); + + if Some(ws.id()) == insert_hint_ws_id { + insert_hint_ws_geo = Some(geo); + } + } + + self.insert_hint_render_loc = None; + if let Some(hint) = &self.insert_hint { + if let Some(ws) = self.workspaces.iter().find(|ws| ws.id() == hint.workspace) { + if let Some(mut area) = ws.insert_hint_area(hint.position) { + let scale = ws.scale().fractional_scale(); + let view_size = ws.view_size(); + + // Make sure the hint is at least partially visible. + if matches!(hint.position, InsertPosition::NewColumn(_)) { + let geo = insert_hint_ws_geo.unwrap(); + + area.loc.x = area.loc.x.max(-geo.loc.x - area.size.w / 2.); + area.loc.x = area.loc.x.min(geo.loc.x + geo.size.w - area.size.w / 2.); + } + + // Round to physical pixels. + area = area.to_physical_precise_round(scale).to_logical(scale); + + let view_rect = Rectangle::new(area.loc.upscale(-1.), view_size); + self.insert_hint_element.update_render_elements( + area.size, + view_rect, + hint.corner_radius, + scale, + ); + self.insert_hint_render_loc = Some(InsertHintRenderLoc { + workspace: hint.workspace, + location: area.loc, + }); + } + } else { + error!("insert hint workspace missing from monitor"); + } } } @@ -698,6 +778,8 @@ impl<W: LayoutElement> Monitor<W> { ws.update_config(options.clone()); } + self.insert_hint_element.update_config(options.insert_hint); + self.options = options; } @@ -705,6 +787,8 @@ impl<W: LayoutElement> Monitor<W> { for ws in &mut self.workspaces { ws.update_shaders(); } + + self.insert_hint_element.update_shaders(); } pub fn move_workspace_down(&mut self) { @@ -950,10 +1034,23 @@ impl<W: LayoutElement> Monitor<W> { ) }; + // Draw the insert hint. + let mut insert_hint = None; + if !self.options.insert_hint.off { + if let Some(render_loc) = self.insert_hint_render_loc { + insert_hint = Some(( + render_loc.workspace, + self.insert_hint_element + .render(renderer, render_loc.location), + )); + } + } + self.workspaces_with_render_geo() .flat_map(move |(ws, geo)| { let map_ws_contents = move |elem: WorkspaceRenderElement<R>| { let elem = CropRenderElement::from_element(elem, scale, crop_bounds)?; + let elem = MonitorInnerRenderElement::Workspace(elem); Some(elem) }; @@ -961,7 +1058,21 @@ impl<W: LayoutElement> Monitor<W> { let floating = floating.filter_map(map_ws_contents); let scrolling = scrolling.filter_map(map_ws_contents); - let iter = floating.chain(scrolling); + let hint = if matches!(insert_hint, Some((hint_ws_id, _)) if hint_ws_id == ws.id()) + { + let iter = insert_hint.take().unwrap().1; + let iter = iter.filter_map(move |elem| { + let elem = CropRenderElement::from_element(elem, scale, crop_bounds)?; + let elem = MonitorInnerRenderElement::InsertHint(elem); + Some(elem) + }); + Some(iter) + } else { + None + }; + let hint = hint.into_iter().flatten(); + + let iter = floating.chain(hint).chain(scrolling); iter.map(move |elem| { RelocateRenderElement::from_element( diff --git a/src/layout/scrolling.rs b/src/layout/scrolling.rs index c50a6bf7..a0fccb5f 100644 --- a/src/layout/scrolling.rs +++ b/src/layout/scrolling.rs @@ -3,14 +3,14 @@ use std::iter::{self, zip}; use std::rc::Rc; use std::time::Duration; -use niri_config::{CenterFocusedColumn, CornerRadius, PresetSize, Struts}; +use niri_config::{CenterFocusedColumn, PresetSize, Struts}; use niri_ipc::{ColumnDisplay, SizeChange}; use ordered_float::NotNan; use smithay::backend::renderer::gles::GlesRenderer; use smithay::utils::{Logical, Point, Rectangle, Scale, Serial, Size}; use super::closing_window::{ClosingWindow, ClosingWindowRenderElement}; -use super::insert_hint_element::{InsertHintElement, InsertHintRenderElement}; +use super::monitor::InsertPosition; use super::tab_indicator::{TabIndicator, TabIndicatorRenderElement, TabInfo}; use super::tile::{Tile, TileRenderElement, TileRenderSnapshot}; use super::workspace::{InteractiveResize, ResolvedSize}; @@ -67,12 +67,6 @@ pub struct ScrollingSpace<W: LayoutElement> { /// Windows in the closing animation. closing_windows: Vec<ClosingWindow>, - /// Indication where an interactively-moved window is about to be placed. - insert_hint: Option<InsertHint>, - - /// Insert hint element for rendering. - insert_hint_element: InsertHintElement, - /// View size for this space. view_size: Size<f64, Logical>, @@ -96,23 +90,9 @@ niri_render_elements! { Tile = TileRenderElement<R>, ClosingWindow = ClosingWindowRenderElement, TabIndicator = TabIndicatorRenderElement, - InsertHint = InsertHintRenderElement, } } -#[derive(Debug, PartialEq)] -pub enum InsertPosition { - NewColumn(usize), - InColumn(usize, usize), - Floating, -} - -#[derive(Debug)] -pub struct InsertHint { - pub position: InsertPosition, - pub corner_radius: CornerRadius, -} - /// Extra per-column data. #[derive(Debug, Clone, Copy, PartialEq)] struct ColumnData { @@ -283,8 +263,6 @@ impl<W: LayoutElement> ScrollingSpace<W> { activate_prev_column_on_removal: None, view_offset_before_fullscreen: None, closing_windows: Vec::new(), - insert_hint: None, - insert_hint_element: InsertHintElement::new(options.insert_hint), view_size, working_area, scale, @@ -307,8 +285,6 @@ impl<W: LayoutElement> ScrollingSpace<W> { data.update(column); } - self.insert_hint_element.update_config(options.insert_hint); - self.view_size = view_size; self.working_area = working_area; self.scale = scale; @@ -319,8 +295,6 @@ impl<W: LayoutElement> ScrollingSpace<W> { for tile in self.tiles_mut() { tile.update_shaders(); } - - self.insert_hint_element.update_shaders(); } pub fn advance_animations(&mut self) { @@ -382,18 +356,6 @@ impl<W: LayoutElement> ScrollingSpace<W> { let view_rect = Rectangle::new(col_pos, view_size); col.update_render_elements(is_active, view_rect); } - - if let Some(insert_hint) = &self.insert_hint { - if let Some(area) = self.insert_hint_area(insert_hint) { - let view_rect = Rectangle::new(area.loc.upscale(-1.), view_size); - self.insert_hint_element.update_render_elements( - area.size, - view_rect, - insert_hint.corner_radius, - self.scale, - ); - } - } } pub fn tiles(&self) -> impl Iterator<Item = &Tile<W>> + '_ { @@ -754,18 +716,7 @@ impl<W: LayoutElement> ScrollingSpace<W> { self.interactive_resize = None; } - pub fn set_insert_hint(&mut self, insert_hint: InsertHint) { - if self.options.insert_hint.off { - return; - } - self.insert_hint = Some(insert_hint); - } - - pub fn clear_insert_hint(&mut self) { - self.insert_hint = None; - } - - pub fn get_insert_position(&self, pos: Point<f64, Logical>) -> InsertPosition { + pub(super) fn insert_position(&self, pos: Point<f64, Logical>) -> InsertPosition { if self.columns.is_empty() { return InsertPosition::NewColumn(0); } @@ -2274,8 +2225,11 @@ impl<W: LayoutElement> ScrollingSpace<W> { }) } - fn insert_hint_area(&self, insert_hint: &InsertHint) -> Option<Rectangle<f64, Logical>> { - let mut hint_area = match insert_hint.position { + pub(super) fn insert_hint_area( + &self, + position: InsertPosition, + ) -> Option<Rectangle<f64, Logical>> { + let mut hint_area = match position { InsertPosition::NewColumn(column_index) => { if column_index == 0 || column_index == self.columns.len() { let size = @@ -2366,19 +2320,6 @@ impl<W: LayoutElement> ScrollingSpace<W> { hint_area.loc.x -= self.view_pos(); } - let view_size = self.view_size; - - // Make sure the hint is at least partially visible. - if matches!(insert_hint.position, InsertPosition::NewColumn(_)) { - hint_area.loc.x = hint_area.loc.x.max(-hint_area.size.w / 2.); - hint_area.loc.x = hint_area.loc.x.min(view_size.w - hint_area.size.w / 2.); - } - - // Round to physical pixels. - hint_area = hint_area - .to_physical_precise_round(self.scale) - .to_logical(self.scale); - Some(hint_area) } @@ -2729,17 +2670,6 @@ impl<W: LayoutElement> ScrollingSpace<W> { let scale = Scale::from(self.scale); - // Draw the insert hint. - if let Some(insert_hint) = &self.insert_hint { - if let Some(area) = self.insert_hint_area(insert_hint) { - rv.extend( - self.insert_hint_element - .render(renderer, area.loc) - .map(ScrollingSpaceRenderElement::InsertHint), - ); - } - } - // Draw the closing windows on top of the other windows. let view_rect = Rectangle::new(Point::from((self.view_pos(), 0.)), self.view_size); for closing in self.closing_windows.iter().rev() { diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index af899966..70d436c8 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -15,12 +15,12 @@ use smithay::wayland::shell::xdg::SurfaceCachedState; use super::floating::{FloatingSpace, FloatingSpaceRenderElement}; use super::scrolling::{ - Column, ColumnWidth, InsertHint, InsertPosition, ScrollDirection, ScrollingSpace, - ScrollingSpaceRenderElement, + Column, ColumnWidth, ScrollDirection, ScrollingSpace, ScrollingSpaceRenderElement, }; use super::tile::{Tile, TileRenderSnapshot}; use super::{ - ActivateWindow, HitType, InteractiveResizeData, LayoutElement, Options, RemovedTile, SizeFrac, + ActivateWindow, HitType, InsertPosition, InteractiveResizeData, LayoutElement, Options, + RemovedTile, SizeFrac, }; use crate::animation::Clock; use crate::niri_render_elements; @@ -1597,16 +1597,15 @@ impl<W: LayoutElement> Workspace<W> { } } - pub fn set_insert_hint(&mut self, insert_hint: InsertHint) { - self.scrolling.set_insert_hint(insert_hint); + pub(super) fn scrolling_insert_position(&self, pos: Point<f64, Logical>) -> InsertPosition { + self.scrolling.insert_position(pos) } - pub fn clear_insert_hint(&mut self) { - self.scrolling.clear_insert_hint(); - } - - pub fn get_insert_position(&self, pos: Point<f64, Logical>) -> InsertPosition { - self.scrolling.get_insert_position(pos) + pub(super) fn insert_hint_area( + &self, + position: InsertPosition, + ) -> Option<Rectangle<f64, Logical>> { + self.scrolling.insert_hint_area(position) } pub fn view_offset_gesture_begin(&mut self, is_touchpad: bool) { |
