diff --git a/docs/wiki/Integrating-niri.md b/docs/wiki/Integrating-niri.md index b12800cf..5109db15 100644 --- a/docs/wiki/Integrating-niri.md +++ b/docs/wiki/Integrating-niri.md @@ -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 `. + You can split the niri config file into multiple files using [`include`](./Configuration:-Include.md). ### Xwayland diff --git a/niri-config/src/binds.rs b/niri-config/src/binds.rs index 597c742e..98ac9fea 100644 --- a/niri-config/src/binds.rs +++ b/niri-config/src/binds.rs @@ -368,7 +368,7 @@ pub enum Action { #[knuffel(skip)] UnsetWindowUrgent(u64), #[knuffel(skip)] - LoadConfigFile, + LoadConfigFile(#[knuffel(argument)] Option), #[knuffel(skip)] MruAdvance { direction: MruDirection, @@ -699,7 +699,7 @@ impl From 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), } } } diff --git a/niri-ipc/src/lib.rs b/niri-ipc/src/lib.rs index d4a60c17..50845633 100644 --- a/niri-ipc/src/lib.rs +++ b/niri-ipc/src/lib.rs @@ -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, + }, } /// Change in window or column size. diff --git a/src/input/mod.rs b/src/input/mod.rs index 40e7ee4e..ab31df94 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -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 => { diff --git a/src/ipc/server.rs b/src/ipc/server.rs index 48c1234d..db71da6d 100644 --- a/src/ipc/server.rs +++ b/src/ipc/server.rs @@ -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(()) } diff --git a/src/utils/watcher.rs b/src/utils/watcher.rs index a16bdb16..c61410f8 100644 --- a/src/utils/watcher.rs +++ b/src/utils/watcher.rs @@ -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>, } 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) { + let _ = self.load_config.send(path); } }