feat: add invariant-safe window stacks

This commit is contained in:
Samuel Onoja committed 2026-09-24 11:30:26 +01:00
1 parent 6060257ffe
commit da4aaf9fb0
3 files changed
+327 -15

No files matched your search

+58
View File
@@ -165,12 +165,46 @@ impl WorkspaceSet {
));
}
if self.placement(window) == Some(WindowPlacement::Tiled) {
self.active_mut().layout.activate_window(window)?;
}
self.active_mut().last_focused = Some(window);
debug_assert!(self.validate().is_ok());
Ok(())
}
pub fn stack_window(
&mut self,
window: WindowId,
target: WindowId,
) -> Result<(), WorkspaceError> {
let workspace = self
.workspace_for_window(window)
.ok_or(LayoutError::UnknownWindow(window))?;
if self.workspace_for_window(target) != Some(workspace) {
return Err(WorkspaceError::InvalidState(
"stack windows belong to different workspaces",
));
}
if self.placement(window) != Some(WindowPlacement::Tiled)
|| self.placement(target) != Some(WindowPlacement::Tiled)
{
return Err(WorkspaceError::InvalidState("stack window is not tiled"));
}
let workspace = self
.workspaces
.get_mut(&workspace)
.ok_or(WorkspaceError::InvalidState("window workspace is missing"))?;
workspace.layout.stack_window(window, target)?;
workspace.last_focused = Some(window);
debug_assert!(self.validate().is_ok());
Ok(())
}
pub fn ensure_numeric(&mut self, index: u32) -> Result<WorkspaceId, WorkspaceError> {
if index == 0 {
return Err(WorkspaceError::InvalidNumericName(index));
@@ -796,4 +830,28 @@ mod tests {
);
assert!(workspaces.validate().is_ok());
}
#[test]
fn stacking_tiled_windows_preserves_workspace_membership() {
let mut workspaces = WorkspaceSet::default();
workspaces
.insert_window(WindowId(1), Axis::Horizontal, 0.5)
.unwrap();
workspaces
.insert_window(WindowId(2), Axis::Horizontal, 0.5)
.unwrap();
workspaces.stack_window(WindowId(2), WindowId(1)).unwrap();
assert_eq!(workspaces.active().last_focused, Some(WindowId(2)));
assert_eq!(
workspaces
.active()
.layout
.geometry(Rect::new(0.0, 0.0, 100.0, 80.0))
.unwrap()
.len(),
1
);
assert!(workspaces.validate().is_ok());
}
}