diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.rs | 4 | ||||
| -rw-r--r-- | src/main.rs | 26 | ||||
| -rw-r--r-- | src/niri.rs | 19 | ||||
| -rw-r--r-- | src/watcher.rs | 60 |
4 files changed, 103 insertions, 6 deletions
diff --git a/src/config.rs b/src/config.rs index 91b4c2e1..82ff7fb2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -237,7 +237,7 @@ impl Default for DebugConfig { } impl Config { - pub fn load(path: Option<PathBuf>) -> miette::Result<Self> { + pub fn load(path: Option<PathBuf>) -> miette::Result<(Self, PathBuf)> { let path = if let Some(path) = path { path } else { @@ -255,7 +255,7 @@ impl Config { let config = Self::parse("config.kdl", &contents).context("error parsing")?; debug!("loaded config from {path:?}"); - Ok(config) + Ok((config, path)) } pub fn parse(filename: &str, text: &str) -> Result<Self, knuffel::Error> { diff --git a/src/main.rs b/src/main.rs index 82f80dd3..e5e26bca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ mod layout; mod niri; mod pw_utils; mod utils; +mod watcher; use std::ffi::OsString; use std::path::PathBuf; @@ -22,10 +23,11 @@ use config::Config; use miette::Context; use niri::{Niri, State}; use portable_atomic::Ordering; -use smithay::reexports::calloop::EventLoop; +use smithay::reexports::calloop::{self, EventLoop}; use smithay::reexports::wayland_server::Display; use tracing_subscriber::EnvFilter; use utils::spawn; +use watcher::Watcher; #[derive(Parser)] #[command(author, version, about, long_about = None)] @@ -52,11 +54,11 @@ fn main() { let _client = tracy_client::Client::start(); - let mut config = match Config::load(cli.config).context("error loading config") { - Ok(config) => config, + let (mut config, path) = match Config::load(cli.config).context("error loading config") { + Ok((config, path)) => (config, Some(path)), Err(err) => { warn!("{err:?}"); - Config::default() + (Config::default(), None) } }; animation::ANIMATION_SLOWDOWN.store(config.debug.animation_slowdown, Ordering::Relaxed); @@ -71,6 +73,22 @@ fn main() { display, ); + // Set up config file watcher. + let _watcher = if let Some(path) = path { + let (tx, rx) = calloop::channel::sync_channel(1); + let watcher = Watcher::new(path.clone(), tx); + event_loop + .handle() + .insert_source(rx, move |event, _, state| match event { + calloop::channel::Event::Msg(()) => state.reload_config(path.clone()), + calloop::channel::Event::Closed => (), + }) + .unwrap(); + Some(watcher) + } else { + None + }; + // Spawn commands from cli and auto-start. if let Some((command, args)) = cli.command.split_first() { spawn(command, args); diff --git a/src/niri.rs b/src/niri.rs index ea061bc3..41c6a41e 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -197,6 +197,25 @@ impl State { self.niri.queue_redraw_all(); } } + + pub fn reload_config(&mut self, path: PathBuf) { + let _span = tracy_client::span!("State::reload_config"); + + let config = match Config::load(Some(path)) { + Ok((config, _)) => config, + Err(err) => { + warn!("{:?}", err.context("error loading config")); + return; + } + }; + + *self.niri.config.borrow_mut() = config; + self.niri.queue_redraw_all(); + // FIXME: apply output scale and whatnot. + // FIXME: apply libinput device settings. + // FIXME: apply xkb settings. + // FIXME: apply xdg decoration settings. + } } impl Niri { diff --git a/src/watcher.rs b/src/watcher.rs new file mode 100644 index 00000000..16e65b4d --- /dev/null +++ b/src/watcher.rs @@ -0,0 +1,60 @@ +//! File modification watcher. + +use std::path::PathBuf; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::thread; +use std::time::Duration; + +use smithay::reexports::calloop::channel::SyncSender; + +pub struct Watcher { + should_stop: Arc<AtomicBool>, +} + +impl Drop for Watcher { + fn drop(&mut self) { + self.should_stop.store(true, Ordering::SeqCst); + } +} + +impl Watcher { + pub fn new(path: PathBuf, changed: SyncSender<()>) -> Self { + let should_stop = Arc::new(AtomicBool::new(false)); + + { + let should_stop = should_stop.clone(); + thread::Builder::new() + .name(format!("Filesystem Watcher for {}", path.to_string_lossy())) + .spawn(move || { + let mut last_mtime = path.metadata().and_then(|meta| meta.modified()).ok(); + + loop { + thread::sleep(Duration::from_millis(500)); + + if should_stop.load(Ordering::SeqCst) { + break; + } + + if let Ok(mtime) = path.metadata().and_then(|meta| meta.modified()) { + if last_mtime != Some(mtime) { + trace!("file changed: {}", path.to_string_lossy()); + + if let Err(err) = changed.send(()) { + warn!("error sending change notification: {err:?}"); + break; + } + + last_mtime = Some(mtime); + } + } + } + + debug!("exiting watcher thread for {}", path.to_string_lossy()); + }) + .unwrap(); + } + + Self { should_stop } + } +} |
