Add load-config-file --path to load a different config (#3395)

* ipc: allow load-config to relocate the path of the config

* doc: add info about alternative configuration paths and relocating

Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>

* Update docs/wiki/Integrating-niri.md

* Update niri-ipc/src/lib.rs

* Update src/ipc/server.rs

---------

Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
This commit is contained in:
ジムワルド
2026-02-06 16:22:16 +00:00
committed by GitHub
parent 189917c933
commit 549148d277
6 changed files with 35 additions and 10 deletions
+3
View File
@@ -11,6 +11,9 @@ When this file is present, niri *will not* automatically create a config at `~/.
Keep in mind that we update the default config in new releases, so if you have a custom `/etc/niri/config.kdl`, you likely want to inspect and apply the relevant changes too.
The default configuration locations can be overridden with the `NIRI_CONFIG` environment variable.
You can also change the configuration path at runtime via the niri IPC or using the command `niri msg action load-config-file --path <path-to-config.kdl>`.
You can split the niri config file into multiple files using [`include`](./Configuration:-Include.md).
### Xwayland
+2 -2
View File
@@ -368,7 +368,7 @@ pub enum Action {
#[knuffel(skip)]
UnsetWindowUrgent(u64),
#[knuffel(skip)]
LoadConfigFile,
LoadConfigFile(#[knuffel(argument)] Option<String>),
#[knuffel(skip)]
MruAdvance {
direction: MruDirection,
@@ -699,7 +699,7 @@ impl From<niri_ipc::Action> for Action {
niri_ipc::Action::ToggleWindowUrgent { id } => Self::ToggleWindowUrgent(id),
niri_ipc::Action::SetWindowUrgent { id } => Self::SetWindowUrgent(id),
niri_ipc::Action::UnsetWindowUrgent { id } => Self::UnsetWindowUrgent(id),
niri_ipc::Action::LoadConfigFile {} => Self::LoadConfigFile,
niri_ipc::Action::LoadConfigFile { path } => Self::LoadConfigFile(path),
}
}
}
+7 -1
View File
@@ -936,7 +936,13 @@ pub enum Action {
///
/// Can be useful for scripts changing the config file, to avoid waiting the small duration for
/// niri's config file watcher to notice the changes.
LoadConfigFile {},
LoadConfigFile {
/// Path of a new config file to load.
///
/// If unset, reloads the current config file.
#[cfg_attr(feature = "clap", arg(long))]
path: Option<String>,
},
}
/// Change in window or column size.
+2 -2
View File
@@ -2318,9 +2318,9 @@ impl State {
}
self.niri.queue_redraw_all();
}
Action::LoadConfigFile => {
Action::LoadConfigFile(path) => {
if let Some(watcher) = &self.niri.config_file_watcher {
watcher.load_config();
watcher.load_config(path);
}
}
Action::MruConfirm => {
+9 -1
View File
@@ -463,7 +463,8 @@ async fn process(ctx: &ClientCtx, request: Request) -> Reply {
fn validate_action(action: &Action) -> Result<(), String> {
if let Action::Screenshot { path, .. }
| Action::ScreenshotScreen { path, .. }
| Action::ScreenshotWindow { path, .. } = action
| Action::ScreenshotWindow { path, .. }
| Action::LoadConfigFile { path } = action
{
if let Some(path) = path {
// Relative paths are resolved against the niri compositor's working directory, which
@@ -474,6 +475,13 @@ fn validate_action(action: &Action) -> Result<(), String> {
}
}
if let Action::LoadConfigFile { path: Some(path) } = action {
let p = Path::new(path);
if !p.is_file() {
return Err(format!("path does not point to a file: {path}"));
}
}
Ok(())
}
+12 -4
View File
@@ -14,7 +14,7 @@ use crate::niri::State;
const POLLING_INTERVAL: Duration = Duration::from_millis(500);
pub struct Watcher {
load_config: mpsc::Sender<()>,
load_config: mpsc::Sender<Option<String>>,
}
struct WatcherInner {
@@ -67,7 +67,15 @@ impl Watcher {
loop {
let mut should_load = match load_config_rx.recv_timeout(POLLING_INTERVAL) {
Ok(()) => true,
Ok(path) => {
if let Some(path) = path {
inner = WatcherInner::new(
ConfigPath::Explicit(PathBuf::from(path)),
Vec::new(),
);
}
true
}
Err(mpsc::RecvTimeoutError::Disconnected) => break,
Err(mpsc::RecvTimeoutError::Timeout) => false,
};
@@ -105,8 +113,8 @@ impl Watcher {
Self { load_config }
}
pub fn load_config(&self) {
let _ = self.load_config.send(());
pub fn load_config(&self, path: Option<String>) {
let _ = self.load_config.send(path);
}
}