aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/input/mod.rs6
-rw-r--r--src/main.rs8
-rw-r--r--src/ui/hotkey_overlay.rs7
-rw-r--r--src/utils/spawning.rs10
4 files changed, 27 insertions, 4 deletions
diff --git a/src/input/mod.rs b/src/input/mod.rs
index cc07aed3..711a09dd 100644
--- a/src/input/mod.rs
+++ b/src/input/mod.rs
@@ -44,7 +44,7 @@ use crate::layout::scrolling::ScrollDirection;
use crate::layout::{ActivateWindow, LayoutElement as _};
use crate::niri::{CastTarget, PointerVisibility, State};
use crate::ui::screenshot_ui::ScreenshotUi;
-use crate::utils::spawning::spawn;
+use crate::utils::spawning::{spawn, spawn_sh};
use crate::utils::{center, get_monotonic_time, ResizeEdge};
pub mod backend_ext;
@@ -595,6 +595,10 @@ impl State {
let (token, _) = self.niri.activation_state.create_external_token(None);
spawn(command, Some(token.clone()));
}
+ Action::SpawnSh(command) => {
+ let (token, _) = self.niri.activation_state.create_external_token(None);
+ spawn_sh(command, Some(token.clone()));
+ }
Action::DoScreenTransition(delay_ms) => {
self.backend.with_primary_renderer(|renderer| {
self.niri.do_screen_transition(renderer, delay_ms);
diff --git a/src/main.rs b/src/main.rs
index 9654f7e9..c17e2f39 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,8 +20,8 @@ use niri::dbus;
use niri::ipc::client::handle_msg;
use niri::niri::State;
use niri::utils::spawning::{
- spawn, store_and_increase_nofile_rlimit, CHILD_DISPLAY, CHILD_ENV, REMOVE_ENV_RUST_BACKTRACE,
- REMOVE_ENV_RUST_LIB_BACKTRACE,
+ spawn, spawn_sh, store_and_increase_nofile_rlimit, CHILD_DISPLAY, CHILD_ENV,
+ REMOVE_ENV_RUST_BACKTRACE, REMOVE_ENV_RUST_LIB_BACKTRACE,
};
use niri::utils::{cause_panic, version, watcher, xwayland, IS_SYSTEMD_SERVICE};
use niri_config::ConfigPath;
@@ -151,6 +151,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.unwrap_or_default();
let spawn_at_startup = mem::take(&mut config.spawn_at_startup);
+ let spawn_at_startup_sh = mem::take(&mut config.spawn_at_startup_sh);
*CHILD_ENV.write().unwrap() = mem::take(&mut config.environment);
store_and_increase_nofile_rlimit();
@@ -237,6 +238,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
for elem in spawn_at_startup {
spawn(elem.command, None);
}
+ for elem in spawn_at_startup_sh {
+ spawn_sh(elem.command, None);
+ }
// Show the config error notification right away if needed.
if config_errored {
diff --git a/src/ui/hotkey_overlay.rs b/src/ui/hotkey_overlay.rs
index 7042d2c0..d30d500d 100644
--- a/src/ui/hotkey_overlay.rs
+++ b/src/ui/hotkey_overlay.rs
@@ -270,7 +270,7 @@ fn render(
// Add the spawn actions.
for bind in binds.iter().filter(|bind| {
- matches!(bind.action, Action::Spawn(_))
+ matches!(bind.action, Action::Spawn(_) | Action::SpawnSh(_))
// Only show binds with Mod or Super to filter out stuff like volume up/down.
&& (bind.key.modifiers.contains(Modifiers::COMPOSITOR)
|| bind.key.modifiers.contains(Modifiers::SUPER))
@@ -447,6 +447,11 @@ fn action_name(action: &Action) -> String {
"Spawn <span face='monospace' bgcolor='#000000'>{}</span>",
args.first().unwrap_or(&String::new())
),
+ Action::SpawnSh(command) => format!(
+ "Spawn <span face='monospace' bgcolor='#000000'>{}</span>",
+ // Fairly crude but should get the job done in most cases.
+ command.split_ascii_whitespace().next().unwrap_or("")
+ ),
_ => String::from("FIXME: Unknown"),
}
}
diff --git a/src/utils/spawning.rs b/src/utils/spawning.rs
index a6f516db..61912eae 100644
--- a/src/utils/spawning.rs
+++ b/src/utils/spawning.rs
@@ -83,6 +83,16 @@ pub fn spawn<T: AsRef<OsStr> + Send + 'static>(command: Vec<T>, token: Option<Xd
}
}
+/// Spawns the command through the shell.
+///
+/// We hardcode `sh -c`, consistent with other compositors:
+///
+/// - https://github.com/swaywm/sway/blob/b3dcde8d69c3f1304b076968a7a64f54d0c958be/sway/commands/exec_always.c#L64
+/// - https://github.com/hyprwm/Hyprland/blob/1ac1ff457ab8ef1ae6a8f2ab17ee7965adfa729f/src/managers/KeybindManager.cpp#L987
+pub fn spawn_sh(command: String, token: Option<XdgActivationToken>) {
+ spawn(vec![String::from("sh"), String::from("-c"), command], token);
+}
+
fn spawn_sync(
command: impl AsRef<OsStr>,
args: impl IntoIterator<Item = impl AsRef<OsStr>>,