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/ctl/src/main.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'crates/ctl') diff --git a/crates/ctl/src/main.rs b/crates/ctl/src/main.rs index fb896a3..fb7196c 100644 --- a/crates/ctl/src/main.rs +++ b/crates/ctl/src/main.rs @@ -145,6 +145,8 @@ fn build_request(args: &[String]) -> Result { Some("monitors") => Ok(r#"{"cmd":"monitors"}"#.to_string()), Some("workspaces") => Ok(r#"{"cmd":"workspaces"}"#.to_string()), Some("settings") => Ok(r#"{"cmd":"settings"}"#.to_string()), + Some("pinned") if args.get(1).map(String::as_str) == Some("inputs") => Ok(r#"{"cmd":"pinned_inputs"}"#.to_string()), + Some("pinned") => Err("did you mean 'srd pinned inputs'?".to_string()), Some("keyboard") if args.get(1).map(String::as_str) == Some("layout") => Ok(r#"{"cmd":"keyboard_layout"}"#.to_string()), Some("keyboard") => Err("did you mean 'srd keyboard layout'?".to_string()), Some("subscribe") => Ok(r#"{"cmd":"subscribe"}"#.to_string()), @@ -184,13 +186,14 @@ fn build_request(args: &[String]) -> Result { // as booleans at all, not a string it then has to reject. Some("set") => { let key = args.get(1).ok_or( - "set needs a key (border_width/border_color/corner_radius/gap_inner/gap_outer/shadows/rounded_corners/animations/night_light/reading_mode/phone_mode/multi_cursor/decoration_mode)", + "set needs a key (border_width/border_color/corner_radius/gap_inner/gap_outer/master_ratio/master_count/shadows/rounded_corners/animations/night_light/reading_mode/phone_mode/multi_cursor/decoration_mode)", )?; let raw = args.get(2).ok_or("set needs a value")?; let value = match key.as_str() { - "border_width" | "corner_radius" | "gap_inner" | "gap_outer" => { + "border_width" | "corner_radius" | "gap_inner" | "gap_outer" | "master_count" => { raw.parse::().map_err(|_| format!("{key} needs a numeric value"))?.to_string() } + "master_ratio" => raw.parse::().map_err(|_| format!("{key} needs a numeric value"))?.to_string(), "shadows" | "rounded_corners" | "animations" | "night_light" | "reading_mode" | "phone_mode" | "multi_cursor" => match raw.as_str() { "true" | "false" => raw.clone(), _ => return Err(format!("{key} needs 'true' or 'false'")), @@ -394,6 +397,7 @@ fn print_usage() { eprintln!(" srd monitors"); eprintln!(" srd workspaces"); eprintln!(" srd settings"); + eprintln!(" srd pinned inputs"); eprintln!(" srd keyboard layout"); eprintln!(" srd subscribe"); eprintln!(" srd dispatch focus "); @@ -654,6 +658,24 @@ mod tests { fn settings_query_needs_no_further_arguments() { assert_eq!(build_request(&args(&["settings"])).unwrap(), r#"{"cmd":"settings"}"#); } + + #[test] + fn pinned_inputs_query_reads_as_two_words() { + assert_eq!(build_request(&args(&["pinned", "inputs"])).unwrap(), r#"{"cmd":"pinned_inputs"}"#); + assert!(build_request(&args(&["pinned"])).is_err()); + } + + #[test] + fn set_master_ratio_accepts_a_fractional_value() { + assert_eq!(build_request(&args(&["set", "master_ratio", "0.65"])).unwrap(), r#"{"cmd":"set","key":"master_ratio","value":0.65}"#); + assert!(build_request(&args(&["set", "master_ratio", "not-a-number"])).is_err()); + } + + #[test] + fn set_master_count_accepts_a_plain_integer() { + assert_eq!(build_request(&args(&["set", "master_count", "2"])).unwrap(), r#"{"cmd":"set","key":"master_count","value":2}"#); + assert!(build_request(&args(&["set", "master_count", "not-a-number"])).is_err()); + } } #[cfg(unix)] -- cgit v1.2.3