diff options
Diffstat (limited to 'crates/config/src/engine')
| -rw-r--r-- | crates/config/src/engine/general.rs | 27 | ||||
| -rw-r--r-- | crates/config/src/engine/support.rs | 14 | ||||
| -rw-r--r-- | crates/config/src/engine/tests.rs | 26 |
3 files changed, 65 insertions, 2 deletions
diff --git a/crates/config/src/engine/general.rs b/crates/config/src/engine/general.rs index e5147cd..6276854 100644 --- a/crates/config/src/engine/general.rs +++ b/crates/config/src/engine/general.rs @@ -128,8 +128,8 @@ impl Engine { /// class_regex = "...", instance = "..." }, { floating = true, /// workspace = 2, x = .., y = .., width = .., height = .., /// decorated = false, border_color = {r,g,b}, border_width = 2, - /// corner_radius = 10, maximized = true, opacity = 0.9 })`. At least - /// one matcher field is + /// corner_radius = 10, maximized = true, opacity = 0.9, + /// aspect_ratio = "9:16" })`. At least one matcher field is /// required; unmatched rules apply nothing. /// /// `title`/`class` are plain substring/exact match, cheap and cover @@ -172,6 +172,28 @@ impl Engine { _ => None, } }; + // `aspect_ratio = "9:16"` - the "phone monitor / special + // workspace" ask's own real, scoped answer (see `Window:: + // aspect_ratio`'s own doc comment in `crates/core`): a rule + // matching any VM/emulator/`scrcpy` window by `app_id` keeps + // it phone-shaped through a resize, with no Android-specific + // (or even VM-specific) code anywhere in this compositor. + // `"W:H"` (a plain string, not a table) matches this + // project's own `border_color = {r,g,b}` precedent for "a + // structured value needs its own small parse", just with a + // string instead of a table since a ratio is conventionally + // written that way everywhere (`16:9`, `9:16`, `4:3`). + let aspect_ratio: Option<(u32, u32)> = match actions.get::<_, Option<String>>("aspect_ratio")? { + Some(spec) => { + let (w, h) = spec + .split_once(':') + .and_then(|(w, h)| Some((w.trim().parse::<u32>().ok()?, h.trim().parse::<u32>().ok()?))) + .filter(|(w, h)| *w > 0 && *h > 0) + .ok_or_else(|| mlua::Error::RuntimeError(format!("srd.rule: aspect_ratio must be \"W:H\" with positive integers, got {spec:?}")))?; + Some((w, h)) + } + None => None, + }; let rule = WindowRule { matcher: WindowMatch { title_contains, class, title_regex, class_regex, instance }, @@ -187,6 +209,7 @@ impl Engine { pinned: actions.get("pinned")?, opacity: actions.get("opacity")?, resize_margin: actions.get("resize_margin")?, + aspect_ratio, }, }; state.borrow().wm.borrow_mut().add_rule(rule); diff --git a/crates/config/src/engine/support.rs b/crates/config/src/engine/support.rs index 7537fce..97c499f 100644 --- a/crates/config/src/engine/support.rs +++ b/crates/config/src/engine/support.rs @@ -154,11 +154,25 @@ pub(super) fn default_config() -> HashMap<String, ConfigValue> { // every other ordinary flag rather than left absent for a backend to // decide. set("general.gpu", Bool(false)); + // `false`: opt-in single-app-at-a-time placement, off by default so + // an ordinary desktop session's floating/tiling behavior is + // completely unaffected - see `WindowManager::phone_mode`'s own doc + // comment. + set("general.phone_mode", Bool(false)); // Real desktop icons (Home/Computer/Trash plus `~/Desktop`'s own // contents) on by default - see `WindowManager::desktop_icons_ // enabled`'s own doc comment for why this, unlike `general.gpu` just // above, doesn't need an opt-in safety net. set("general.desktop_icons", Bool(true)); + // On by default - see `WindowManager::desktop_icons_all_monitors`'s + // own doc comment. + set("general.desktop_icons_all_monitors", Bool(true)); + // `0` (no static reservation) by default - see `WindowManager:: + // reserve_top`'s own doc comment for what this is and why. + set("general.reserve_top", Number(0.0)); + set("general.reserve_bottom", Number(0.0)); + set("general.reserve_left", Number(0.0)); + set("general.reserve_right", Number(0.0)); // Empty by default - see `WindowManager::file_manager`'s own doc // comment: empty means "dispatch via `xdg-open`", not "no file manager // configured, do nothing". diff --git a/crates/config/src/engine/tests.rs b/crates/config/src/engine/tests.rs index f170320..f4f011b 100644 --- a/crates/config/src/engine/tests.rs +++ b/crates/config/src/engine/tests.rs @@ -197,6 +197,32 @@ } #[test] + fn srd_rule_aspect_ratio_applies_a_parsed_w_h_pair_on_creation() { + let dir = tempfile::tempdir().unwrap(); + let wm = Rc::new(RefCell::new(WindowManager::new())); + let engine = Engine::new(wm.clone(), dir.path()).unwrap(); + engine.lua.load(r#"srd.rule({ class = "scrcpy" }, { aspect_ratio = "9:16" })"#).exec().unwrap(); + let id = { + let mut wm = wm.borrow_mut(); + let id = wm.alloc_window_id(); + let mut w = srdwm_core::Window::new(id, "phone"); + w.app_id = "scrcpy".into(); + wm.add_window(w); + id + }; + assert_eq!(wm.borrow().window(id).unwrap().aspect_ratio, Some((9, 16))); + } + + #[test] + fn srd_rule_rejects_a_malformed_aspect_ratio() { + let dir = tempfile::tempdir().unwrap(); + let wm = Rc::new(RefCell::new(WindowManager::new())); + let engine = Engine::new(wm.clone(), dir.path()).unwrap(); + let err = engine.lua.load(r#"srd.rule({ class = "x" }, { aspect_ratio = "sixteen by nine" })"#).exec(); + assert!(err.is_err()); + } + + #[test] fn srd_monitor_split_stores_a_split_request_by_connector_name() { let dir = tempfile::tempdir().unwrap(); let wm = Rc::new(RefCell::new(WindowManager::new())); |