feat(host): list-monitors CLI, and two bugs it caught on-glass
An operator configuring an unattended host has to learn the connector
names from somewhere, and "curl the management API before the host is
configured" is not it. `punktfunk-host list-monitors` prints them with
geometry and flags the pinned one.
Running it under a real sway immediately caught two defects the unit tests
could not:
- the query used the `swaymsg` command helper, which inserts `--`, so
`-t get_outputs` came back as "Unknown/invalid command '-t'". Queries
now go through a `swaymsg_query` helper that cannot make that mistake.
- compositors write the literal "Unknown" rather than leaving make/model
empty, so the picker label read "Unknown Unknown". One `describe`
helper now treats that as absent, for all four backends.
Verified on a headless two-output sway: names, modes, positions, scale and
the case-insensitive pin all resolve.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -199,6 +199,9 @@ fn is_management_cli(args: &[String]) -> bool {
|
||||
| Some("openapi")
|
||||
| Some("library")
|
||||
| Some("detect-conflicts")
|
||||
// Reads the compositor's output list and exits — none of the host-startup work applies,
|
||||
// and it must not re-run the pin's own startup report while printing that same list.
|
||||
| Some("list-monitors")
|
||||
| Some("-h")
|
||||
| Some("--help")
|
||||
| Some("help")
|
||||
@@ -458,6 +461,51 @@ fn real_main() -> Result<()> {
|
||||
println!("{compositor:?} ready");
|
||||
Ok(())
|
||||
}
|
||||
// List the host's physical monitors — the connector names `PUNKTFUNK_CAPTURE_MONITOR`
|
||||
// takes. An operator configuring an unattended host has to learn those names from
|
||||
// somewhere, and "curl the management API before the host is configured" is not it.
|
||||
#[cfg(target_os = "linux")]
|
||||
Some("list-monitors") => {
|
||||
let compositor = vdisplay::detect()?;
|
||||
let monitors = vdisplay::monitors::list(compositor)
|
||||
.with_context(|| format!("enumerate monitors on {compositor:?}"))?;
|
||||
if monitors.is_empty() {
|
||||
println!("{compositor:?}: no monitors");
|
||||
return Ok(());
|
||||
}
|
||||
let pinned = pf_host_config::config().capture_monitor.as_deref();
|
||||
println!("{compositor:?}:");
|
||||
for m in &monitors {
|
||||
let mut tags = Vec::new();
|
||||
if m.primary {
|
||||
tags.push("primary");
|
||||
}
|
||||
if !m.enabled {
|
||||
tags.push("disabled");
|
||||
}
|
||||
if m.managed {
|
||||
tags.push("punktfunk virtual display");
|
||||
}
|
||||
if pinned.is_some_and(|p| p.eq_ignore_ascii_case(&m.connector)) {
|
||||
tags.push("PINNED (PUNKTFUNK_CAPTURE_MONITOR)");
|
||||
}
|
||||
println!(
|
||||
" {:<12} {:>13} at +{},+{} scale {} {}{}",
|
||||
m.connector,
|
||||
m.mode_label(),
|
||||
m.x,
|
||||
m.y,
|
||||
m.scale,
|
||||
m.description,
|
||||
if tags.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
format!(" [{}]", tags.join(", "))
|
||||
}
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
// Create a virtual DualSense via UHID and exercise it (validation, no streaming session).
|
||||
#[cfg(target_os = "linux")]
|
||||
Some("dualsense-test") => devtest::dualsense_test(&args),
|
||||
@@ -780,6 +828,8 @@ USAGE:
|
||||
punktfunk-host openapi print the management API's OpenAPI document (codegen)
|
||||
punktfunk-host punktfunk1-host [OPTIONS] native punktfunk/1 host (QUIC control + UDP data plane)
|
||||
punktfunk-host probe-compositor exit 0 iff the compositor is up + ready (bringup gate)
|
||||
punktfunk-host list-monitors list the host's physical monitors (Linux) — the
|
||||
connector names PUNKTFUNK_CAPTURE_MONITOR takes
|
||||
punktfunk-host spike [OPTIONS] capture→encode→file pipeline spike (dev tool)
|
||||
|
||||
SERVE OPTIONS:
|
||||
|
||||
Reference in New Issue
Block a user