diff --git a/src/main.rs b/src/main.rs index 194c476..7d27d77 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ mod niri; mod output; mod pulse; mod util; +mod xwayland; #[derive(Parser)] struct Opt { @@ -17,6 +18,22 @@ struct Opt { command: Command, } +#[derive(Clone, Subcommand)] +enum Command { + /// Commands that need to be handled differently on a per-wm basis + #[clap(flatten)] + Wm(WmCommand), + + /// Get the list of audio sinks + Sinks, + + /// Print battery information + Battery, + + #[clap(subcommand)] + Xwayland(XwaylandCommand), +} + #[derive(Clone, Subcommand)] enum WmCommand { /// Get the list of workspaces @@ -34,16 +51,18 @@ enum WmCommand { } #[derive(Clone, Subcommand)] -enum Command { - /// Commands that need to be handled differently on a per-wm basis - #[clap(flatten)] - Wm(WmCommand), +enum XwaylandCommand { + /// Print whether xwayland is enabled. + IsRunning, - /// Get the list of audio sinks - Sinks, + /// Enable xwayland + Start, - /// Print battery information - Battery, + /// Disable xwayland + Stop, + + /// Toggle xwayland + Toggle, } enum WindowManager { @@ -85,6 +104,7 @@ fn main() -> eyre::Result<()> { println!("{}", serde_json::to_string(&pulse::get_sinks()?)?); } Command::Battery => battery::print_info(), + Command::Xwayland(cmd) => xwayland::handle(cmd)?, } Ok(()) diff --git a/src/xwayland.rs b/src/xwayland.rs new file mode 100644 index 0000000..ffcfe33 --- /dev/null +++ b/src/xwayland.rs @@ -0,0 +1,62 @@ +use std::process::{Command, Stdio}; + +use eyre::Context; + +use crate::{util::CommandExt, XwaylandCommand}; + +pub fn handle(cmd: XwaylandCommand) -> eyre::Result<()> { + match cmd { + XwaylandCommand::IsRunning => { + println!("{}", xwayland_is_running()?); + } + XwaylandCommand::Start => { + if !xwayland_is_running()? { + start_xwayland()?; + } else { + eprintln!("xwayland is already running"); + } + } + XwaylandCommand::Stop => { + if xwayland_is_running()? { + stop_xwayland()?; + } else { + eprintln!("xwayland is not running"); + } + } + XwaylandCommand::Toggle => { + if !xwayland_is_running()? { + start_xwayland()?; + } else { + stop_xwayland()?; + } + } + } + + Ok(()) +} + +/// Is xwayland running? +pub fn xwayland_is_running() -> eyre::Result { + let processes = Command::new("ps").arg("-A").just_exec()?; + Ok(processes.contains("xwayland") || processes.contains("Xwayland")) +} + +pub fn start_xwayland() -> eyre::Result<()> { + let child = Command::new("xwayland-satellite") + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .wrap_err("Failed to spawn xwayland-satellite")?; + + drop(child); + + Ok(()) +} + +pub fn stop_xwayland() -> eyre::Result<()> { + Command::new("killall") + .arg("xwayland-satellite") + .just_exec()?; + Ok(()) +}