diff options
| author | Horu <73709188+HigherOrderLogic@users.noreply.github.com> | 2025-08-17 16:28:24 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-17 09:28:24 +0300 |
| commit | 271534e115e5915231c99df287bbfe396185924d (patch) | |
| tree | 5642ba961a88d5f5d1f5afc0686d7b2f2476f28c | |
| parent | af30cc8df68b29973c8b9eec290f9e6b93463929 (diff) | |
| download | niri-271534e115e5915231c99df287bbfe396185924d.tar.gz niri-271534e115e5915231c99df287bbfe396185924d.tar.bz2 niri-271534e115e5915231c99df287bbfe396185924d.zip | |
Add ConfigLoaded event to IPC, option to disable built-in notification (#1829)
* feat: config reload ipc event
* cleanups
* Rename and move the new config option
* rename to ConfigLoaded and emit at connection
---------
Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
| -rw-r--r-- | niri-config/src/lib.rs | 11 | ||||
| -rw-r--r-- | niri-ipc/src/lib.rs | 10 | ||||
| -rw-r--r-- | niri-ipc/src/state.rs | 30 | ||||
| -rw-r--r-- | src/ipc/client.rs | 8 | ||||
| -rw-r--r-- | src/ipc/server.rs | 11 | ||||
| -rw-r--r-- | src/main.rs | 1 | ||||
| -rw-r--r-- | src/ui/config_error_notification.rs | 5 | ||||
| -rw-r--r-- | src/utils/watcher.rs | 17 | ||||
| -rw-r--r-- | wiki/Configuration:-Miscellaneous.md | 19 |
9 files changed, 107 insertions, 5 deletions
diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index 613aad3a..16ec6dca 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -60,6 +60,8 @@ pub struct Config { #[knuffel(child, default)] pub hotkey_overlay: HotkeyOverlay, #[knuffel(child, default)] + pub config_notification: ConfigNotification, + #[knuffel(child, default)] pub animations: Animations, #[knuffel(child, default)] pub gestures: Gestures, @@ -1048,6 +1050,12 @@ pub struct HotkeyOverlay { } #[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq, Eq)] +pub struct ConfigNotification { + #[knuffel(child)] + pub disable_failed: bool, +} + +#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct Clipboard { #[knuffel(child)] pub disable_primary: bool, @@ -4769,6 +4777,9 @@ mod tests { skip_at_startup: true, hide_not_bound: false, }, + config_notification: ConfigNotification { + disable_failed: false, + }, animations: Animations { off: false, slowdown: FloatOrInt( diff --git a/niri-ipc/src/lib.rs b/niri-ipc/src/lib.rs index 737f1647..a1be86d2 100644 --- a/niri-ipc/src/lib.rs +++ b/niri-ipc/src/lib.rs @@ -1399,6 +1399,16 @@ pub enum Event { /// The new state of the overview. is_open: bool, }, + /// The configuration was reloaded. + /// + /// You will always receive this event when connecting to the event stream, indicating the last + /// config load attempt. + ConfigLoaded { + /// Whether the loading failed. + /// + /// For example, the config file couldn't be parsed. + failed: bool, + }, } impl FromStr for WorkspaceReferenceArg { diff --git a/niri-ipc/src/state.rs b/niri-ipc/src/state.rs index ef883021..3ba63a52 100644 --- a/niri-ipc/src/state.rs +++ b/niri-ipc/src/state.rs @@ -43,6 +43,9 @@ pub struct EventStreamState { /// State of the overview. pub overview: OverviewState, + + /// State of the config. + pub config: ConfigState, } /// The workspaces state communicated over the event stream. @@ -73,6 +76,13 @@ pub struct OverviewState { pub is_open: bool, } +/// The config state communicated over the event stream. +#[derive(Debug, Default)] +pub struct ConfigState { + /// Whether the last config load attempt had failed. + pub failed: bool, +} + impl EventStreamStatePart for EventStreamState { fn replicate(&self) -> Vec<Event> { let mut events = Vec::new(); @@ -80,6 +90,7 @@ impl EventStreamStatePart for EventStreamState { events.extend(self.windows.replicate()); events.extend(self.keyboard_layouts.replicate()); events.extend(self.overview.replicate()); + events.extend(self.config.replicate()); events } @@ -88,6 +99,7 @@ impl EventStreamStatePart for EventStreamState { let event = self.windows.apply(event)?; let event = self.keyboard_layouts.apply(event)?; let event = self.overview.apply(event)?; + let event = self.config.apply(event)?; Some(event) } } @@ -244,3 +256,21 @@ impl EventStreamStatePart for OverviewState { None } } + +impl EventStreamStatePart for ConfigState { + fn replicate(&self) -> Vec<Event> { + vec![Event::ConfigLoaded { + failed: self.failed, + }] + } + + fn apply(&mut self, event: Event) -> Option<Event> { + match event { + Event::ConfigLoaded { failed } => { + self.failed = failed; + } + event => return Some(event), + } + None + } +} diff --git a/src/ipc/client.rs b/src/ipc/client.rs index 42fbbf75..094bb636 100644 --- a/src/ipc/client.rs +++ b/src/ipc/client.rs @@ -459,6 +459,14 @@ pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> { Event::OverviewOpenedOrClosed { is_open: opened } => { println!("Overview toggled: {opened}"); } + Event::ConfigLoaded { failed } => { + let status = if failed { + "with an error" + } else { + "successfully" + }; + println!("Config loaded {status}"); + } } } } diff --git a/src/ipc/server.rs b/src/ipc/server.rs index 464a2a13..051bccab 100644 --- a/src/ipc/server.rs +++ b/src/ipc/server.rs @@ -762,4 +762,15 @@ impl State { state.apply(event.clone()); server.send_event(event); } + + pub fn ipc_config_loaded(&mut self, failed: bool) { + let Some(server) = &self.niri.ipc_server else { + return; + }; + let mut state = server.event_stream_state.borrow_mut(); + + let event = Event::ConfigLoaded { failed }; + state.apply(event.clone()); + server.send_event(event); + } } diff --git a/src/main.rs b/src/main.rs index 2b3e1c5a..9654f7e9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -241,6 +241,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { // Show the config error notification right away if needed. if config_errored { state.niri.config_error_notification.show(); + state.ipc_config_loaded(true); } else if let Some(path) = config_created_at { state.niri.config_error_notification.show_created(path); } diff --git a/src/ui/config_error_notification.rs b/src/ui/config_error_notification.rs index 4e976633..20667172 100644 --- a/src/ui/config_error_notification.rs +++ b/src/ui/config_error_notification.rs @@ -78,6 +78,11 @@ impl ConfigErrorNotification { } pub fn show(&mut self) { + let c = self.config.borrow(); + if c.config_notification.disable_failed { + return; + } + if self.created_path.is_some() { self.created_path = None; self.buffers.borrow_mut().clear(); diff --git a/src/utils/watcher.rs b/src/utils/watcher.rs index 4ed4c8ae..034e963a 100644 --- a/src/utils/watcher.rs +++ b/src/utils/watcher.rs @@ -5,7 +5,7 @@ use std::sync::mpsc; use std::time::{Duration, SystemTime}; use std::{io, thread}; -use niri_config::ConfigPath; +use niri_config::{Config, ConfigPath}; use smithay::reexports::calloop::channel::SyncSender; use crate::niri::State; @@ -137,10 +137,17 @@ pub fn setup(state: &mut State, config_path: &ConfigPath) { state .niri .event_loop - .insert_source(rx, |event, _, state| match event { - calloop::channel::Event::Msg(config) => state.reload_config(config), - calloop::channel::Event::Closed => (), - }) + .insert_source( + rx, + |event: calloop::channel::Event<Result<Config, ()>>, _, state| match event { + calloop::channel::Event::Msg(config) => { + let failed = config.is_err(); + state.reload_config(config); + state.ipc_config_loaded(failed); + } + calloop::channel::Event::Closed => (), + }, + ) .unwrap(); state.niri.config_file_watcher = Some(Watcher::new(config_path.clone(), process, tx)); diff --git a/wiki/Configuration:-Miscellaneous.md b/wiki/Configuration:-Miscellaneous.md index 3eba0a31..f2d1010a 100644 --- a/wiki/Configuration:-Miscellaneous.md +++ b/wiki/Configuration:-Miscellaneous.md @@ -49,6 +49,10 @@ hotkey-overlay { skip-at-startup hide-not-bound } + +config-notification { + disable-failed +} ``` ### `spawn-at-startup` @@ -277,3 +281,18 @@ hotkey-overlay { ``` You can customize which binds the hotkey overlay shows using the [`hotkey-overlay-title` property](./Configuration:-Key-Bindings.md#custom-hotkey-overlay-titles). + +### `config-notification` + +<sup>Since: next release</sup> + +Settings for the config created/failed notification. + +Set the `disable-failed` flag to disable the "Failed to parse the config file" notification. +For example, if you have a custom one. + +```kdl +config-notification { + disable-failed +} +``` |
