mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-24 02:01:18 +07:00
Add the LoadConfigFile action (#2163)
* Add the `LoadConfigFile` action * fixes --------- Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
This commit is contained in:
@@ -1924,6 +1924,8 @@ pub enum Action {
|
||||
SetWindowUrgent(u64),
|
||||
#[knuffel(skip)]
|
||||
UnsetWindowUrgent(u64),
|
||||
#[knuffel(skip)]
|
||||
LoadConfigFile,
|
||||
}
|
||||
|
||||
impl From<niri_ipc::Action> for Action {
|
||||
@@ -2199,6 +2201,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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -840,6 +840,11 @@ pub enum Action {
|
||||
#[cfg_attr(feature = "clap", arg(long))]
|
||||
id: u64,
|
||||
},
|
||||
/// Reload the config file.
|
||||
///
|
||||
/// 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 {},
|
||||
}
|
||||
|
||||
/// Change in window or column size.
|
||||
|
||||
@@ -2113,6 +2113,11 @@ impl State {
|
||||
}
|
||||
self.niri.queue_redraw_all();
|
||||
}
|
||||
Action::LoadConfigFile => {
|
||||
if let Some(watcher) = &self.niri.config_file_watcher {
|
||||
watcher.load_config();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-23
@@ -23,8 +23,7 @@ use niri::utils::spawning::{
|
||||
spawn, store_and_increase_nofile_rlimit, CHILD_DISPLAY, CHILD_ENV, REMOVE_ENV_RUST_BACKTRACE,
|
||||
REMOVE_ENV_RUST_LIB_BACKTRACE,
|
||||
};
|
||||
use niri::utils::watcher::Watcher;
|
||||
use niri::utils::{cause_panic, version, xwayland, IS_SYSTEMD_SERVICE};
|
||||
use niri::utils::{cause_panic, version, watcher, xwayland, IS_SYSTEMD_SERVICE};
|
||||
use niri_config::ConfigPath;
|
||||
use niri_ipc::socket::SOCKET_PATH_ENV;
|
||||
use portable_atomic::Ordering;
|
||||
@@ -230,27 +229,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
}
|
||||
|
||||
// Set up config file watcher.
|
||||
let _watcher = {
|
||||
// Parsing the config actually takes > 20 ms on my beefy machine, so let's do it on the
|
||||
// watcher thread.
|
||||
let process = |path: &ConfigPath| {
|
||||
path.load().map_err(|err| {
|
||||
warn!("{err:?}");
|
||||
})
|
||||
};
|
||||
|
||||
let (tx, rx) = calloop::channel::sync_channel(1);
|
||||
let watcher = Watcher::new(config_path.clone(), process, tx);
|
||||
event_loop
|
||||
.handle()
|
||||
.insert_source(rx, |event, _, state| match event {
|
||||
calloop::channel::Event::Msg(config) => state.reload_config(config),
|
||||
calloop::channel::Event::Closed => (),
|
||||
})
|
||||
.unwrap();
|
||||
watcher
|
||||
};
|
||||
watcher::setup(&mut state, &config_path);
|
||||
|
||||
// Spawn commands from cli and auto-start.
|
||||
spawn(cli.command, None);
|
||||
|
||||
@@ -164,6 +164,7 @@ use crate::ui::screen_transition::{self, ScreenTransition};
|
||||
use crate::ui::screenshot_ui::{OutputScreenshot, ScreenshotUi, ScreenshotUiRenderElement};
|
||||
use crate::utils::scale::{closest_representable_scale, guess_monitor_scale};
|
||||
use crate::utils::spawning::{CHILD_DISPLAY, CHILD_ENV};
|
||||
use crate::utils::watcher::Watcher;
|
||||
use crate::utils::xwayland::satellite::Satellite;
|
||||
use crate::utils::{
|
||||
center, center_f64, expand_home, get_monotonic_time, ipc_transform_to_smithay, is_mapped,
|
||||
@@ -190,6 +191,8 @@ pub struct Niri {
|
||||
/// (and transient changes dropped).
|
||||
pub config_file_output_config: niri_config::Outputs,
|
||||
|
||||
pub config_file_watcher: Option<Watcher>,
|
||||
|
||||
pub event_loop: LoopHandle<'static, State>,
|
||||
pub scheduler: Scheduler<()>,
|
||||
pub stop_signal: LoopSignal,
|
||||
@@ -2528,6 +2531,7 @@ impl Niri {
|
||||
let mut niri = Self {
|
||||
config,
|
||||
config_file_output_config,
|
||||
config_file_watcher: None,
|
||||
|
||||
event_loop,
|
||||
scheduler,
|
||||
|
||||
+40
-20
@@ -1,22 +1,17 @@
|
||||
//! File modification watcher.
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{mpsc, Arc};
|
||||
use std::sync::mpsc;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::{io, thread};
|
||||
|
||||
use niri_config::ConfigPath;
|
||||
use smithay::reexports::calloop::channel::SyncSender;
|
||||
|
||||
pub struct Watcher {
|
||||
should_stop: Arc<AtomicBool>,
|
||||
}
|
||||
use crate::niri::State;
|
||||
|
||||
impl Drop for Watcher {
|
||||
fn drop(&mut self) {
|
||||
self.should_stop.store(true, Ordering::SeqCst);
|
||||
}
|
||||
pub struct Watcher {
|
||||
load_config: mpsc::Sender<()>,
|
||||
}
|
||||
|
||||
impl Watcher {
|
||||
@@ -36,10 +31,8 @@ impl Watcher {
|
||||
started: Option<mpsc::SyncSender<()>>,
|
||||
polling_interval: Duration,
|
||||
) -> Self {
|
||||
let should_stop = Arc::new(AtomicBool::new(false));
|
||||
let (load_config, load_config_rx) = mpsc::channel();
|
||||
|
||||
{
|
||||
let should_stop = should_stop.clone();
|
||||
thread::Builder::new()
|
||||
.name(format!("Filesystem Watcher for {config_path:?}"))
|
||||
.spawn(move || {
|
||||
@@ -80,24 +73,26 @@ impl Watcher {
|
||||
}
|
||||
|
||||
loop {
|
||||
thread::sleep(polling_interval);
|
||||
|
||||
if should_stop.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
let mut should_load = match load_config_rx.recv_timeout(polling_interval) {
|
||||
Ok(()) => true,
|
||||
Err(mpsc::RecvTimeoutError::Disconnected) => break,
|
||||
Err(mpsc::RecvTimeoutError::Timeout) => false,
|
||||
};
|
||||
|
||||
if let Ok(new_props) = see(&config_path) {
|
||||
if last_props.as_ref() != Some(&new_props) {
|
||||
last_props = Some(new_props);
|
||||
trace!("config file changed");
|
||||
should_load = true;
|
||||
}
|
||||
|
||||
if should_load {
|
||||
let rv = process(&config_path);
|
||||
|
||||
if let Err(err) = changed.send(rv) {
|
||||
warn!("error sending change notification: {err:?}");
|
||||
break;
|
||||
}
|
||||
|
||||
last_props = Some(new_props);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,12 +100,37 @@ impl Watcher {
|
||||
debug!("exiting watcher thread for {config_path:?}");
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
Self { load_config }
|
||||
}
|
||||
|
||||
Self { should_stop }
|
||||
pub fn load_config(&self) {
|
||||
let _ = self.load_config.send(());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup(state: &mut State, config_path: &ConfigPath) {
|
||||
// Parsing the config actually takes > 20 ms on my beefy machine, so let's do it on the
|
||||
// watcher thread.
|
||||
let process = |path: &ConfigPath| {
|
||||
path.load().map_err(|err| {
|
||||
warn!("{err:?}");
|
||||
})
|
||||
};
|
||||
|
||||
let (tx, rx) = calloop::channel::sync_channel(1);
|
||||
state
|
||||
.niri
|
||||
.event_loop
|
||||
.insert_source(rx, |event, _, state| match event {
|
||||
calloop::channel::Event::Msg(config) => state.reload_config(config),
|
||||
calloop::channel::Event::Closed => (),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
state.niri.config_file_watcher = Some(Watcher::new(config_path.clone(), process, tx));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::error::Error;
|
||||
|
||||
Reference in New Issue
Block a user