mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-23 02:05:33 +07:00
Add environment {} config section
This commit is contained in:
@@ -39,6 +39,8 @@ pub struct Config {
|
|||||||
pub hotkey_overlay: HotkeyOverlay,
|
pub hotkey_overlay: HotkeyOverlay,
|
||||||
#[knuffel(child, default)]
|
#[knuffel(child, default)]
|
||||||
pub animations: Animations,
|
pub animations: Animations,
|
||||||
|
#[knuffel(child, default)]
|
||||||
|
pub environment: Environment,
|
||||||
#[knuffel(children(name = "window-rule"))]
|
#[knuffel(children(name = "window-rule"))]
|
||||||
pub window_rules: Vec<WindowRule>,
|
pub window_rules: Vec<WindowRule>,
|
||||||
#[knuffel(child, default)]
|
#[knuffel(child, default)]
|
||||||
@@ -572,6 +574,17 @@ pub enum AnimationCurve {
|
|||||||
EaseOutExpo,
|
EaseOutExpo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(knuffel::Decode, Debug, Default, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Environment(#[knuffel(children)] pub Vec<EnvironmentVariable>);
|
||||||
|
|
||||||
|
#[derive(knuffel::Decode, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct EnvironmentVariable {
|
||||||
|
#[knuffel(node_name)]
|
||||||
|
pub name: String,
|
||||||
|
#[knuffel(argument)]
|
||||||
|
pub value: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(knuffel::Decode, Debug, Default, Clone, PartialEq)]
|
#[derive(knuffel::Decode, Debug, Default, Clone, PartialEq)]
|
||||||
pub struct WindowRule {
|
pub struct WindowRule {
|
||||||
#[knuffel(children(name = "match"))]
|
#[knuffel(children(name = "match"))]
|
||||||
@@ -1061,6 +1074,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
environment {
|
||||||
|
QT_QPA_PLATFORM "wayland"
|
||||||
|
DISPLAY null
|
||||||
|
}
|
||||||
|
|
||||||
window-rule {
|
window-rule {
|
||||||
match app-id=".*alacritty"
|
match app-id=".*alacritty"
|
||||||
exclude title="~"
|
exclude title="~"
|
||||||
@@ -1217,6 +1235,16 @@ mod tests {
|
|||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
environment: Environment(vec![
|
||||||
|
EnvironmentVariable {
|
||||||
|
name: String::from("QT_QPA_PLATFORM"),
|
||||||
|
value: Some(String::from("wayland")),
|
||||||
|
},
|
||||||
|
EnvironmentVariable {
|
||||||
|
name: String::from("DISPLAY"),
|
||||||
|
value: None,
|
||||||
|
},
|
||||||
|
]),
|
||||||
window_rules: vec![WindowRule {
|
window_rules: vec![WindowRule {
|
||||||
matches: vec![Match {
|
matches: vec![Match {
|
||||||
app_id: Some(Regex::new(".*alacritty").unwrap()),
|
app_id: Some(Regex::new(".*alacritty").unwrap()),
|
||||||
|
|||||||
@@ -199,6 +199,15 @@ layout {
|
|||||||
// which may be more convenient to use.
|
// which may be more convenient to use.
|
||||||
// spawn-at-startup "alacritty" "-e" "fish"
|
// spawn-at-startup "alacritty" "-e" "fish"
|
||||||
|
|
||||||
|
// You can override environment variables for processes spawned by niri.
|
||||||
|
environment {
|
||||||
|
// Set a variable like this:
|
||||||
|
// QT_QPA_PLATFORM "wayland"
|
||||||
|
|
||||||
|
// Remove a variable by using null as the value:
|
||||||
|
// DISPLAY null
|
||||||
|
}
|
||||||
|
|
||||||
cursor {
|
cursor {
|
||||||
// Change the theme and size of the cursor as well as set the
|
// Change the theme and size of the cursor as well as set the
|
||||||
// `XCURSOR_THEME` and `XCURSOR_SIZE` env variables.
|
// `XCURSOR_THEME` and `XCURSOR_SIZE` env variables.
|
||||||
|
|||||||
+4
-1
@@ -15,7 +15,9 @@ use niri::cli::{Cli, Sub};
|
|||||||
use niri::dbus;
|
use niri::dbus;
|
||||||
use niri::ipc::client::handle_msg;
|
use niri::ipc::client::handle_msg;
|
||||||
use niri::niri::State;
|
use niri::niri::State;
|
||||||
use niri::utils::spawning::{spawn, REMOVE_ENV_RUST_BACKTRACE, REMOVE_ENV_RUST_LIB_BACKTRACE};
|
use niri::utils::spawning::{
|
||||||
|
spawn, CHILD_ENV, REMOVE_ENV_RUST_BACKTRACE, REMOVE_ENV_RUST_LIB_BACKTRACE,
|
||||||
|
};
|
||||||
use niri::utils::watcher::Watcher;
|
use niri::utils::watcher::Watcher;
|
||||||
use niri::utils::{cause_panic, version, IS_SYSTEMD_SERVICE};
|
use niri::utils::{cause_panic, version, IS_SYSTEMD_SERVICE};
|
||||||
use niri_config::Config;
|
use niri_config::Config;
|
||||||
@@ -161,6 +163,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
animation::ANIMATION_SLOWDOWN.store(slowdown, Ordering::Relaxed);
|
animation::ANIMATION_SLOWDOWN.store(slowdown, Ordering::Relaxed);
|
||||||
|
|
||||||
let spawn_at_startup = mem::take(&mut config.spawn_at_startup);
|
let spawn_at_startup = mem::take(&mut config.spawn_at_startup);
|
||||||
|
*CHILD_ENV.write().unwrap() = mem::take(&mut config.environment);
|
||||||
|
|
||||||
// Create the compositor.
|
// Create the compositor.
|
||||||
let mut event_loop = EventLoop::try_new().unwrap();
|
let mut event_loop = EventLoop::try_new().unwrap();
|
||||||
|
|||||||
+4
-1
@@ -104,6 +104,7 @@ use crate::ui::config_error_notification::ConfigErrorNotification;
|
|||||||
use crate::ui::exit_confirm_dialog::ExitConfirmDialog;
|
use crate::ui::exit_confirm_dialog::ExitConfirmDialog;
|
||||||
use crate::ui::hotkey_overlay::HotkeyOverlay;
|
use crate::ui::hotkey_overlay::HotkeyOverlay;
|
||||||
use crate::ui::screenshot_ui::{ScreenshotUi, ScreenshotUiRenderElement};
|
use crate::ui::screenshot_ui::{ScreenshotUi, ScreenshotUiRenderElement};
|
||||||
|
use crate::utils::spawning::CHILD_ENV;
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
center, get_monotonic_time, make_screenshot_path, output_size, write_png_rgba8,
|
center, get_monotonic_time, make_screenshot_path, output_size, write_png_rgba8,
|
||||||
};
|
};
|
||||||
@@ -577,7 +578,7 @@ impl State {
|
|||||||
pub fn reload_config(&mut self, path: PathBuf) {
|
pub fn reload_config(&mut self, path: PathBuf) {
|
||||||
let _span = tracy_client::span!("State::reload_config");
|
let _span = tracy_client::span!("State::reload_config");
|
||||||
|
|
||||||
let config = match Config::load(&path) {
|
let mut config = match Config::load(&path) {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("{:?}", err.context("error loading config"));
|
warn!("{:?}", err.context("error loading config"));
|
||||||
@@ -598,6 +599,8 @@ impl State {
|
|||||||
};
|
};
|
||||||
animation::ANIMATION_SLOWDOWN.store(slowdown, Ordering::Relaxed);
|
animation::ANIMATION_SLOWDOWN.store(slowdown, Ordering::Relaxed);
|
||||||
|
|
||||||
|
*CHILD_ENV.write().unwrap() = mem::take(&mut config.environment);
|
||||||
|
|
||||||
let mut reload_xkb = None;
|
let mut reload_xkb = None;
|
||||||
let mut libinput_config_changed = false;
|
let mut libinput_config_changed = false;
|
||||||
let mut output_config_changed = false;
|
let mut output_config_changed = false;
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ use std::os::unix::process::CommandExt;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::RwLock;
|
||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
|
|
||||||
use libc::close_range;
|
use libc::close_range;
|
||||||
|
use niri_config::Environment;
|
||||||
use smithay::reexports::rustix;
|
use smithay::reexports::rustix;
|
||||||
use smithay::reexports::rustix::io::{close, read, retry_on_intr, write};
|
use smithay::reexports::rustix::io::{close, read, retry_on_intr, write};
|
||||||
use smithay::reexports::rustix::pipe::{pipe_with, PipeFlags};
|
use smithay::reexports::rustix::pipe::{pipe_with, PipeFlags};
|
||||||
@@ -15,6 +17,7 @@ use crate::utils::expand_home;
|
|||||||
|
|
||||||
pub static REMOVE_ENV_RUST_BACKTRACE: AtomicBool = AtomicBool::new(false);
|
pub static REMOVE_ENV_RUST_BACKTRACE: AtomicBool = AtomicBool::new(false);
|
||||||
pub static REMOVE_ENV_RUST_LIB_BACKTRACE: AtomicBool = AtomicBool::new(false);
|
pub static REMOVE_ENV_RUST_LIB_BACKTRACE: AtomicBool = AtomicBool::new(false);
|
||||||
|
pub static CHILD_ENV: RwLock<Environment> = RwLock::new(Environment(Vec::new()));
|
||||||
|
|
||||||
/// Spawns the command to run independently of the compositor.
|
/// Spawns the command to run independently of the compositor.
|
||||||
pub fn spawn<T: AsRef<OsStr> + Send + 'static>(command: Vec<T>) {
|
pub fn spawn<T: AsRef<OsStr> + Send + 'static>(command: Vec<T>) {
|
||||||
@@ -67,6 +70,17 @@ fn spawn_sync(command: impl AsRef<OsStr>, args: impl IntoIterator<Item = impl As
|
|||||||
process.env_remove("RUST_LIB_BACKTRACE");
|
process.env_remove("RUST_LIB_BACKTRACE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set configured environment.
|
||||||
|
let env = CHILD_ENV.read().unwrap();
|
||||||
|
for var in &env.0 {
|
||||||
|
if let Some(value) = &var.value {
|
||||||
|
process.env(&var.name, value);
|
||||||
|
} else {
|
||||||
|
process.env_remove(&var.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drop(env);
|
||||||
|
|
||||||
// When running as a systemd session, we want to put children into their own transient scopes
|
// When running as a systemd session, we want to put children into their own transient scopes
|
||||||
// in order to separate them from the niri process. This is helpful for example to prevent the
|
// in order to separate them from the niri process. This is helpful for example to prevent the
|
||||||
// OOM killer from taking down niri together with a misbehaving client.
|
// OOM killer from taking down niri together with a misbehaving client.
|
||||||
|
|||||||
Reference in New Issue
Block a user