aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/layout/floating.rs79
-rw-r--r--src/layout/mod.rs10
-rw-r--r--src/layout/monitor.rs16
-rw-r--r--src/layout/tile.rs18
-rw-r--r--src/layout/workspace.rs44
5 files changed, 107 insertions, 60 deletions
diff --git a/src/layout/floating.rs b/src/layout/floating.rs
index 6b997405..8054497c 100644
--- a/src/layout/floating.rs
+++ b/src/layout/floating.rs
@@ -10,7 +10,9 @@ use super::closing_window::{ClosingWindow, ClosingWindowRenderElement};
use super::scrolling::ColumnWidth;
use super::tile::{Tile, TileRenderElement, TileRenderSnapshot};
use super::workspace::InteractiveResize;
-use super::{ConfigureIntent, InteractiveResizeData, LayoutElement, Options, RemovedTile};
+use super::{
+ ConfigureIntent, InteractiveResizeData, LayoutElement, Options, RemovedTile, SizeFrac,
+};
use crate::animation::{Animation, Clock};
use crate::niri_render_elements;
use crate::render_helpers::renderer::NiriRenderer;
@@ -68,9 +70,6 @@ niri_render_elements! {
}
}
-/// Size-relative units.
-struct SizeFrac;
-
/// Extra per-tile data.
#[derive(Debug, Clone, Copy, PartialEq)]
struct Data {
@@ -106,11 +105,30 @@ impl Data {
rv
}
+ pub fn scale_by_working_area(
+ area: Rectangle<f64, Logical>,
+ pos: Point<f64, SizeFrac>,
+ ) -> Point<f64, Logical> {
+ let mut logical_pos = Point::from((pos.x, pos.y));
+ logical_pos.x *= area.size.w;
+ logical_pos.y *= area.size.h;
+ logical_pos += area.loc;
+ logical_pos
+ }
+
+ pub fn logical_to_size_frac_in_working_area(
+ area: Rectangle<f64, Logical>,
+ logical_pos: Point<f64, Logical>,
+ ) -> Point<f64, SizeFrac> {
+ let pos = logical_pos - area.loc;
+ let mut pos = Point::from((pos.x, pos.y));
+ pos.x /= f64::max(area.size.w, 1.0);
+ pos.y /= f64::max(area.size.h, 1.0);
+ pos
+ }
+
fn recompute_logical_pos(&mut self) {
- let mut logical_pos = Point::from((self.pos.x, self.pos.y));
- logical_pos.x *= self.working_area.size.w;
- logical_pos.y *= self.working_area.size.h;
- logical_pos += self.working_area.loc;
+ let mut logical_pos = Self::scale_by_working_area(self.working_area, self.pos);
// Make sure the window doesn't go too much off-screen. Numbers taken from Mutter.
let min_on_screen_hor = f64::clamp(self.size.w / 4., 10., 75.);
@@ -152,12 +170,7 @@ impl Data {
}
pub fn set_logical_pos(&mut self, logical_pos: Point<f64, Logical>) {
- let pos = logical_pos - self.working_area.loc;
- let mut pos = Point::from((pos.x, pos.y));
- pos.x /= f64::max(self.working_area.size.w, 1.0);
- pos.y /= f64::max(self.working_area.size.h, 1.0);
-
- self.pos = pos;
+ self.pos = Self::logical_to_size_frac_in_working_area(self.working_area, logical_pos);
// This will clamp the logical position to the current working area.
self.recompute_logical_pos();
@@ -353,17 +366,11 @@ impl<W: LayoutElement> FloatingSpace<W> {
self.tiles.is_empty()
}
- pub fn add_tile(&mut self, tile: Tile<W>, pos: Option<Point<f64, Logical>>, activate: bool) {
- self.add_tile_at(0, tile, pos, activate);
+ pub fn add_tile(&mut self, tile: Tile<W>, activate: bool) {
+ self.add_tile_at(0, tile, activate);
}
- fn add_tile_at(
- &mut self,
- mut idx: usize,
- mut tile: Tile<W>,
- pos: Option<Point<f64, Logical>>,
- activate: bool,
- ) {
+ fn add_tile_at(&mut self, mut idx: usize, mut tile: Tile<W>, activate: bool) {
tile.update_config(self.scale, self.options.clone());
// Restore the previous floating window size, and in case the tile is fullscreen,
@@ -402,9 +409,12 @@ impl<W: LayoutElement> FloatingSpace<W> {
}
}
- let pos = pos.unwrap_or_else(|| {
- center_preferring_top_left_in_area(self.working_area, tile.tile_size())
- });
+ let pos = tile
+ .floating_pos()
+ .map(|pos| self.scale_by_working_area(pos))
+ .unwrap_or_else(|| {
+ center_preferring_top_left_in_area(self.working_area, tile.tile_size())
+ });
let data = Data::new(self.working_area, &tile, pos);
self.data.insert(idx, data);
@@ -413,7 +423,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
self.bring_up_descendants_of(idx);
}
- pub fn add_tile_above(&mut self, above: &W::Id, tile: Tile<W>) {
+ pub fn add_tile_above(&mut self, above: &W::Id, mut tile: Tile<W>) {
// Activate the new window if above was active.
let activate = Some(above) == self.active_window_id.as_ref();
@@ -424,8 +434,9 @@ impl<W: LayoutElement> FloatingSpace<W> {
let tile_size = tile.tile_size();
let pos = above_pos + (above_size.to_point() - tile_size.to_point()).downscale(2.);
let pos = self.clamp_within_working_area(pos, tile_size);
+ tile.set_floating_pos(self.logical_to_size_frac(pos));
- self.add_tile_at(idx, tile, Some(pos), activate);
+ self.add_tile_at(idx, tile, activate);
}
fn bring_up_descendants_of(&mut self, idx: usize) {
@@ -467,7 +478,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
fn remove_tile_by_idx(&mut self, idx: usize) -> RemovedTile<W> {
let mut tile = self.tiles.remove(idx);
- self.data.remove(idx);
+ let data = self.data.remove(idx);
if self.tiles.is_empty() {
self.active_window_id = None;
@@ -487,6 +498,8 @@ impl<W: LayoutElement> FloatingSpace<W> {
if let Some(size) = tile.window().expected_size() {
tile.set_floating_window_size(size);
}
+ // Store the floating position.
+ tile.set_floating_pos(data.pos);
let width = ColumnWidth::Fixed(tile.window_size().w);
RemovedTile {
@@ -934,6 +947,14 @@ impl<W: LayoutElement> FloatingSpace<W> {
rect.loc
}
+ fn scale_by_working_area(&self, pos: Point<f64, SizeFrac>) -> Point<f64, Logical> {
+ Data::scale_by_working_area(self.working_area, pos)
+ }
+
+ pub fn logical_to_size_frac(&self, logical_pos: Point<f64, Logical>) -> Point<f64, SizeFrac> {
+ Data::logical_to_size_frac_in_working_area(self.working_area, logical_pos)
+ }
+
fn move_and_animate(&mut self, idx: usize, new_pos: Point<f64, Logical>) {
// Moves up to this logical pixel distance are not animated.
const ANIMATION_THRESHOLD_SQ: f64 = 10. * 10.;
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 26521f3e..2ed08ba8 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -81,6 +81,9 @@ pub const RESIZE_ANIMATION_THRESHOLD: f64 = 10.;
/// Pointer needs to move this far to pull a window from the layout.
const INTERACTIVE_MOVE_START_THRESHOLD: f64 = 256. * 256.;
+/// Size-relative units.
+pub struct SizeFrac;
+
niri_render_elements! {
LayoutElementRenderElement<R> => {
Wayland = WaylandSurfaceRenderElement<R>,
@@ -3482,14 +3485,17 @@ impl<W: LayoutElement> Layout<W> {
InsertPosition::Floating => {
let pos = move_.tile_render_location() - offset;
+ let mut tile = move_.tile;
+ let pos = mon.workspaces[ws_idx].floating_logical_to_size_frac(pos);
+ tile.set_floating_pos(pos);
+
// Set the floating size so it takes into account any window resizing that
// took place during the move.
- let mut tile = move_.tile;
if let Some(size) = tile.window().expected_size() {
tile.set_floating_window_size(size);
}
- mon.add_floating_tile(ws_idx, tile, Some(pos), true);
+ mon.add_floating_tile(ws_idx, tile, true);
}
}
diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs
index 844e932d..3ef1b605 100644
--- a/src/layout/monitor.rs
+++ b/src/layout/monitor.rs
@@ -324,16 +324,10 @@ impl<W: LayoutElement> Monitor<W> {
}
}
- pub fn add_floating_tile(
- &mut self,
- mut workspace_idx: usize,
- tile: Tile<W>,
- pos: Option<Point<f64, Logical>>,
- activate: bool,
- ) {
+ pub fn add_floating_tile(&mut self, mut workspace_idx: usize, tile: Tile<W>, activate: bool) {
let workspace = &mut self.workspaces[workspace_idx];
- workspace.add_floating_tile(tile, pos, activate);
+ workspace.add_floating_tile(tile, activate);
// After adding a new window, workspace becomes this output's own.
workspace.original_output = OutputId::new(&self.output);
@@ -531,7 +525,7 @@ impl<W: LayoutElement> Monitor<W> {
};
if removed.is_floating {
- self.add_floating_tile(new_idx, removed.tile, None, true);
+ self.add_floating_tile(new_idx, removed.tile, true);
} else {
self.add_tile(
new_idx,
@@ -558,7 +552,7 @@ impl<W: LayoutElement> Monitor<W> {
};
if removed.is_floating {
- self.add_floating_tile(new_idx, removed.tile, None, true);
+ self.add_floating_tile(new_idx, removed.tile, true);
} else {
self.add_tile(
new_idx,
@@ -601,7 +595,7 @@ impl<W: LayoutElement> Monitor<W> {
};
if removed.is_floating {
- self.add_floating_tile(new_idx, removed.tile, None, activate);
+ self.add_floating_tile(new_idx, removed.tile, activate);
} else {
self.add_tile(
new_idx,
diff --git a/src/layout/tile.rs b/src/layout/tile.rs
index 13adbd50..586b950a 100644
--- a/src/layout/tile.rs
+++ b/src/layout/tile.rs
@@ -9,7 +9,7 @@ use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform};
use super::focus_ring::{FocusRing, FocusRingRenderElement};
use super::opening_window::{OpenAnimation, OpeningWindowRenderElement};
use super::{
- LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot, Options,
+ LayoutElement, LayoutElementRenderElement, LayoutElementRenderSnapshot, Options, SizeFrac,
RESIZE_ANIMATION_THRESHOLD,
};
use crate::animation::{Animation, Clock};
@@ -60,6 +60,13 @@ pub struct Tile<W: LayoutElement> {
/// the window starts out in the tiling layout or fullscreen.
floating_window_size: Option<Size<i32, Logical>>,
+ /// The position that the tile should assume when going floating, relative to the floating
+ /// space working area.
+ ///
+ /// This is generally the last position the tile had when it was floating. It can be unknown if
+ /// the window starts out in the tiling layout.
+ floating_pos: Option<Point<f64, SizeFrac>>,
+
/// The animation upon opening a window.
open_animation: Option<OpenAnimation>,
@@ -135,6 +142,7 @@ impl<W: LayoutElement> Tile<W> {
fullscreen_size: Default::default(),
unfullscreen_to_floating: false,
floating_window_size: None,
+ floating_pos: None,
open_animation: None,
resize_animation: None,
move_x_animation: None,
@@ -950,6 +958,14 @@ impl<W: LayoutElement> Tile<W> {
self.floating_window_size = Some(floating_window_size);
}
+ pub fn floating_pos(&self) -> Option<Point<f64, SizeFrac>> {
+ self.floating_pos
+ }
+
+ pub fn set_floating_pos(&mut self, floating_pos: Point<f64, SizeFrac>) {
+ self.floating_pos = Some(floating_pos);
+ }
+
#[cfg(test)]
pub fn verify_invariants(&self) {
use approx::assert_abs_diff_eq;
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index 00dc5a58..6feb7ce9 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -18,7 +18,7 @@ use super::scrolling::{
Column, ColumnWidth, InsertHint, InsertPosition, ScrollingSpace, ScrollingSpaceRenderElement,
};
use super::tile::{Tile, TileRenderSnapshot};
-use super::{InteractiveResizeData, LayoutElement, Options, RemovedTile};
+use super::{InteractiveResizeData, LayoutElement, Options, RemovedTile, SizeFrac};
use crate::animation::Clock;
use crate::niri_render_elements;
use crate::render_helpers::renderer::NiriRenderer;
@@ -503,7 +503,7 @@ impl<W: LayoutElement> Workspace<W> {
// If the tile is pending fullscreen, open it in the scrolling layout where it can go
// fullscreen.
if is_floating && !tile.window().is_pending_fullscreen() {
- self.add_floating_tile(tile, None, activate);
+ self.add_floating_tile(tile, activate);
} else {
self.add_tile(None, tile, activate, width, is_full_width);
}
@@ -526,14 +526,9 @@ impl<W: LayoutElement> Workspace<W> {
}
}
- pub fn add_floating_tile(
- &mut self,
- tile: Tile<W>,
- pos: Option<Point<f64, Logical>>,
- activate: bool,
- ) {
+ pub fn add_floating_tile(&mut self, tile: Tile<W>, activate: bool) {
self.enter_output_for_window(tile.window());
- self.floating.add_tile(tile, pos, activate);
+ self.floating.add_tile(tile, activate);
if activate || self.scrolling.is_empty() {
self.floating_is_active = FloatingActive::Yes;
@@ -578,7 +573,7 @@ impl<W: LayoutElement> Workspace<W> {
pub fn add_tile_right_of(
&mut self,
right_of: &W::Id,
- tile: Tile<W>,
+ mut tile: Tile<W>,
width: ColumnWidth,
is_full_width: bool,
is_floating: bool,
@@ -605,8 +600,10 @@ impl<W: LayoutElement> Workspace<W> {
let pos = render_pos
+ (right_of_tile.tile_size().to_point() - tile_size.to_point()).downscale(2.);
let pos = self.floating.clamp_within_working_area(pos, tile_size);
+ let pos = self.floating.logical_to_size_frac(pos);
+ tile.set_floating_pos(pos);
- self.floating.add_tile(tile, Some(pos), activate);
+ self.floating.add_tile(tile, activate);
if activate {
self.floating_is_active = FloatingActive::Yes;
}
@@ -1087,12 +1084,18 @@ impl<W: LayoutElement> Workspace<W> {
} else {
let mut removed = self.scrolling.remove_tile(&id, Transaction::new());
removed.tile.stop_move_animations();
- let pos = self.floating.clamp_within_working_area(
- render_pos + Point::from((50., 50.)),
- removed.tile.tile_size(),
- );
- self.floating
- .add_tile(removed.tile, Some(pos), target_is_active);
+
+ // Come up with a default floating position close to the tile position.
+ if removed.tile.floating_pos().is_none() {
+ let pos = self.floating.clamp_within_working_area(
+ render_pos + Point::from((50., 50.)),
+ removed.tile.tile_size(),
+ );
+ let pos = self.floating.logical_to_size_frac(pos);
+ removed.tile.set_floating_pos(pos);
+ }
+
+ self.floating.add_tile(removed.tile, target_is_active);
if target_is_active {
self.floating_is_active = FloatingActive::Yes;
}
@@ -1436,6 +1439,13 @@ impl<W: LayoutElement> Workspace<W> {
self.floating_is_active.get()
}
+ pub fn floating_logical_to_size_frac(
+ &self,
+ logical_pos: Point<f64, Logical>,
+ ) -> Point<f64, SizeFrac> {
+ self.floating.logical_to_size_frac(logical_pos)
+ }
+
#[cfg(test)]
pub fn scrolling(&self) -> &ScrollingSpace<W> {
&self.scrolling