From ea78f94027ecd2c690904a6d7729e9e3cc190a20 Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Fri, 7 Nov 2025 14:04:00 +0200 Subject: Make tiling's master/stack ratio live, add settings readback everywhere Investigated the "tiling needs a lot of work" report directly. The MasterStackLayout algorithm itself was already correct; the real gap was that dragging or resizing a tiled window did nothing durable (raw geometry that the next arrange_workspace silently discarded), and master_ratio/master_count had no live path at all (config-file only). A resize-drag on the shared master/stack boundary now live-adjusts TilingConfig::master_ratio and re-arranges the group immediately; srd set master_ratio/master_count do the same for a keybind or script. Found and fixed a real bug while building this: start_resize's own focus_window call re-stacks its target in self.order before the ratio-drag decision used to be made, silently misclassifying real master-column grabs. Fixed by deciding ratio-drag status (and freezing the membership snapshot it depends on) before that raise happens, applying MasterStackLayout directly against the frozen snapshot rather than re-deriving membership from the by-then-reordered live order. Live- verified in a nested compositor, not just unit-tested. Also closes the readback gaps flagged directly by the AGS peer session: border_width/border_color/corner_radius/decoration_mode/gap_inner/ gap_outer/master_ratio/master_count were all live-settable via srd set with no way to read the current value back, and pin_input had no readback at all. SettingsResponse now reports all of them; a new pinned_inputs query (srd pinned inputs) lists every currently pinned pid/window. --- crates/core/src/manager/tests.rs | 102 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'crates/core/src/manager/tests.rs') diff --git a/crates/core/src/manager/tests.rs b/crates/core/src/manager/tests.rs index 3d628a8..860af89 100644 --- a/crates/core/src/manager/tests.rs +++ b/crates/core/src/manager/tests.rs @@ -287,6 +287,108 @@ assert_eq!(wm.window(a).unwrap().monitor, 1, "monitor must update live during the resize"); } + #[test] + fn dragging_the_master_columns_right_edge_grows_master_ratio_live() { + // Live report: "tiling needs a lot of work" - dragging a tiled + // window's border used to write raw geometry that the very next + // `arrange_workspace` call silently discarded. Two windows: window + // `a` is the sole master (index 0 < master_count 1), `b` is the + // whole stack. + let mut wm = wm_with_monitor(); + wm.set_layout(wm.current_workspace(), "tiling"); + wm.tiling.gap_outer = 0; + wm.tiling.gap_inner = 0; + wm.tiling.master_ratio = 0.5; + let a = wm.alloc_window_id(); + wm.add_window(Window::new(a, "a")); + let b = wm.alloc_window_id(); + wm.add_window(Window::new(b, "b")); + + let before = wm.window(a).unwrap().geometry.width; + wm.start_resize(a, ResizeEdge::Right, 0, 0); + wm.update_resize(200, 0); // dragged 200px to the right + let after = wm.window(a).unwrap().geometry.width; + assert!(after > before, "the master column must visibly grow while dragging its own right edge"); + assert!(wm.tiling.master_ratio > 0.5, "master_ratio itself must have grown, not just this one window's rect"); + // The stack window must have shrunk by the matching amount -- + // this is a real ratio change, not a floating-style resize that + // only touched the grabbed window. + assert!(wm.window(b).unwrap().geometry.width < 960); + } + + #[test] + fn dragging_a_stack_windows_left_edge_adjusts_the_same_shared_boundary() { + // The mirror case: grabbing the *stack* column's own left edge is + // the same physical boundary as the master column's right edge, + // approached from the other side. + let mut wm = wm_with_monitor(); + wm.set_layout(wm.current_workspace(), "tiling"); + wm.tiling.gap_outer = 0; + wm.tiling.gap_inner = 0; + wm.tiling.master_ratio = 0.5; + let a = wm.alloc_window_id(); + wm.add_window(Window::new(a, "a")); + let b = wm.alloc_window_id(); + wm.add_window(Window::new(b, "b")); + + wm.start_resize(b, ResizeEdge::Left, 0, 0); + wm.update_resize(200, 0); // dragged the shared boundary right + assert!(wm.tiling.master_ratio > 0.5, "master must grow when the boundary is dragged right, regardless of which side initiated it"); + } + + #[test] + fn dragging_a_floating_windows_edge_never_touches_master_ratio() { + let mut wm = wm_with_monitor(); + wm.set_layout(wm.current_workspace(), "tiling"); + wm.tiling.master_ratio = 0.5; + let a = wm.alloc_window_id(); + let mut w = Window::new(a, "a"); + w.floating = true; + w.geometry = Rect::new(100, 100, 300, 200); + wm.add_window(w); + + wm.start_resize(a, ResizeEdge::Right, 0, 0); + wm.update_resize(200, 0); + assert_eq!(wm.tiling.master_ratio, 0.5, "a floating window's own resize must behave exactly as before - no tiling ratio involved"); + assert_eq!(wm.window(a).unwrap().geometry.width, 500, "the floating window itself must still resize normally"); + } + + #[test] + fn dragging_a_tiled_windows_vertical_edge_does_not_touch_master_ratio() { + // Only the shared master/stack *horizontal* boundary is a ratio + // drag - a vertical edge has no equivalent concept in this + // layout (stack windows split height evenly, with no per-window + // override), so it must fall through to the ordinary (if + // ultimately overwritten) geometry path rather than doing nothing + // useful either way. + let mut wm = wm_with_monitor(); + wm.set_layout(wm.current_workspace(), "tiling"); + wm.tiling.master_ratio = 0.5; + let a = wm.alloc_window_id(); + wm.add_window(Window::new(a, "a")); + let b = wm.alloc_window_id(); + wm.add_window(Window::new(b, "b")); + + wm.start_resize(a, ResizeEdge::Bottom, 0, 0); + wm.update_resize(0, 100); + assert_eq!(wm.tiling.master_ratio, 0.5); + } + + #[test] + fn dragging_the_only_windows_edge_with_no_stack_does_not_touch_master_ratio() { + // A lone master window has nothing on the other side of any + // boundary - there is no stack to trade width with. + let mut wm = wm_with_monitor(); + wm.set_layout(wm.current_workspace(), "tiling"); + wm.tiling.master_ratio = 0.5; + let a = wm.alloc_window_id(); + wm.add_window(Window::new(a, "a")); + + wm.start_resize(a, ResizeEdge::Right, 0, 0); + wm.update_resize(200, 0); + assert_eq!(wm.tiling.master_ratio, 0.5); + } + #[test] fn ending_a_resize_remembers_the_new_size_for_the_apps_next_window() { let mut wm = wm_with_monitor(); -- cgit v1.2.3