mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-22 02:01:55 +07:00
Remember floating window position
This commit is contained in:
+48
-27
@@ -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,7 +409,10 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
}
|
||||
}
|
||||
|
||||
let pos = pos.unwrap_or_else(|| {
|
||||
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())
|
||||
});
|
||||
|
||||
@@ -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.;
|
||||
|
||||
+8
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-11
@@ -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,
|
||||
|
||||
+17
-1
@@ -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;
|
||||
|
||||
+23
-13
@@ -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();
|
||||
|
||||
// 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(),
|
||||
);
|
||||
self.floating
|
||||
.add_tile(removed.tile, Some(pos), target_is_active);
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user