srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/ctl/src
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-10-26 22:58:00 +0200
committersrdusr <[email protected]>2025-10-26 22:58:00 +0200
commit304f3a374408bb6a5a04ebb7d4652c631395f5c6 (patch)
tree8a40628fe016bd3e31c295cc76985d65c6354561 /crates/ctl/src
parent9f07715b469a481849ee35ffa33d6dab34356c7d (diff)
downloadsrdwm-304f3a374408bb6a5a04ebb7d4652c631395f5c6.tar.gz
srdwm-304f3a374408bb6a5a04ebb7d4652c631395f5c6.zip
Live-expose monitor split, clean up leftover debug diagnostics
srd.monitor.split only ever ran at Lua config load despite being a plain WindowManager mutation that every backend's monitors() already reads fresh on each call. Adds srd dispatch set output split <name|id> <parts> [rows|columns] (IPC set_monitor_split), same id-resolves-to-name pattern set_output_enabled already uses. Also removes eight log::warn!("XXX-DIAG ...") lines left behind from live debugging in the multi-session shift that landed in 3c41fc4 - the same "temporary, never removed" pattern already fixed twice earlier this session. Several fired on genuinely constant interaction (every title change, every workspace switch, every layer-shell surface hide), not just a one-off leftover. Left xdg_shell.rs's own POPUP-GEOM-DIAG/ POPUP-GRAB-DIAG alone - that one is a still-open, self-documented investigation, not litter. Also documents (docs/TODO.md, not a code change) a live incident where creating a second fake monitor visibly corrupted the real monitor's position and kept drifting with no further input - not root-caused srdwm-side, flagged to the AGS peer session since a fake monitor's real wl_output global is indistinguishable from a real hotplug to GDK/GTK. And documents a deliberate decision not to blind-port window decoration rendering onto the experimental, never-live-tested GPU render path.
Diffstat (limited to 'crates/ctl/src')
-rw-r--r--crates/ctl/src/main.rs55
1 files changed, 53 insertions, 2 deletions
diff --git a/crates/ctl/src/main.rs b/crates/ctl/src/main.rs
index 3cf3bfd..fb896a3 100644
--- a/crates/ctl/src/main.rs
+++ b/crates/ctl/src/main.rs
@@ -43,6 +43,12 @@
//! disabled output stops presenting
//! and its `wl_output` global goes away
//! until re-enabled
+//! srd dispatch set output split NAME|ID PARTS [rows|columns] divides
+//! one real output into PARTS logical
+//! monitors for placement/tiling --
+//! columns (default) side by side,
+//! rows stacked; PARTS <= 1 clears an
+//! existing split. Live, no restart.
//! srd set border_width 3 live theme values, applied immediately
//! srd set border_color '#cba6f7' (hex string)
//! srd set corner_radius 10
@@ -294,9 +300,9 @@ fn build_dispatch(args: &[String]) -> Result<String, String> {
// back.
"set" => {
if args.get(1).map(String::as_str) != Some("output") {
- return Err(format!("'set' only supports 'output position'/'output enabled' - {usage_hint}"));
+ return Err(format!("'set' only supports 'output position'/'output enabled'/'output split' - {usage_hint}"));
}
- let noun = args.get(2).ok_or("'set output' needs a target: position or enabled")?;
+ let noun = args.get(2).ok_or("'set output' needs a target: position, enabled or split")?;
let target = args.get(3).ok_or("'set output' needs a monitor name or id")?;
match noun.as_str() {
"position" => {
@@ -318,6 +324,25 @@ fn build_dispatch(args: &[String]) -> Result<String, String> {
Err(_) => Ok(format!(r#"{{"cmd":"set_output_enabled","name":"{target}","enabled":{enabled}}}"#)),
}
}
+ // `srd dispatch set output split <name|id> <parts> [rows|columns]`
+ // - the live equivalent of `srd.monitor.split(name, parts,
+ // direction)` in Lua config, which previously only ever took
+ // effect at config load/reload. `parts <= 1` clears an
+ // existing split. `columns` (side-by-side, splitting width)
+ // is the default when the direction is omitted, matching the
+ // Lua function's own default.
+ "split" => {
+ let parts: u64 = args.get(4).ok_or("'set output split' needs a part count")?.parse().map_err(|_| "parts must be a number".to_string())?;
+ let rows = match args.get(5).map(String::as_str) {
+ None | Some("columns") => false,
+ Some("rows") => true,
+ Some(other) => return Err(format!("'set output split' direction must be 'rows' or 'columns', got '{other}'")),
+ };
+ match target.parse::<u64>() {
+ Ok(id) => Ok(format!(r#"{{"cmd":"set_monitor_split","id":{id},"parts":{parts},"rows":{rows}}}"#)),
+ Err(_) => Ok(format!(r#"{{"cmd":"set_monitor_split","name":"{target}","parts":{parts},"rows":{rows}}}"#)),
+ }
+ }
_ => Err(format!("unknown 'set output' target '{noun}' - {usage_hint}")),
}
}
@@ -385,6 +410,7 @@ fn print_usage() {
eprintln!(" srd dispatch cycle keyboard layout");
eprintln!(" srd dispatch set output position <name|id> <x> <y>");
eprintln!(" srd dispatch set output enabled <name|id> <true|false>");
+ eprintln!(" srd dispatch set output split <name|id> <parts> [rows|columns]");
eprintln!(" srd dispatch pin input <pid> <window-id>");
eprintln!(" srd dispatch unpin input <pid>");
eprintln!(" srd dispatch create fake-monitor <name> <width>x<height>");
@@ -503,6 +529,31 @@ mod tests {
}
#[test]
+ fn set_output_split_accepts_a_numeric_id_and_a_name() {
+ assert_eq!(build_request(&args(&["dispatch", "set", "output", "split", "1", "2"])).unwrap(), r#"{"cmd":"set_monitor_split","id":1,"parts":2,"rows":false}"#);
+ assert_eq!(
+ build_request(&args(&["dispatch", "set", "output", "split", "HDMI-A-1", "3", "rows"])).unwrap(),
+ r#"{"cmd":"set_monitor_split","name":"HDMI-A-1","parts":3,"rows":true}"#
+ );
+ }
+
+ #[test]
+ fn set_output_split_defaults_direction_to_columns() {
+ assert_eq!(build_request(&args(&["dispatch", "set", "output", "split", "eDP-1", "2", "columns"])).unwrap(), r#"{"cmd":"set_monitor_split","name":"eDP-1","parts":2,"rows":false}"#);
+ }
+
+ #[test]
+ fn set_output_split_rejects_an_unknown_direction() {
+ assert!(build_request(&args(&["dispatch", "set", "output", "split", "eDP-1", "2", "sideways"])).is_err());
+ }
+
+ #[test]
+ fn set_output_split_needs_a_part_count() {
+ assert!(build_request(&args(&["dispatch", "set", "output", "split", "eDP-1"])).is_err());
+ assert!(build_request(&args(&["dispatch", "set", "output", "split", "eDP-1", "not-a-number"])).is_err());
+ }
+
+ #[test]
fn create_fake_monitor_builds_a_sized_request() {
assert_eq!(
build_request(&args(&["dispatch", "create", "fake-monitor", "FAKE-1", "1920x1080"])).unwrap(),