lesavka/client/src/layout.rs

74 lines
2.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// client/src/layout.rs - Wayland-only window placement utilities
#![forbid(unsafe_code)]
use serde_json::Value;
use std::process::Command;
use tracing::{info, warn};
/// The three layouts we cycle through.
#[derive(Clone, Copy)]
pub enum Layout {
SideBySide, // two halves on the current monitor
FullLeft, // left eye full-screen, right hidden
FullRight, // right eye full-screen, left hidden
}
/// Move/resize a window titled “Lesavka-eye-{eye}” using `swaymsg`.
fn place_window(eye: u32, x: i32, y: i32, w: i32, h: i32) {
let title = format!("Lesavka-eye-{eye}");
let cmd = format!(r#"[title="^{title}$"] resize set {w} {h}; move position {x} {y}"#);
match Command::new("swaymsg").arg(cmd).status() {
Ok(st) if st.success() => info!("✅ placed eye{eye} {w}×{h}@{x},{y}"),
Ok(st) => warn!("⚠️ swaymsg exited with {st}"),
Err(e) => warn!("⚠️ swaymsg failed: {e}"),
}
}
/// Apply a layout on the **currently-focused** output.
/// No `?` operators → the function can stay `-> ()`.
pub fn apply(layout: Layout) {
let out = match Command::new("swaymsg")
.args(["-t", "get_outputs", "-r"])
.output()
{
Ok(o) => o.stdout,
Err(e) => {
warn!("get_outputs failed: {e}");
return;
}
};
let Ok(Value::Array(outputs)) = serde_json::from_slice::<Value>(&out) else {
warn!("unexpected JSON from swaymsg");
return;
};
let Some(rect) = outputs
.iter()
.find(|o| o.get("focused").and_then(Value::as_bool) == Some(true))
.and_then(|o| o.get("rect"))
else {
return;
};
// helper to read an i64 → i32 with defaults
let g = |k: &str| rect.get(k).and_then(Value::as_i64).unwrap_or(0) as i32;
let (x, y, w, h) = (g("x"), g("y"), g("width"), g("height"));
match layout {
Layout::SideBySide => {
let w_half = w / 2;
place_window(0, x, y, w_half, h);
place_window(1, x + w_half, y, w_half, h);
}
Layout::FullLeft => {
place_window(0, x, y, w, h);
place_window(1, x + w * 2, y + h * 2, 1, 1); // off-screen
}
Layout::FullRight => {
place_window(1, x, y, w, h);
place_window(0, x + w * 2, y + h * 2, 1, 1);
}
}
}