aboutsummaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
authoryrkv <yegor@tydbits.com>2025-08-16 01:42:08 -0700
committerGitHub <noreply@github.com>2025-08-16 11:42:08 +0300
commitaf30cc8df68b29973c8b9eec290f9e6b93463929 (patch)
treec216831fe217e191c958545b7536183d67b1b186 /src/layout
parenta003e013074b5188a2b1f2364fff90fb4caf972a (diff)
downloadniri-af30cc8df68b29973c8b9eec290f9e6b93463929.tar.gz
niri-af30cc8df68b29973c8b9eec290f9e6b93463929.tar.bz2
niri-af30cc8df68b29973c8b9eec290f9e6b93463929.zip
niri-ipc: Add window positions and sizes (#1265)
* Add window sizes and positions to the IPC * basic fixes * report window_loc instead of window pos * clean ups * make scrolling indices 1-based * add printing to niri msg windows * don't include render offset in floating tile pos --------- Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/floating.rs18
-rw-r--r--src/layout/mod.rs19
-rw-r--r--src/layout/scrolling.rs18
-rw-r--r--src/layout/tile.rs14
-rw-r--r--src/layout/workspace.rs8
5 files changed, 67 insertions, 10 deletions
diff --git a/src/layout/floating.rs b/src/layout/floating.rs
index 98927c0d..bd976d7d 100644
--- a/src/layout/floating.rs
+++ b/src/layout/floating.rs
@@ -3,7 +3,7 @@ use std::iter::zip;
use std::rc::Rc;
use niri_config::{PresetSize, RelativeTo};
-use niri_ipc::{PositionChange, SizeChange};
+use niri_ipc::{PositionChange, SizeChange, WindowLayout};
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::utils::{Logical, Point, Rectangle, Scale, Serial, Size};
@@ -322,6 +322,22 @@ impl<W: LayoutElement> FloatingSpace<W> {
})
}
+ pub fn tiles_with_ipc_layouts(&self) -> impl Iterator<Item = (&Tile<W>, WindowLayout)> {
+ let scale = self.scale;
+ self.tiles_with_offsets().map(move |(tile, offset)| {
+ // Do not include animated render offset here to avoid IPC spam.
+ let pos = offset;
+ // Round to physical pixels.
+ let pos = pos.to_physical_precise_round(scale).to_logical(scale);
+
+ let layout = WindowLayout {
+ tile_pos_in_workspace_view: Some(pos.into()),
+ ..tile.ipc_layout_template()
+ };
+ (tile, layout)
+ })
+ }
+
pub fn new_window_toplevel_bounds(&self, rules: &ResolvedWindowRules) -> Size<i32, Logical> {
let border_config = rules.border.resolve_against(self.options.border);
compute_toplevel_bounds(border_config, self.working_area.size)
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 7bf25b42..52e3173b 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -42,7 +42,7 @@ use niri_config::{
CenterFocusedColumn, Config, CornerRadius, FloatOrInt, PresetSize, Struts,
Workspace as WorkspaceConfig, WorkspaceReference,
};
-use niri_ipc::{ColumnDisplay, PositionChange, SizeChange};
+use niri_ipc::{ColumnDisplay, PositionChange, SizeChange, WindowLayout};
use scrolling::{Column, ColumnWidth};
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;
use smithay::backend::renderer::element::utils::RescaleRenderElement;
@@ -1742,25 +1742,30 @@ impl<W: LayoutElement> Layout<W> {
moving_window.chain(mon_windows)
}
- pub fn with_windows(&self, mut f: impl FnMut(&W, Option<&Output>, Option<WorkspaceId>)) {
+ pub fn with_windows(
+ &self,
+ mut f: impl FnMut(&W, Option<&Output>, Option<WorkspaceId>, WindowLayout),
+ ) {
if let Some(InteractiveMoveState::Moving(move_)) = &self.interactive_move {
- f(move_.tile.window(), Some(&move_.output), None);
+ // We don't fill any positions for interactively moved windows.
+ let layout = move_.tile.ipc_layout_template();
+ f(move_.tile.window(), Some(&move_.output), None, layout);
}
match &self.monitor_set {
MonitorSet::Normal { monitors, .. } => {
for mon in monitors {
for ws in &mon.workspaces {
- for win in ws.windows() {
- f(win, Some(&mon.output), Some(ws.id()));
+ for (tile, layout) in ws.tiles_with_ipc_layouts() {
+ f(tile.window(), Some(&mon.output), Some(ws.id()), layout);
}
}
}
}
MonitorSet::NoOutputs { workspaces } => {
for ws in workspaces {
- for win in ws.windows() {
- f(win, None, Some(ws.id()));
+ for (tile, layout) in ws.tiles_with_ipc_layouts() {
+ f(tile.window(), None, Some(ws.id()), layout);
}
}
}
diff --git a/src/layout/scrolling.rs b/src/layout/scrolling.rs
index a60581af..551fa692 100644
--- a/src/layout/scrolling.rs
+++ b/src/layout/scrolling.rs
@@ -4,7 +4,7 @@ use std::rc::Rc;
use std::time::Duration;
use niri_config::{CenterFocusedColumn, PresetSize, Struts};
-use niri_ipc::{ColumnDisplay, SizeChange};
+use niri_ipc::{ColumnDisplay, SizeChange, WindowLayout};
use ordered_float::NotNan;
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::utils::{Logical, Point, Rectangle, Scale, Serial, Size};
@@ -2366,6 +2366,22 @@ impl<W: LayoutElement> ScrollingSpace<W> {
})
}
+ pub fn tiles_with_ipc_layouts(&self) -> impl Iterator<Item = (&Tile<W>, WindowLayout)> {
+ self.columns
+ .iter()
+ .enumerate()
+ .flat_map(move |(col_idx, col)| {
+ col.tiles().enumerate().map(move |(tile_idx, (tile, _))| {
+ let layout = WindowLayout {
+ // Our indices are 1-based, consistent with the actions.
+ pos_in_scrolling_layout: Some((col_idx + 1, tile_idx + 1)),
+ ..tile.ipc_layout_template()
+ };
+ (tile, layout)
+ })
+ })
+ }
+
pub(super) fn insert_hint_area(
&self,
position: InsertPosition,
diff --git a/src/layout/tile.rs b/src/layout/tile.rs
index a4fe8a57..1555b129 100644
--- a/src/layout/tile.rs
+++ b/src/layout/tile.rs
@@ -2,6 +2,7 @@ use core::f64;
use std::rc::Rc;
use niri_config::{Color, CornerRadius, GradientInterpolation};
+use niri_ipc::WindowLayout;
use smithay::backend::renderer::element::{Element, Kind};
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::utils::{Logical, Point, Rectangle, Scale, Size};
@@ -688,6 +689,19 @@ impl<W: LayoutElement> Tile<W> {
loc
}
+ /// Returns a partially-filled [`WindowLayout`].
+ ///
+ /// Only the sizing properties that a [`Tile`] can fill are filled.
+ pub fn ipc_layout_template(&self) -> WindowLayout {
+ WindowLayout {
+ pos_in_scrolling_layout: None,
+ tile_size: self.tile_size().into(),
+ window_size: self.window().size().into(),
+ tile_pos_in_workspace_view: None,
+ window_offset_in_tile: self.window_loc().into(),
+ }
+ }
+
fn is_in_input_region(&self, mut point: Point<f64, Logical>) -> bool {
point -= self.window_loc().to_f64();
self.window.is_in_input_region(point)
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index 588a6971..c01df8fd 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -5,7 +5,7 @@ use std::time::Duration;
use niri_config::{
CenterFocusedColumn, CornerRadius, OutputName, PresetSize, Workspace as WorkspaceConfig,
};
-use niri_ipc::{ColumnDisplay, PositionChange, SizeChange};
+use niri_ipc::{ColumnDisplay, PositionChange, SizeChange, WindowLayout};
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::desktop::{layer_map_for_output, Window};
use smithay::output::Output;
@@ -1427,6 +1427,12 @@ impl<W: LayoutElement> Workspace<W> {
floating.chain(scrolling)
}
+ pub fn tiles_with_ipc_layouts(&self) -> impl Iterator<Item = (&Tile<W>, WindowLayout)> {
+ let scrolling = self.scrolling.tiles_with_ipc_layouts();
+ let floating = self.floating.tiles_with_ipc_layouts();
+ floating.chain(scrolling)
+ }
+
pub fn active_tile_visual_rectangle(&self) -> Option<Rectangle<f64, Logical>> {
if self.floating_is_active.get() {
self.floating.active_tile_visual_rectangle()