From ee9f756431cfc6e38a27ef717c12cba9df8c5491 Mon Sep 17 00:00:00 2001 From: lars-berger Date: Tue, 3 Dec 2024 01:44:17 +0800 Subject: [PATCH] feat: restore to previous tiling size from minimized/fullscreen (#876) --- .../windows/commands/update_window_state.rs | 57 ++++++++++++++----- packages/wm/src/windows/insertion_target.rs | 9 +++ packages/wm/src/windows/mod.rs | 2 + packages/wm/src/windows/non_tiling_window.rs | 11 ++-- packages/wm/src/windows/tiling_window.rs | 5 +- 5 files changed, 63 insertions(+), 21 deletions(-) create mode 100644 packages/wm/src/windows/insertion_target.rs diff --git a/packages/wm/src/windows/commands/update_window_state.rs b/packages/wm/src/windows/commands/update_window_state.rs index 8c3d581ea..5ae3ee546 100644 --- a/packages/wm/src/windows/commands/update_window_state.rs +++ b/packages/wm/src/windows/commands/update_window_state.rs @@ -3,12 +3,15 @@ use tracing::info; use crate::{ containers::{ - commands::{move_container_within_tree, replace_container}, - traits::CommonGetters, + commands::{ + move_container_within_tree, replace_container, + resize_tiling_container, + }, + traits::{CommonGetters, TilingSizeGetters}, WindowContainer, }, user_config::UserConfig, - windows::{traits::WindowGetters, WindowState}, + windows::{traits::WindowGetters, InsertionTarget, WindowState}, wm_state::WmState, }; @@ -49,17 +52,26 @@ fn set_tiling( let workspace = window.workspace().context("Window has no workspace.")?; - // Get the position in the tree to insert the new tiling window. This - // will be the window's previous tiling position if it has one, or - // instead beside the last focused tiling window in the workspace. - let (target_parent, target_index) = window - .insertion_target() - // Check whether insertion target is still valid. - .filter(|(insertion_target, _)| { + // Check whether insertion target is still valid. + let insertion_target = + window.insertion_target().filter(|insertion_target| { insertion_target + .target_parent .workspace() .map(|workspace| workspace.is_displayed()) .unwrap_or(false) + }); + + // Get the position in the tree to insert the new tiling window. This + // will be the window's previous tiling position if it has one, or + // instead beside the last focused tiling window in the workspace. + let (target_parent, target_index) = insertion_target + .as_ref() + .map(|insertion_target| { + ( + insertion_target.target_parent.clone(), + insertion_target.target_index, + ) }) // Fallback to the last focused tiling window within the workspace. .or_else(|| { @@ -77,7 +89,7 @@ fn set_tiling( // Replace the original window with the created tiling window. replace_container( tiling_window.clone().into(), - window.parent().context("No parent")?, + window.parent().context("No parent.")?, window.index(), )?; @@ -88,6 +100,17 @@ fn set_tiling( state, )?; + if let Some(insertion_target) = &insertion_target { + let size_scale = (insertion_target.prev_sibling_count + 1) as f32 + / (tiling_window.tiling_siblings().count() + 1) as f32; + + // Scale the window's previous size based on the current number of + // siblings. E.g. if the window was 0.5 with 1 sibling, and now has 2 + // siblings, scale to 0.5 * (2/3) to maintain proportional sizing. + let target_size = insertion_target.prev_tiling_size * size_scale; + resize_tiling_container(&tiling_window.clone().into(), target_size); + } + state .pending_sync .containers_to_redraw @@ -137,9 +160,15 @@ fn set_non_tiling( let parent = window.parent().context("No parent")?; let workspace = window.workspace().context("No workspace.")?; - let insertion_target = (parent.clone(), window.index()); - let non_tiling_window = - window.to_non_tiling(target_state.clone(), Some(insertion_target)); + let non_tiling_window = window.to_non_tiling( + target_state.clone(), + Some(InsertionTarget { + target_parent: parent.clone(), + target_index: window.index(), + prev_tiling_size: window.tiling_size(), + prev_sibling_count: window.tiling_siblings().count(), + }), + ); // Non-tiling windows should always be direct children of the // workspace. diff --git a/packages/wm/src/windows/insertion_target.rs b/packages/wm/src/windows/insertion_target.rs new file mode 100644 index 000000000..905b3a824 --- /dev/null +++ b/packages/wm/src/windows/insertion_target.rs @@ -0,0 +1,9 @@ +use crate::containers::Container; + +#[derive(Debug, Clone)] +pub struct InsertionTarget { + pub target_parent: Container, + pub target_index: usize, + pub prev_tiling_size: f32, + pub prev_sibling_count: usize, +} diff --git a/packages/wm/src/windows/mod.rs b/packages/wm/src/windows/mod.rs index 9d4b32447..213c28d5d 100644 --- a/packages/wm/src/windows/mod.rs +++ b/packages/wm/src/windows/mod.rs @@ -1,5 +1,6 @@ mod active_drag; pub mod commands; +mod insertion_target; mod non_tiling_window; mod tiling_window; pub mod traits; @@ -7,6 +8,7 @@ mod window_dto; mod window_state; pub use active_drag::*; +pub use insertion_target::*; pub use non_tiling_window::*; pub use tiling_window::*; pub use window_dto::*; diff --git a/packages/wm/src/windows/non_tiling_window.rs b/packages/wm/src/windows/non_tiling_window.rs index f195ef572..1a946e316 100644 --- a/packages/wm/src/windows/non_tiling_window.rs +++ b/packages/wm/src/windows/non_tiling_window.rs @@ -8,7 +8,8 @@ use anyhow::Context; use uuid::Uuid; use super::{ - traits::WindowGetters, ActiveDrag, TilingWindow, WindowDto, WindowState, + traits::WindowGetters, ActiveDrag, InsertionTarget, TilingWindow, + WindowDto, WindowState, }; use crate::{ common::{platform::NativeWindow, DisplayState, Rect, RectDelta}, @@ -32,7 +33,7 @@ struct NonTilingWindowInner { native: NativeWindow, state: WindowState, prev_state: Option, - insertion_target: Option<(Container, usize)>, + insertion_target: Option, display_state: DisplayState, border_delta: RectDelta, has_pending_dpi_adjustment: bool, @@ -49,7 +50,7 @@ impl NonTilingWindow { state: WindowState, prev_state: Option, border_delta: RectDelta, - insertion_target: Option<(Container, usize)>, + insertion_target: Option, floating_placement: Rect, has_custom_floating_placement: bool, done_window_rules: Vec, @@ -76,13 +77,13 @@ impl NonTilingWindow { Self(Rc::new(RefCell::new(window))) } - pub fn insertion_target(&self) -> Option<(Container, usize)> { + pub fn insertion_target(&self) -> Option { self.0.borrow().insertion_target.clone() } pub fn set_insertion_target( &self, - insertion_target: Option<(Container, usize)>, + insertion_target: Option, ) { self.0.borrow_mut().insertion_target = insertion_target; } diff --git a/packages/wm/src/windows/tiling_window.rs b/packages/wm/src/windows/tiling_window.rs index b384d198f..5a3f24320 100644 --- a/packages/wm/src/windows/tiling_window.rs +++ b/packages/wm/src/windows/tiling_window.rs @@ -8,7 +8,8 @@ use anyhow::Context; use uuid::Uuid; use super::{ - traits::WindowGetters, NonTilingWindow, WindowDto, WindowState, + traits::WindowGetters, InsertionTarget, NonTilingWindow, WindowDto, + WindowState, }; use crate::{ common::{ @@ -88,7 +89,7 @@ impl TilingWindow { pub fn to_non_tiling( &self, state: WindowState, - insertion_target: Option<(Container, usize)>, + insertion_target: Option, ) -> NonTilingWindow { NonTilingWindow::new( Some(self.id()),