interactive: Host/View entry menu, clipboard copy, player picker

Bare `pixelpass` now opens a dialoguer-driven Host/View menu instead of
going straight to host mode. Host path copies the ticket to the system
clipboard via arboard with silent print-only fallback. View path
prompts for the ticket, then after the local listener binds prompts
mpv-vs-VLC and spawns it detached (setsid + null stdio) so the player
survives pixelpass exiting.

Headless invocations (`pixelpass <ticket>`, `pixelpass --repair`)
unchanged. Per spec at ~/Documents/pixelpass-interactive-mode-spec.md.
This commit is contained in:
2026-05-18 15:46:57 -04:00
parent 4cab9f6b20
commit bb437a73cf
9 changed files with 410 additions and 15 deletions
+25
View File
@@ -0,0 +1,25 @@
use std::io;
use std::os::unix::process::CommandExt;
use std::process::{Command, Stdio};
/// Spawn a child process fully detached from this process group.
///
/// The child gets its own session via `setsid(2)` and null stdio, so it
/// survives the parent exiting and doesn't take a SIGKILL cascade when
/// pixelpass dies. The `Child` is dropped immediately — `std::process::Child::drop`
/// does not kill the process on Unix.
pub fn spawn_detached(prog: &str, args: &[&str]) -> io::Result<()> {
unsafe {
Command::new(prog)
.args(args)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.pre_exec(|| {
nix::unistd::setsid().ok();
Ok(())
})
.spawn()?;
}
Ok(())
}