diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 98c0e8d..9ecc9b1 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -759,6 +759,9 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "spawn") == 0) { func = spawn; (*arg).v = strdup(arg_value); + } else if (strcmp(func_name, "spawn_shell") == 0) { + func = spawn_shell; + (*arg).v = strdup(arg_value); } else if (strcmp(func_name, "spawn_on_empty") == 0) { func = spawn_on_empty; (*arg).v = strdup(arg_value); // 注意:之后需要释放这个内存 diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index d4ef97c..1bc039d 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -20,6 +20,7 @@ void togglemaxmizescreen(const Arg *arg); void togglegaps(const Arg *arg); void tagmon(const Arg *arg); void spawn(const Arg *arg); +void spawn_shell(const Arg *arg); void spawn_on_empty(const Arg *arg); void setlayout(const Arg *arg); void switch_layout(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 2c6e43f..df2b8c6 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -615,6 +615,32 @@ void centerwin(const Arg *arg) { resize(c, c->oldgeom, 1); } +void spawn_shell(const Arg *arg) { + if (!arg->v) + return; + + if (fork() == 0) { + // 1. 忽略可能导致 coredump 的信号 + signal(SIGSEGV, SIG_IGN); + signal(SIGABRT, SIG_IGN); + signal(SIGILL, SIG_IGN); + + dup2(STDERR_FILENO, STDOUT_FILENO); + setsid(); + + execlp("sh", "sh", "-c", arg->v, (char *)NULL); + + // fallback to bash + execlp("bash", "bash", "-c", arg->v, (char *)NULL); + + // if execlp fails, we should not reach here + wlr_log(WLR_ERROR, + "mango: failed to execute command '%s' with shell: %s\n", + arg->v, strerror(errno)); + _exit(EXIT_FAILURE); + } +} + void spawn(const Arg *arg) { if (!arg->v) @@ -648,7 +674,7 @@ void spawn(const Arg *arg) { execvp(argv[0], argv); // 4. execvp 失败时:打印错误并直接退出(避免 coredump) - wlr_log(WLR_ERROR, "dwl: execvp '%s' failed: %s\n", argv[0], + wlr_log(WLR_ERROR, "mango: execvp '%s' failed: %s\n", argv[0], strerror(errno)); _exit(EXIT_FAILURE); // 使用 _exit 避免缓冲区刷新等操作 }