mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-22 02:01:55 +07:00
layout: Move insert hint from ScrollingSpace to Monitor
This commit is contained in:
+13
-9
@@ -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();
|
||||
|
||||
+115
-4
@@ -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(
|
||||
|
||||
+8
-78
@@ -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() {
|
||||
|
||||
+10
-11
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user