aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/input.rs8
-rw-r--r--src/main.rs5
-rw-r--r--src/utils.rs51
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:?}");
+ }
+ }
+}