oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git

fix: prevent crash when spawning non-existent commands

Commit
2971bafad6e0e8dbdc3958fb410782f408c31646
Parent
9b07b6c
Author
emzywastaken <amiamemetoo@gmail.com>
Date
2025-10-12 20:32:40
Previously, spawning a command that didn't exist would cause the wm to
crash. Commit adds proper error handling for `KeyAction::Spawn` to catch
IO's `ErrorKind::NotFound` and prints a warning instead of propagating
up the call stack.

Diff

diff --git a/src/keyboard/handlers.rs b/src/keyboard/handlers.rs
index 3933192..77d45db 100644
--- a/src/keyboard/handlers.rs
+++ b/src/keyboard/handlers.rs
@@ -1,3 +1,5 @@
+use std::process::Command;
+
 use anyhow::Result;
 use x11rb::connection::Connection;
 use x11rb::protocol::xproto::*;
@@ -92,3 +94,41 @@ pub fn handle_key_press(event: KeyPressEvent, keybindings: &[Key]) -> Result<(Ke
 
     Ok((KeyAction::None, Arg::None))
 }
+
+pub fn handle_spawn_action(action: KeyAction, arg: &Arg) -> Result<()> {
+    use std::io::ErrorKind;
+    match action {
+        KeyAction::Spawn => match arg {
+            Arg::Str(command) => match Command::new(command).spawn() {
+                Err(err) if err.kind() == ErrorKind::NotFound => {
+                    eprintln!(
+                        "KeyAction::Spawn failed: could not spawn \"{}\", command not found",
+                        command
+                    );
+                }
+                Err(err) => Err(err)?,
+                _ => (),
+            },
+            Arg::Array(command) => {
+                let Some((cmd, args)) = command.split_first() else {
+                    return Ok(());
+                };
+
+                match Command::new(cmd).args(args).spawn() {
+                    Err(err) if err.kind() == ErrorKind::NotFound => {
+                        eprintln!(
+                            "KeyAction::Spawn failed: could not spawn \"{}\", command not found",
+                            cmd
+                        );
+                    }
+                    Err(err) => Err(err)?,
+                    _ => (),
+                }
+            }
+            _ => {}
+        },
+        _ => {}
+    }
+
+    Ok(())
+}
diff --git a/src/window_manager.rs b/src/window_manager.rs
index d211978..8599437 100644
--- a/src/window_manager.rs
+++ b/src/window_manager.rs
@@ -1,6 +1,6 @@
 use crate::Config;
 use crate::bar::Bar;
-use crate::keyboard::{self, Arg, KeyAction};
+use crate::keyboard::{self, Arg, KeyAction, handlers};
 use crate::layout::GapConfig;
 use crate::layout::Layout;
 use crate::layout::tiling::TilingLayout;
@@ -449,17 +449,7 @@ impl WindowManager {
 
     fn handle_key_action(&mut self, action: KeyAction, arg: &Arg) -> Result<()> {
         match action {
-            KeyAction::Spawn => match arg {
-                Arg::Str(command) => {
-                    std::process::Command::new(command).spawn()?;
-                }
-                Arg::Array(cmd) => {
-                    if let Some((program, args)) = cmd.split_first() {
-                        std::process::Command::new(program).args(args).spawn()?;
-                    }
-                }
-                _ => {}
-            },
+            KeyAction::Spawn => handlers::handle_spawn_action(action, arg)?,
             KeyAction::KillClient => {
                 if let Some(focused) = self.focused_window {
                     match self.connection.kill_client(focused) {