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) {