use std::io::Write;
use std::process::{Command, Stdio};
#[cfg(windows)]
const DETACHED_PROCESS: u32 = 0x0000_0008;
#[cfg(windows)]
const CREATE_NEW_PROCESS_GROUP: u32 = 0x0000_0200;
pub const DETACHED_CHILD_ENV: &str = "TINYVIEW_DETACHED_CHILD";
const RAW_MODE_ENV: &str = "TINYVIEW_RAW_MODE";
pub struct SpawnOpts<'a> {
pub html: &'a str,
pub width: u32,
pub height: u32,
pub raw_mode: bool,
pub allow_fetch: bool,
pub allow_clipboard: bool,
pub allow_storage: bool,
pub frameless: bool,
pub transparent: bool,
}
pub fn spawn(opts: &SpawnOpts<'_>) -> std::io::Result<()> {
let exe = std::env::current_exe()?;
let mut cmd = Command::new(exe);
cmd.env(DETACHED_CHILD_ENV, "1");
if opts.raw_mode {
cmd.env(RAW_MODE_ENV, "1");
}
cmd.arg("--width").arg(opts.width.to_string());
cmd.arg("--height").arg(opts.height.to_string());
if opts.allow_fetch {
cmd.arg("--allow-fetch");
}
if opts.allow_clipboard {
cmd.arg("--allow-clipboard");
}
if opts.allow_storage {
cmd.arg("--allow-storage");
}
if opts.frameless {
cmd.arg("--frameless");
}
if opts.transparent {
cmd.arg("--transparent");
}
cmd.stdin(Stdio::piped());
cmd.stdout(Stdio::null());
cmd.stderr(Stdio::null());
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
unsafe {
cmd.pre_exec(|| {
if libc::setsid() < 0 {
return Err(std::io::Error::last_os_error());
}
Ok(())
});
}
}
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
cmd.creation_flags(DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP);
}
let mut child = cmd.spawn()?;
if let Some(mut stdin) = child.stdin.take() {
stdin.write_all(opts.html.as_bytes())?;
}
Ok(())
}
pub fn is_detached_child() -> bool {
std::env::var_os(DETACHED_CHILD_ENV).is_some()
}
pub fn detached_raw_mode() -> bool {
std::env::var_os(RAW_MODE_ENV).is_some()
}