diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/input.rs | 8 | ||||
| -rw-r--r-- | src/main.rs | 5 | ||||
| -rw-r--r-- | src/utils.rs | 51 |
3 files changed, 54 insertions, 10 deletions
diff --git a/src/input.rs b/src/input.rs index 310b4f82..3cc13a5f 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,5 +1,3 @@ -use std::process::Command; - use smithay::backend::input::{ AbsolutePositionEvent, Axis, AxisSource, ButtonState, Device, DeviceCapability, Event, GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, @@ -19,7 +17,7 @@ use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait}; use crate::config::{Action, Config, Modifiers}; use crate::niri::State; -use crate::utils::get_monotonic_time; +use crate::utils::{get_monotonic_time, spawn}; pub enum CompositorMod { Super, @@ -149,9 +147,7 @@ impl State { } Action::Spawn(command) => { if let Some((command, args)) = command.split_first() { - if let Err(err) = Command::new(command).args(args).spawn() { - warn!("error spawning {command}: {err}"); - } + spawn(command, args); } } Action::Screenshot => { diff --git a/src/main.rs b/src/main.rs index 6c5e9ab0..cb58910e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ use portable_atomic::Ordering; use smithay::reexports::calloop::EventLoop; use smithay::reexports::wayland_server::Display; use tracing_subscriber::EnvFilter; +use utils::spawn; #[derive(Parser)] #[command(author, version, about, long_about = None)] @@ -76,9 +77,7 @@ fn main() { let mut data = LoopData { display, state }; if let Some((command, args)) = cli.command.split_first() { - if let Err(err) = std::process::Command::new(command).args(args).spawn() { - warn!("error spawning command: {err:?}"); - } + spawn(command, args); } event_loop diff --git a/src/utils.rs b/src/utils.rs index adf14abb..e5ba895c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,9 @@ +use std::ffi::OsStr; use std::fs::File; -use std::io::Read; +use std::io::{self, Read}; +use std::os::unix::process::CommandExt; use std::path::PathBuf; +use std::process::{Command, Stdio}; use std::time::Duration; use anyhow::{anyhow, Context}; @@ -107,3 +110,49 @@ pub fn make_screenshot_path() -> anyhow::Result<PathBuf> { Ok(path) } + +/// Spawns the command to run independently of the compositor. +pub fn spawn(command: impl AsRef<OsStr>, args: impl IntoIterator<Item = impl AsRef<OsStr>>) { + let _span = tracy_client::span!(); + + let command = command.as_ref(); + + let mut process = Command::new(command); + process + .args(args) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()); + + // Double-fork to avoid having to waitpid the child. + unsafe { + process.pre_exec(|| { + match libc::fork() { + -1 => return Err(io::Error::last_os_error()), + 0 => (), + _ => libc::_exit(0), + } + + Ok(()) + }); + } + + let mut child = match process.spawn() { + Ok(child) => child, + Err(err) => { + warn!("error spawning {command:?}: {err:?}"); + return; + } + }; + + match child.wait() { + Ok(status) => { + if !status.success() { + warn!("child did not exit successfully: {status:?}"); + } + } + Err(err) => { + warn!("error waiting for child: {err:?}"); + } + } +} |
