Add initial config hot reloading

This commit is contained in:
Ivan Molodetskikh
2023-09-26 19:24:50 +04:00
parent 3b83b2fb16
commit 4a585a3293
4 changed files with 103 additions and 6 deletions
+2 -2
View File
@@ -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> {
+22 -4
View File
@@ -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);
+19
View File
@@ -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 {
+60
View File
@@ -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 }
}
}