Handle application exit somewhat nicely
This commit is contained in:
parent
b4880a55b8
commit
b9b8a77cf4
5 changed files with 170 additions and 190 deletions
15
src/app.rs
15
src/app.rs
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
config,
|
||||
application_lifecycle, config,
|
||||
config::{window_definition::WindowName, AnchorPoint, WindowStacking},
|
||||
eww_state,
|
||||
script_var_handler::*,
|
||||
|
|
@ -60,6 +60,7 @@ pub struct App {
|
|||
}
|
||||
|
||||
impl App {
|
||||
/// Handle an EwwCommand event.
|
||||
pub fn handle_command(&mut self, event: EwwCommand) {
|
||||
log::debug!("Handling event: {:?}", &event);
|
||||
let result: Result<_> = try {
|
||||
|
|
@ -78,10 +79,8 @@ impl App {
|
|||
}
|
||||
EwwCommand::KillServer => {
|
||||
log::info!("Received kill command, stopping server!");
|
||||
self.script_var_handler.stop_all();
|
||||
self.windows.drain().for_each(|(_, w)| w.close());
|
||||
// script_var_process::on_application_death();
|
||||
std::process::exit(0);
|
||||
self.stop_application();
|
||||
crate::application_lifecycle::send_exit()?;
|
||||
}
|
||||
EwwCommand::CloseAll => {
|
||||
log::info!("Received close command, closing all windows");
|
||||
|
|
@ -119,6 +118,12 @@ impl App {
|
|||
crate::print_result_err!("while handling event", &result);
|
||||
}
|
||||
|
||||
fn stop_application(&mut self) {
|
||||
self.script_var_handler.stop_all();
|
||||
self.windows.drain().for_each(|(_, w)| w.close());
|
||||
gtk::main_quit();
|
||||
}
|
||||
|
||||
fn update_state(&mut self, fieldname: VarName, value: PrimitiveValue) -> Result<()> {
|
||||
self.eww_state.update_variable(fieldname, value)
|
||||
}
|
||||
|
|
|
|||
43
src/application_lifecycle.rs
Normal file
43
src/application_lifecycle.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
//! Module concerned with handling the global application lifecycle of eww.
|
||||
//! Currently, this only means handling application exit by providing a global
|
||||
//! `recv_exit()` function which can be awaited to receive an event in case of application termination.
|
||||
|
||||
use anyhow::*;
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref APPLICATION_EXIT_SENDER: broadcast::Sender<()> = broadcast::channel(2).0;
|
||||
}
|
||||
|
||||
/// Notify all listening tasks of the termination of the eww application process.
|
||||
pub fn send_exit() -> Result<()> {
|
||||
(&*APPLICATION_EXIT_SENDER)
|
||||
.send(())
|
||||
.context("Failed to send exit lifecycle event")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Yields Ok(()) on application termination. Await on this in all long-running tasks
|
||||
/// and perform any cleanup if necessary.
|
||||
pub async fn recv_exit() -> Result<()> {
|
||||
(&*APPLICATION_EXIT_SENDER)
|
||||
.subscribe()
|
||||
.recv()
|
||||
.await
|
||||
.context("Failed to receive lifecycle event")
|
||||
}
|
||||
|
||||
/// Select in a loop, breaking once a application termination event (see `crate::application_lifecycle`) is received.
|
||||
#[macro_export]
|
||||
macro_rules! loop_select_exiting {
|
||||
($($content:tt)*) => {
|
||||
loop {
|
||||
tokio::select! {
|
||||
Ok(()) = crate::application_lifecycle::recv_exit() => {
|
||||
break;
|
||||
}
|
||||
$($content)*
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ use anyhow::*;
|
|||
use std::{os::unix::net, path::PathBuf};
|
||||
|
||||
pub mod app;
|
||||
pub mod application_lifecycle;
|
||||
pub mod client;
|
||||
pub mod config;
|
||||
pub mod eww_state;
|
||||
|
|
|
|||
|
|
@ -13,37 +13,8 @@ use tokio::{
|
|||
};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
enum ScriptVarHandlerMsg {
|
||||
AddVar(config::ScriptVar),
|
||||
Stop(VarName),
|
||||
StopAll,
|
||||
}
|
||||
|
||||
pub struct ScriptVarHandlerHandle {
|
||||
msg_send: UnboundedSender<ScriptVarHandlerMsg>,
|
||||
}
|
||||
|
||||
impl ScriptVarHandlerHandle {
|
||||
pub fn add(&self, script_var: config::ScriptVar) {
|
||||
self.msg_send.send(ScriptVarHandlerMsg::AddVar(script_var)).unwrap();
|
||||
}
|
||||
|
||||
pub fn stop_for_variable(&self, name: VarName) {
|
||||
self.msg_send.send(ScriptVarHandlerMsg::Stop(name)).unwrap();
|
||||
}
|
||||
|
||||
pub fn stop_all(&self) {
|
||||
self.msg_send.send(ScriptVarHandlerMsg::StopAll).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Handler that manages running and updating [ScriptVar]s
|
||||
struct ScriptVarHandler {
|
||||
tail_handler: TailVarHandler,
|
||||
poll_handler: PollVarHandler,
|
||||
}
|
||||
|
||||
/// Initialize the script var handler, and return a handle to that handler, which can be used to control
|
||||
/// the script var execution.
|
||||
pub fn init(evt_send: UnboundedSender<EwwCommand>) -> Result<ScriptVarHandlerHandle> {
|
||||
let (msg_send, mut msg_recv) = tokio::sync::mpsc::unbounded_channel();
|
||||
let handle = ScriptVarHandlerHandle { msg_send };
|
||||
|
|
@ -55,8 +26,8 @@ pub fn init(evt_send: UnboundedSender<EwwCommand>) -> Result<ScriptVarHandlerHan
|
|||
tail_handler: TailVarHandler::new(evt_send.clone())?,
|
||||
poll_handler: PollVarHandler::new(evt_send)?,
|
||||
};
|
||||
while let Some(msg) = msg_recv.recv().await {
|
||||
match msg {
|
||||
crate::loop_select_exiting! {
|
||||
Some(msg) = msg_recv.recv() => match msg {
|
||||
ScriptVarHandlerMsg::AddVar(var) => {
|
||||
handler.add(var).await;
|
||||
}
|
||||
|
|
@ -66,16 +37,53 @@ pub fn init(evt_send: UnboundedSender<EwwCommand>) -> Result<ScriptVarHandlerHan
|
|||
ScriptVarHandlerMsg::StopAll => {
|
||||
handler.stop_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
else => break,
|
||||
};
|
||||
};
|
||||
})
|
||||
});
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
/// Handle to the script-var handling system.
|
||||
pub struct ScriptVarHandlerHandle {
|
||||
msg_send: UnboundedSender<ScriptVarHandlerMsg>,
|
||||
}
|
||||
|
||||
impl ScriptVarHandlerHandle {
|
||||
/// Add a new script-var that should be executed.
|
||||
pub fn add(&self, script_var: config::ScriptVar) {
|
||||
self.msg_send.send(ScriptVarHandlerMsg::AddVar(script_var)).unwrap();
|
||||
}
|
||||
|
||||
/// Stop the execution of a specific script-var.
|
||||
pub fn stop_for_variable(&self, name: VarName) {
|
||||
self.msg_send.send(ScriptVarHandlerMsg::Stop(name)).unwrap();
|
||||
}
|
||||
|
||||
/// Stop the execution of all script-vars.
|
||||
pub fn stop_all(&self) {
|
||||
self.msg_send.send(ScriptVarHandlerMsg::StopAll).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Message enum used by the ScriptVarHandlerHandle to communicate to the ScriptVarHandler
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
enum ScriptVarHandlerMsg {
|
||||
AddVar(config::ScriptVar),
|
||||
Stop(VarName),
|
||||
StopAll,
|
||||
}
|
||||
|
||||
/// Handler that manages running and updating [ScriptVar]s
|
||||
struct ScriptVarHandler {
|
||||
tail_handler: TailVarHandler,
|
||||
poll_handler: PollVarHandler,
|
||||
}
|
||||
|
||||
impl ScriptVarHandler {
|
||||
pub async fn add(&mut self, script_var: config::ScriptVar) {
|
||||
async fn add(&mut self, script_var: config::ScriptVar) {
|
||||
match script_var {
|
||||
config::ScriptVar::Poll(var) => self.poll_handler.start(var).await,
|
||||
config::ScriptVar::Tail(var) => self.tail_handler.start(var).await,
|
||||
|
|
@ -83,27 +91,21 @@ impl ScriptVarHandler {
|
|||
}
|
||||
|
||||
/// Stop the handler that is responsible for a given variable.
|
||||
pub fn stop_for_variable(&mut self, name: &VarName) -> Result<()> {
|
||||
fn stop_for_variable(&mut self, name: &VarName) -> Result<()> {
|
||||
log::debug!("Stopping script var process for variable {}", name);
|
||||
self.tail_handler.stop_for_variable(name)?;
|
||||
self.poll_handler.stop_for_variable(name)?;
|
||||
self.tail_handler.stop_for_variable(name);
|
||||
self.poll_handler.stop_for_variable(name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// stop all running scripts and schedules
|
||||
pub fn stop_all(&mut self) {
|
||||
fn stop_all(&mut self) {
|
||||
log::debug!("Stopping script-var-handlers");
|
||||
self.tail_handler.stop_all();
|
||||
self.poll_handler.stop_all();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ScriptVarHandler {
|
||||
fn drop(&mut self) {
|
||||
self.stop_all();
|
||||
}
|
||||
}
|
||||
|
||||
struct PollVarHandler {
|
||||
evt_send: UnboundedSender<EwwCommand>,
|
||||
poll_handles: HashMap<VarName, CancellationToken>,
|
||||
|
|
@ -124,7 +126,7 @@ impl PollVarHandler {
|
|||
self.poll_handles.insert(var.name.clone(), cancellation_token.clone());
|
||||
let evt_send = self.evt_send.clone();
|
||||
tokio::spawn(async move {
|
||||
crate::loop_select! {
|
||||
crate::loop_select_exiting! {
|
||||
_ = cancellation_token.cancelled() => break,
|
||||
_ = tokio::time::sleep(var.interval) => {
|
||||
let result: Result<_> = try {
|
||||
|
|
@ -136,19 +138,24 @@ impl PollVarHandler {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn stop_for_variable(&mut self, name: &VarName) -> Result<()> {
|
||||
fn stop_for_variable(&mut self, name: &VarName) {
|
||||
if let Some(token) = self.poll_handles.remove(name) {
|
||||
log::debug!("stopped poll var {}", name);
|
||||
token.cancel()
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stop_all(&mut self) {
|
||||
fn stop_all(&mut self) {
|
||||
self.poll_handles.drain().for_each(|(_, token)| token.cancel());
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PollVarHandler {
|
||||
fn drop(&mut self) {
|
||||
self.stop_all();
|
||||
}
|
||||
}
|
||||
|
||||
struct TailVarHandler {
|
||||
evt_send: UnboundedSender<EwwCommand>,
|
||||
tail_process_handles: HashMap<VarName, CancellationToken>,
|
||||
|
|
@ -178,27 +185,24 @@ impl TailVarHandler {
|
|||
.spawn()
|
||||
.unwrap();
|
||||
let mut stdout_lines = BufReader::new(handle.stdout.take().unwrap()).lines();
|
||||
crate::loop_select! {
|
||||
crate::loop_select_exiting! {
|
||||
_ = handle.wait() => break,
|
||||
_ = cancellation_token.cancelled() => break,
|
||||
line = stdout_lines.next_line() => match line {
|
||||
Ok(Some(line)) => {
|
||||
let new_value = PrimitiveValue::from_string(line.to_owned());
|
||||
evt_send.send(EwwCommand::UpdateVars(vec![(var.name.to_owned(), new_value)])).unwrap();
|
||||
},
|
||||
Ok(None) => break,
|
||||
Err(_e) => break,
|
||||
Ok(Some(line)) = stdout_lines.next_line() => {
|
||||
let new_value = PrimitiveValue::from_string(line.to_owned());
|
||||
evt_send.send(EwwCommand::UpdateVars(vec![(var.name.to_owned(), new_value)])).unwrap();
|
||||
}
|
||||
else => break,
|
||||
}
|
||||
handle.kill().await.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
fn stop_for_variable(&mut self, name: &VarName) -> Result<()> {
|
||||
fn stop_for_variable(&mut self, name: &VarName) {
|
||||
if let Some(token) = self.tail_process_handles.remove(name) {
|
||||
log::debug!("stopped tail var {}", name);
|
||||
token.cancel();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stop_all(&mut self) {
|
||||
|
|
@ -206,97 +210,8 @@ impl TailVarHandler {
|
|||
}
|
||||
}
|
||||
|
||||
pub mod script_var_process {
|
||||
use anyhow::*;
|
||||
use nix::{
|
||||
sys::{signal, wait},
|
||||
unistd::Pid,
|
||||
};
|
||||
use std::{ffi::CString, io::BufReader, sync::Mutex};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref SCRIPT_VAR_CHILDREN: Mutex<Vec<u32>> = Mutex::new(Vec::new());
|
||||
}
|
||||
|
||||
fn terminate_pid(pid: u32) -> Result<()> {
|
||||
signal::kill(Pid::from_raw(pid as i32), signal::SIGTERM)?;
|
||||
wait::waitpid(Pid::from_raw(pid as i32), None)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This function should be called in the signal handler, killing all child processes.
|
||||
pub fn on_application_death() {
|
||||
SCRIPT_VAR_CHILDREN.lock().unwrap().drain(..).for_each(|pid| {
|
||||
let result = terminate_pid(pid);
|
||||
crate::print_result_err!("While killing process '{}' during cleanup", &result);
|
||||
});
|
||||
}
|
||||
|
||||
pub struct ScriptVarProcess {
|
||||
pub pid: i32,
|
||||
pub stdout_reader: BufReader<filedescriptor::FileDescriptor>,
|
||||
}
|
||||
|
||||
impl ScriptVarProcess {
|
||||
pub(super) fn run(command: &str) -> Result<Self> {
|
||||
use nix::unistd::*;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
let pipe = filedescriptor::Pipe::new()?;
|
||||
|
||||
match unsafe { fork()? } {
|
||||
ForkResult::Parent { child, .. } => {
|
||||
SCRIPT_VAR_CHILDREN.lock().unwrap().push(child.as_raw() as u32);
|
||||
|
||||
close(pipe.write.as_raw_fd())?;
|
||||
|
||||
Ok(ScriptVarProcess {
|
||||
stdout_reader: BufReader::new(pipe.read),
|
||||
pid: child.as_raw(),
|
||||
})
|
||||
}
|
||||
ForkResult::Child => {
|
||||
let _ = setpgid(Pid::from_raw(0), Pid::from_raw(0));
|
||||
match unsafe { fork()? } {
|
||||
ForkResult::Parent { .. } => {
|
||||
simple_signal::set_handler(&[simple_signal::Signal::Int, simple_signal::Signal::Term], |_| {
|
||||
let pgid = getpgid(Some(getpid())).unwrap();
|
||||
let _ = signal::killpg(pgid, nix::sys::signal::SIGKILL);
|
||||
while nix::sys::wait::wait().unwrap().pid().is_some() {}
|
||||
});
|
||||
loop {}
|
||||
}
|
||||
ForkResult::Child => {
|
||||
close(pipe.read.as_raw_fd()).unwrap();
|
||||
dup2(pipe.write.as_raw_fd(), std::io::stdout().as_raw_fd()).unwrap();
|
||||
dup2(pipe.write.as_raw_fd(), std::io::stderr().as_raw_fd()).unwrap();
|
||||
execv(
|
||||
CString::new("/bin/sh").unwrap().as_ref(),
|
||||
&[
|
||||
CString::new("/bin/sh").unwrap(),
|
||||
CString::new("-c").unwrap(),
|
||||
CString::new(command).unwrap(),
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
unreachable!(
|
||||
"Child fork called exec, thus the process was replaced by the command the user provided"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn kill(&self) -> Result<()> {
|
||||
SCRIPT_VAR_CHILDREN.lock().unwrap().retain(|item| *item != self.pid as u32);
|
||||
terminate_pid(self.pid as u32).context("Error manually killing tail-var script")
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ScriptVarProcess {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.kill();
|
||||
}
|
||||
impl Drop for TailVarHandler {
|
||||
fn drop(&mut self) {
|
||||
self.stop_all();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,10 +14,9 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) ->
|
|||
do_detach()?;
|
||||
}
|
||||
|
||||
simple_signal::set_handler(&[simple_signal::Signal::Int, simple_signal::Signal::Term], |_| {
|
||||
simple_signal::set_handler(&[simple_signal::Signal::Int, simple_signal::Signal::Term], move |_| {
|
||||
println!("Shutting down eww daemon...");
|
||||
// script_var_handler::script_var_process::on_application_death();
|
||||
std::process::exit(0);
|
||||
crate::application_lifecycle::send_exit().unwrap();
|
||||
});
|
||||
|
||||
let config_file_path = crate::CONFIG_DIR.join("eww.xml");
|
||||
|
|
@ -65,14 +64,8 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) ->
|
|||
.build()
|
||||
.expect("Failed to initialize tokio runtime");
|
||||
rt.block_on(async {
|
||||
let filewatch_join_handle = {
|
||||
let ui_send = ui_send.clone();
|
||||
tokio::spawn(async move { run_filewatch_thingy(config_file_path, scss_file_path, ui_send).await })
|
||||
};
|
||||
let ipc_server_join_handle = tokio::spawn(async move { async_server(ui_send.clone()).await });
|
||||
|
||||
// print out the response of this initial command, if there is any
|
||||
tokio::spawn(async {
|
||||
// print out the response of this initial command, if there is any
|
||||
if let Some(mut response_recv) = maybe_response_recv {
|
||||
if let Ok(Some(response)) = tokio::time::timeout(Duration::from_millis(100), response_recv.recv()).await {
|
||||
println!("{}", response);
|
||||
|
|
@ -80,7 +73,27 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) ->
|
|||
}
|
||||
});
|
||||
|
||||
let result = tokio::try_join!(filewatch_join_handle, ipc_server_join_handle);
|
||||
let filewatch_join_handle = {
|
||||
let ui_send = ui_send.clone();
|
||||
tokio::spawn(async move { run_filewatch_thingy(config_file_path, scss_file_path, ui_send).await })
|
||||
};
|
||||
|
||||
let ipc_server_join_handle = {
|
||||
let ui_send = ui_send.clone();
|
||||
tokio::spawn(async move { async_server(ui_send).await })
|
||||
};
|
||||
|
||||
let forward_lifecycle_to_app_handle = {
|
||||
let ui_send = ui_send.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(()) = crate::application_lifecycle::recv_exit().await {
|
||||
let _ = ui_send.send(app::EwwCommand::KillServer);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let result = tokio::try_join!(filewatch_join_handle, ipc_server_join_handle, forward_lifecycle_to_app_handle);
|
||||
|
||||
if let Err(e) = result {
|
||||
eprintln!("Eww exiting with error: {:?}", e);
|
||||
}
|
||||
|
|
@ -94,20 +107,20 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) ->
|
|||
});
|
||||
|
||||
gtk::main();
|
||||
log::info!("main application thread finished");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn async_server(evt_send: UnboundedSender<app::EwwCommand>) -> Result<()> {
|
||||
let listener = tokio::net::UnixListener::bind(&*crate::IPC_SOCKET_PATH)?;
|
||||
loop {
|
||||
tokio::select! {
|
||||
connection = listener.accept() => match connection {
|
||||
Ok((stream, _addr)) => handle_connection(stream, evt_send.clone()).await?,
|
||||
Err(e) => eprintln!("Failed to connect to client: {:?}", e),
|
||||
}
|
||||
crate::loop_select_exiting! {
|
||||
connection = listener.accept() => match connection {
|
||||
Ok((stream, _addr)) => handle_connection(stream, evt_send.clone()).await?,
|
||||
Err(e) => eprintln!("Failed to connect to client: {:?}", e),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_connection(mut stream: tokio::net::UnixStream, evt_send: UnboundedSender<app::EwwCommand>) -> Result<()> {
|
||||
|
|
@ -121,7 +134,6 @@ async fn handle_connection(mut stream: tokio::net::UnixStream, evt_send: Unbound
|
|||
|
||||
log::info!("received command from IPC: {:?}", &action);
|
||||
|
||||
// TODO clean up the maybe_response_recv
|
||||
let (command, maybe_response_recv) = action.into_eww_command();
|
||||
|
||||
evt_send.send(command)?;
|
||||
|
|
@ -152,22 +164,26 @@ async fn run_filewatch_thingy<P: AsRef<Path>>(
|
|||
|
||||
let mut buffer = [0; 1024];
|
||||
let mut event_stream = inotify.event_stream(&mut buffer)?;
|
||||
while let Some(Ok(event)) = event_stream.next().await {
|
||||
if event.wd == config_file_descriptor {
|
||||
try_logging_errors!("handling change of config file" => {
|
||||
log::info!("Reloading eww configuration");
|
||||
let new_eww_config = config::EwwConfig::read_from_file(config_file_path.as_ref())?;
|
||||
evt_send.send(app::EwwCommand::ReloadConfig(new_eww_config))?;
|
||||
});
|
||||
} else if event.wd == scss_file_descriptor {
|
||||
try_logging_errors!("handling change of scss file" => {
|
||||
log::info!("reloading eww css file");
|
||||
let eww_css = util::parse_scss_from_file(scss_file_path.as_ref())?;
|
||||
evt_send.send(app::EwwCommand::ReloadCss(eww_css))?;
|
||||
});
|
||||
} else {
|
||||
eprintln!("Got inotify event for unknown thing: {:?}", event);
|
||||
|
||||
crate::loop_select_exiting! {
|
||||
Some(Ok(event)) = event_stream.next() => {
|
||||
if event.wd == config_file_descriptor {
|
||||
try_logging_errors!("handling change of config file" => {
|
||||
log::info!("Reloading eww configuration");
|
||||
let new_eww_config = config::EwwConfig::read_from_file(config_file_path.as_ref())?;
|
||||
evt_send.send(app::EwwCommand::ReloadConfig(new_eww_config))?;
|
||||
});
|
||||
} else if event.wd == scss_file_descriptor {
|
||||
try_logging_errors!("handling change of scss file" => {
|
||||
log::info!("reloading eww css file");
|
||||
let eww_css = crate::util::parse_scss_from_file(scss_file_path.as_ref())?;
|
||||
evt_send.send(app::EwwCommand::ReloadCss(eww_css))?;
|
||||
});
|
||||
} else {
|
||||
eprintln!("Got inotify event for unknown thing: {:?}", event);
|
||||
}
|
||||
}
|
||||
else => break,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue