diff options
| -rw-r--r-- | src/layout/floating.rs | 79 | ||||
| -rw-r--r-- | src/layout/mod.rs | 10 | ||||
| -rw-r--r-- | src/layout/monitor.rs | 16 | ||||
| -rw-r--r-- | src/layout/tile.rs | 18 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 44 |
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 |
