From 47863a3e7736974712e1c8782072e7a8916c8f48 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Thu, 21 Jan 2021 21:47:40 +0100 Subject: [PATCH] Add eww reload command --- src/app.rs | 61 +++++++++++++++++++++++++++++----------- src/config/eww_config.rs | 2 +- src/opts.rs | 5 ++++ src/server.rs | 12 ++++---- 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/app.rs b/src/app.rs index 2e9bff4..4c930ba 100644 --- a/src/app.rs +++ b/src/app.rs @@ -11,7 +11,7 @@ use debug_stub_derive::*; use gdk::WindowExt; use gtk::{ContainerExt, CssProviderExt, GtkWindowExt, StyleContextExt, WidgetExt}; use itertools::Itertools; -use std::collections::HashMap; +use std::{collections::HashMap, path::PathBuf}; use tokio::sync::mpsc::UnboundedSender; /// Response that the app may send as a response to a event. @@ -42,8 +42,9 @@ pub type DaemonResponseReceiver = tokio::sync::mpsc::UnboundedReceiver), - ReloadConfig(config::EwwConfig), - ReloadCss(String), + ReloadConfigAndCss(DaemonResponseSender), + UpdateConfig(config::EwwConfig), + UpdateCss(String), OpenMany { windows: Vec, sender: DaemonResponseSender, @@ -83,11 +84,16 @@ impl EwwWindow { pub struct App { pub eww_state: eww_state::EwwState, pub eww_config: config::EwwConfig, - pub windows: HashMap, + pub open_windows: HashMap, pub css_provider: gtk::CssProvider, + + #[debug_stub = "ScriptVarHandler(...)"] pub app_evt_send: UnboundedSender, #[debug_stub = "ScriptVarHandler(...)"] pub script_var_handler: ScriptVarHandlerHandle, + + pub config_file_path: PathBuf, + pub scss_file_path: PathBuf, } impl App { @@ -102,10 +108,32 @@ impl App { self.update_state(var_name, new_value)?; } } - DaemonCommand::ReloadConfig(config) => { - self.reload_all_windows(config)?; + DaemonCommand::ReloadConfigAndCss(sender) => { + let mut errors = Vec::new(); + + let config_result = config::EwwConfig::read_from_file(&self.config_file_path); + match config_result { + Ok(new_config) => self.handle_command(DaemonCommand::UpdateConfig(new_config)), + Err(e) => errors.push(e), + } + + let css_result = crate::util::parse_scss_from_file(&self.scss_file_path); + match css_result { + Ok(new_css) => self.handle_command(DaemonCommand::UpdateCss(new_css)), + Err(e) => errors.push(e), + } + + let errors = errors.into_iter().map(|e| format!("{:?}", e)).join("\n"); + if errors.is_empty() { + sender.send(DaemonResponse::Success(String::new()))?; + } else { + sender.send(DaemonResponse::Failure(errors))?; + } } - DaemonCommand::ReloadCss(css) => { + DaemonCommand::UpdateConfig(config) => { + self.load_config(config)?; + } + DaemonCommand::UpdateCss(css) => { self.load_css(&css)?; } DaemonCommand::KillServer => { @@ -115,7 +143,7 @@ impl App { } DaemonCommand::CloseAll => { log::info!("Received close command, closing all windows"); - for (window_name, _window) in self.windows.clone() { + for (window_name, _window) in self.open_windows.clone() { self.close_window(&window_name)?; } } @@ -157,7 +185,7 @@ impl App { .get_windows() .keys() .map(|window_name| { - let is_open = self.windows.contains_key(window_name); + let is_open = self.open_windows.contains_key(window_name); format!("{}{}", if is_open { "*" } else { "" }, window_name) }) .join("\n"); @@ -179,7 +207,7 @@ impl App { fn stop_application(&mut self) { self.script_var_handler.stop_all(); - self.windows.drain().for_each(|(_, w)| w.close()); + self.open_windows.drain().for_each(|(_, w)| w.close()); gtk::main_quit(); } @@ -194,7 +222,7 @@ impl App { } let window = self - .windows + .open_windows .remove(window_name) .context(format!("No window with name '{}' is running.", window_name))?; @@ -231,7 +259,7 @@ impl App { let monitor_geometry = get_monitor_geometry(window_def.screen_number.unwrap_or_else(get_default_monitor_index)); let eww_window = initialize_window(monitor_geometry, root_widget, window_def)?; - self.windows.insert(window_name.clone(), eww_window); + self.open_windows.insert(window_name.clone(), eww_window); // initialize script var handlers for variables that where not used before opening this window. // TODO somehow make this less shit @@ -245,7 +273,8 @@ impl App { Ok(()) } - pub fn reload_all_windows(&mut self, config: config::EwwConfig) -> Result<()> { + /// Load the given configuration, reloading all script-vars and reopening all windows that where opened. + pub fn load_config(&mut self, config: config::EwwConfig) -> Result<()> { log::info!("Reloading windows"); // refresh script-var poll stuff self.script_var_handler.stop_all(); @@ -253,7 +282,7 @@ impl App { self.eww_config = config; self.eww_state.clear_all_window_states(); - let windows = self.windows.clone(); + let windows = self.open_windows.clone(); for (window_name, window) in windows { window.close(); self.open_window(&window_name, None, None, None)?; @@ -268,7 +297,7 @@ impl App { /// Get all variable names that are currently referenced in any of the open windows. pub fn get_currently_used_variables(&self) -> impl Iterator { - self.windows + self.open_windows .keys() .flat_map(move |window_name| self.eww_state.vars_referenced_in(window_name)) } @@ -276,7 +305,7 @@ impl App { /// Get all variables mapped to a list of windows they are being used in. pub fn currently_used_variables<'a>(&'a self) -> HashMap<&'a VarName, Vec<&'a WindowName>> { let mut vars: HashMap<&'a VarName, Vec<_>> = HashMap::new(); - for window_name in self.windows.keys() { + for window_name in self.open_windows.keys() { for var in self.eww_state.vars_referenced_in(window_name) { vars.entry(var) .and_modify(|l| l.push(window_name)) diff --git a/src/config/eww_config.rs b/src/config/eww_config.rs index 8fb1a7d..720bb0f 100644 --- a/src/config/eww_config.rs +++ b/src/config/eww_config.rs @@ -39,7 +39,7 @@ impl EwwConfig { pub fn read_from_file>(path: P) -> Result { let result: Result<_> = try { let content = util::replace_env_var_references(std::fs::read_to_string(path.as_ref())?); - let document = roxmltree::Document::parse(&content).map_err(|e| anyhow!("Failed to parse eww xml: {:?}", e))?; + let document = roxmltree::Document::parse(&content).map_err(|e| anyhow!(e))?; let root_node = XmlNode::from(document.root_element()); let root_element = root_node.as_element()?; EwwConfig::from_xml_element(root_element.clone(), path.as_ref())? diff --git a/src/opts.rs b/src/opts.rs index bd17950..13f3bcd 100644 --- a/src/opts.rs +++ b/src/opts.rs @@ -87,6 +87,10 @@ pub enum ActionWithServer { #[structopt(name = "close")] CloseWindow { window_name: WindowName }, + /// Reload the configuration + #[structopt(name = "reload")] + Reload, + /// kill the eww daemon #[structopt(name = "kill")] KillServer, @@ -164,6 +168,7 @@ impl ActionWithServer { ActionWithServer::CloseWindow { window_name } => { return with_response_channel(|sender| app::DaemonCommand::CloseWindow { window_name, sender }); } + ActionWithServer::Reload => return with_response_channel(app::DaemonCommand::ReloadConfigAndCss), ActionWithServer::ShowWindows => return with_response_channel(app::DaemonCommand::PrintWindows), ActionWithServer::ShowState => return with_response_channel(app::DaemonCommand::PrintState), ActionWithServer::ShowDebug => return with_response_channel(app::DaemonCommand::PrintDebug), diff --git a/src/server.rs b/src/server.rs index a1b454a..0da204f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -38,22 +38,24 @@ pub fn initialize_server() -> Result<()> { let mut app = app::App { eww_state: EwwState::from_default_vars(eww_config.generate_initial_state()?), eww_config, - windows: HashMap::new(), + open_windows: HashMap::new(), css_provider: gtk::CssProvider::new(), script_var_handler, app_evt_send: ui_send.clone(), + config_file_path, + scss_file_path, }; if let Some(screen) = gdk::Screen::get_default() { gtk::StyleContext::add_provider_for_screen(&screen, &app.css_provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION); } - if let Ok(eww_css) = util::parse_scss_from_file(&scss_file_path) { + if let Ok(eww_css) = util::parse_scss_from_file(&app.scss_file_path) { app.load_css(&eww_css)?; } // initialize all the handlers and tasks running asyncronously - init_async_part(config_file_path, scss_file_path, ui_send); + init_async_part(app.config_file_path.clone(), app.scss_file_path.clone(), ui_send); glib::MainContext::default().spawn_local(async move { while let Some(event) = ui_recv.recv().await { @@ -127,11 +129,11 @@ async fn run_filewatch>( if event.wd == config_file_descriptor { log::info!("Reloading eww configuration"); let new_eww_config = config::EwwConfig::read_from_file(config_file_path.as_ref())?; - evt_send.send(app::DaemonCommand::ReloadConfig(new_eww_config))?; + evt_send.send(app::DaemonCommand::UpdateConfig(new_eww_config))?; } else if event.wd == scss_file_descriptor { log::info!("reloading eww css file"); let eww_css = crate::util::parse_scss_from_file(scss_file_path.as_ref())?; - evt_send.send(app::DaemonCommand::ReloadCss(eww_css))?; + evt_send.send(app::DaemonCommand::UpdateCss(eww_css))?; } else { eprintln!("Got inotify event for unknown thing: {:?}", event); }