Diff
diff --git a/Cargo.lock b/Cargo.lock
index 6b613df..2566f7f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -295,7 +295,6 @@ version = "0.8.1"
dependencies = [
"chrono",
"dirs",
- "libc",
"mlua",
"serde",
"x11",
diff --git a/Cargo.toml b/Cargo.toml
index fb1078a..6a13c55 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,4 +18,3 @@ chrono = "0.4"
dirs = "5.0"
serde = { version = "1.0", features = ["derive"] }
mlua = { version = "0.10", features = ["lua54", "vendored"] }
-libc = "0.2"
diff --git a/src/bin/main.rs b/src/bin/main.rs
index 9eb3692..f6de012 100644
--- a/src/bin/main.rs
+++ b/src/bin/main.rs
@@ -1,8 +1,6 @@
use std::path::PathBuf;
fn main() -> Result<(), Box<dyn std::error::Error>> {
- oxwm::signal::prevent_zombie_processes();
-
let arguments: Vec<String> = std::env::args().collect();
let mut custom_config_path: Option<PathBuf> = None;
diff --git a/src/config/lua_api.rs b/src/config/lua_api.rs
index 089baec..ebb11ec 100644
--- a/src/config/lua_api.rs
+++ b/src/config/lua_api.rs
@@ -647,10 +647,6 @@ fn register_misc(lua: &Lua, parent: &Table, builder: SharedBuilder) -> Result<()
create_action_table(lua, "Restart", Value::Nil)
})?;
- let recompile = lua.create_function(|lua, ()| {
- create_action_table(lua, "Recompile", Value::Nil)
- })?;
-
let toggle_gaps = lua.create_function(|lua, ()| {
create_action_table(lua, "ToggleGaps", Value::Nil)
})?;
@@ -693,7 +689,6 @@ fn register_misc(lua: &Lua, parent: &Table, builder: SharedBuilder) -> Result<()
parent.set("autostart", autostart)?;
parent.set("quit", quit)?;
parent.set("restart", restart)?;
- parent.set("recompile", recompile)?;
parent.set("toggle_gaps", toggle_gaps)?;
parent.set("set_master_factor", set_master_factor)?;
parent.set("inc_num_master", inc_num_master)?;
@@ -781,7 +776,6 @@ fn string_to_action(s: &str) -> mlua::Result<KeyAction> {
"MoveStack" => Ok(KeyAction::MoveStack),
"Quit" => Ok(KeyAction::Quit),
"Restart" => Ok(KeyAction::Restart),
- "Recompile" => Ok(KeyAction::Recompile),
"ViewTag" => Ok(KeyAction::ViewTag),
"ToggleView" => Ok(KeyAction::ToggleView),
"MoveToTag" => Ok(KeyAction::MoveToTag),
diff --git a/src/keyboard/handlers.rs b/src/keyboard/handlers.rs
index f527819..6683816 100644
--- a/src/keyboard/handlers.rs
+++ b/src/keyboard/handlers.rs
@@ -1,5 +1,4 @@
-use std::io::{ErrorKind, Result};
-use std::process::Command;
+use std::io::Result;
use serde::Deserialize;
use x11rb::connection::Connection;
@@ -17,7 +16,6 @@ pub enum KeyAction {
MoveStack,
Quit,
Restart,
- Recompile,
ViewTag,
ToggleView,
MoveToTag,
@@ -315,16 +313,9 @@ fn handle_next_key(
pub fn handle_spawn_action(action: KeyAction, arg: &Arg, selected_monitor: usize) -> Result<()> {
if let KeyAction::Spawn = action {
match arg {
- Arg::Str(command) => match Command::new(command.as_str()).spawn() {
- Err(error) if error.kind() == ErrorKind::NotFound => {
- eprintln!(
- "KeyAction::Spawn failed: could not spawn \"{}\", command not found",
- command
- );
- }
- Err(error) => Err(error)?,
- _ => (),
- },
+ Arg::Str(command) => {
+ crate::signal::spawn_detached(command);
+ }
Arg::Array(command) => {
let Some((cmd, args)) = command.split_first() else {
return Ok(());
@@ -341,16 +332,7 @@ pub fn handle_spawn_action(action: KeyAction, arg: &Arg, selected_monitor: usize
}
let args_str: Vec<&str> = args_vec.iter().map(|s| s.as_str()).collect();
- match Command::new(cmd.as_str()).args(&args_str).spawn() {
- Err(error) if error.kind() == ErrorKind::NotFound => {
- eprintln!(
- "KeyAction::Spawn failed: could not spawn \"{}\", command not found",
- cmd
- );
- }
- Err(error) => Err(error)?,
- _ => (),
- }
+ crate::signal::spawn_detached_with_args(cmd, &args_str);
}
_ => {}
}
diff --git a/src/overlay/keybind.rs b/src/overlay/keybind.rs
index 59d3113..8dc1eee 100644
--- a/src/overlay/keybind.rs
+++ b/src/overlay/keybind.rs
@@ -198,7 +198,6 @@ impl KeybindOverlay {
KeyAction::ShowKeybindOverlay => "Show This Keybind Help".to_string(),
KeyAction::Quit => "Quit Window Manager".to_string(),
KeyAction::Restart => "Restart Window Manager".to_string(),
- KeyAction::Recompile => "Recompile Window Manager".to_string(),
KeyAction::KillClient => "Close Focused Window".to_string(),
KeyAction::Spawn => match &binding.arg {
Arg::Str(cmd) => format!("Launch: {}", cmd),
diff --git a/src/signal.rs b/src/signal.rs
index 408fbd8..c5cec0b 100644
--- a/src/signal.rs
+++ b/src/signal.rs
@@ -1,13 +1,32 @@
-use std::ptr;
+use std::process::{Command, Stdio};
-pub fn prevent_zombie_processes() {
- unsafe {
- let mut sa: libc::sigaction = std::mem::zeroed();
- libc::sigemptyset(&mut sa.sa_mask);
- sa.sa_flags = libc::SA_NOCLDSTOP | libc::SA_NOCLDWAIT | libc::SA_RESTART;
- sa.sa_sigaction = libc::SIG_IGN;
- libc::sigaction(libc::SIGCHLD, &sa, ptr::null_mut());
+pub fn spawn_detached(cmd: &str) {
+ if let Ok(mut child) = Command::new("sh")
+ .arg("-c")
+ .arg(format!("({}) &", cmd))
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .spawn()
+ {
+ let _ = child.wait();
+ }
+}
+
+pub fn spawn_detached_with_args(program: &str, args: &[&str]) {
+ let escaped_args: Vec<String> = args.iter().map(|a| shell_escape(a)).collect();
+ let full_cmd = if escaped_args.is_empty() {
+ program.to_string()
+ } else {
+ format!("{} {}", program, escaped_args.join(" "))
+ };
+ spawn_detached(&full_cmd)
+}
- while libc::waitpid(-1, ptr::null_mut(), libc::WNOHANG) > 0 {}
+fn shell_escape(s: &str) -> String {
+ if s.contains(|c: char| c.is_whitespace() || c == '\'' || c == '"' || c == '\\') {
+ format!("'{}'", s.replace('\'', "'\\''"))
+ } else {
+ s.to_string()
}
}
diff --git a/src/window_manager.rs b/src/window_manager.rs
index 0beac56..d79e163 100644
--- a/src/window_manager.rs
+++ b/src/window_manager.rs
@@ -9,7 +9,6 @@ use crate::layout::{Layout, LayoutBox, LayoutType, layout_from_str, next_layout}
use crate::monitor::{Monitor, detect_monitors};
use crate::overlay::{ErrorOverlay, KeybindOverlay, Overlay};
use std::collections::{HashMap, HashSet};
-use std::process::Command;
use x11rb::cursor::Handle as CursorHandle;
use x11rb::connection::Connection;
@@ -299,7 +298,7 @@ impl WindowManager {
window_manager.scan_existing_windows()?;
window_manager.update_bar()?;
- window_manager.run_autostart_commands()?;
+ window_manager.run_autostart_commands();
Ok(window_manager)
}
@@ -718,11 +717,7 @@ impl WindowManager {
match action {
KeyAction::Spawn => handlers::handle_spawn_action(action, arg, self.selected_monitor)?,
KeyAction::SpawnTerminal => {
- use std::process::Command;
- let terminal = &self.config.terminal;
- if let Err(error) = Command::new(terminal).spawn() {
- eprintln!("Failed to spawn terminal {}: {:?}", terminal, error);
- }
+ crate::signal::spawn_detached(&self.config.terminal);
}
KeyAction::KillClient => {
if let Some(focused) = self
@@ -787,15 +782,6 @@ impl WindowManager {
KeyAction::Quit | KeyAction::Restart => {
// Handled in handle_event
}
- KeyAction::Recompile => {
- match std::process::Command::new("oxwm")
- .arg("--recompile")
- .spawn()
- {
- Ok(_) => eprintln!("Recompiling in background"),
- Err(e) => eprintln!("Failed to spawn recompile: {}", e),
- }
- }
KeyAction::ViewTag => {
if let Arg::Int(tag_index) = arg {
self.view_tag(*tag_index as usize)?;
@@ -3808,15 +3794,10 @@ impl WindowManager {
Ok(())
}
- fn run_autostart_commands(&self) -> Result<(), WmError> {
+ fn run_autostart_commands(&self) {
for command in &self.config.autostart {
- Command::new("sh")
- .arg("-c")
- .arg(command)
- .spawn()
- .map_err(|e| WmError::Autostart(command.clone(), e))?;
+ crate::signal::spawn_detached(command);
eprintln!("[autostart] Spawned: {}", command);
}
- Ok(())
}
}