From f4f2a1f6deeffa5c13d871c534ac99ea398e9175 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Sun, 22 Dec 2024 09:28:57 +0300 Subject: floating: Remember and restore window size --- src/layout/floating.rs | 37 ++++++++++++++++++++++--------------- src/layout/mod.rs | 34 +++++++++++++++++++--------------- src/layout/tile.rs | 15 +++++++++++++++ 3 files changed, 56 insertions(+), 30 deletions(-) (limited to 'src/layout') diff --git a/src/layout/floating.rs b/src/layout/floating.rs index 4565e2f2..f870b2f2 100644 --- a/src/layout/floating.rs +++ b/src/layout/floating.rs @@ -366,24 +366,27 @@ impl FloatingSpace { ) { tile.update_config(self.scale, self.options.clone()); + // Restore the previous floating window size, and in case the tile is fullscreen, + // unfullscreen it. + let floating_size = tile.floating_window_size(); let win = tile.window_mut(); - let size = if win.is_pending_fullscreen() { - let mut size = Size::from((0, 0)); - - // Make sure fixed-size through window rules keeps working. - let min_size = win.min_size(); - let max_size = win.max_size(); - if min_size.w == max_size.w { - size.w = min_size.w; - } - if min_size.h == max_size.h { - size.h = min_size.h; - } - - size + let mut size = if win.is_pending_fullscreen() { + // If the window was fullscreen without a floating size, ask for (0, 0). + floating_size.unwrap_or_default() } else { - win.size() + // If the window wasn't fullscreen without a floating size (e.g. it was tiled before), + // ask for the current size. + floating_size.unwrap_or_else(|| win.size_to_request()) }; + // Make sure fixed-size through window rules keeps working. + let min_size = win.min_size(); + let max_size = win.max_size(); + if min_size.w != 0 && min_size.w == max_size.w { + size.w = min_size.w; + } + if min_size.h != 0 && min_size.h == max_size.h { + size.h = min_size.h; + } win.request_size_once(size, true); if activate || self.tiles.is_empty() { @@ -761,6 +764,10 @@ impl FloatingSpace { tile.update_window(); data.update(tile); + // Update the stored floating window size. + let floating_size = tile.window().size_to_request(); + tile.set_floating_window_size(floating_size); + // When resizing by top/left edge, update the position accordingly. if let Some(resize) = resize { let mut offset = Point::from((0., 0.)); diff --git a/src/layout/mod.rs b/src/layout/mod.rs index acc5257f..8e86c0ca 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1152,6 +1152,12 @@ impl Layout { if let Some(InteractiveMoveState::Moving(move_)) = &mut self.interactive_move { if move_.tile.window().id() == window { move_.tile.update_window(); + + // Update the floating size in case the window resizes itself during an interactive + // move. + let floating_size = move_.tile.window().size_to_request(); + move_.tile.set_floating_window_size(floating_size); + return; } } @@ -3254,35 +3260,33 @@ impl Layout { Rc::new(Options::clone(&self.options).adjusted_for_scale(scale)), ); - // Unfullscreen and let the window pick a natural size. - // - // TODO - // When we have floating, we will want to always send a (0, 0) size here, not just - // to unfullscreen. However, when implementing that, remember to check how GTK - // tiled window size restoration works. It seems to remember *some* last size with - // prefer-no-csd, and occasionally that last size can become the full-width size - // rather than a smaller size, which is annoying. Need to see if niri can use some - // heuristics to make this case behave better. + // Unfullscreen. + let floating_size = tile.floating_window_size(); + let unfullscreen_to_floating = tile.unfullscreen_to_floating(); let win = tile.window_mut(); if win.is_pending_fullscreen() { - let mut size = Size::from((0, 0)); + // If we're unfullscreening to floating, use the stored floating size, + // otherwise use (0, 0). + let mut size = if unfullscreen_to_floating { + floating_size.unwrap_or_default() + } else { + Size::from((0, 0)) + }; // Make sure fixed-size through window rules keeps working. let min_size = win.min_size(); let max_size = win.max_size(); - if min_size.w == max_size.w { + if min_size.w != 0 && min_size.w == max_size.w { size.w = min_size.w; } - if min_size.h == max_size.h { + if min_size.h != 0 && min_size.h == max_size.h { size.h = min_size.h; } win.request_size_once(size, true); // If we're unfullscreening to floating, default to the floating layout. - is_floating = tile.unfullscreen_to_floating(); - } else { - win.request_size_once(win.size(), true); + is_floating = unfullscreen_to_floating; } let mut data = InteractiveMoveData { diff --git a/src/layout/tile.rs b/src/layout/tile.rs index 1b9aac2d..13adbd50 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -54,6 +54,12 @@ pub struct Tile { /// Whether the tile should float upon unfullscreening. unfullscreen_to_floating: bool, + /// The size that the window should assume when going floating. + /// + /// This is generally the last size the window had when it was floating. It can be unknown if + /// the window starts out in the tiling layout or fullscreen. + floating_window_size: Option>, + /// The animation upon opening a window. open_animation: Option, @@ -128,6 +134,7 @@ impl Tile { fullscreen_backdrop: SolidColorBuffer::new((0., 0.), [0., 0., 0., 1.]), fullscreen_size: Default::default(), unfullscreen_to_floating: false, + floating_window_size: None, open_animation: None, resize_animation: None, move_x_animation: None, @@ -935,6 +942,14 @@ impl Tile { self.unfullscreen_to_floating = value; } + pub fn floating_window_size(&self) -> Option> { + self.floating_window_size + } + + pub fn set_floating_window_size(&mut self, floating_window_size: Size) { + self.floating_window_size = Some(floating_window_size); + } + #[cfg(test)] pub fn verify_invariants(&self) { use approx::assert_abs_diff_eq; -- cgit