Add eww reload command

This commit is contained in:
elkowar 2021-01-21 21:47:40 +01:00
parent 8530f90a7c
commit 47863a3e77
4 changed files with 58 additions and 22 deletions

View file

@ -11,7 +11,7 @@ use debug_stub_derive::*;
use gdk::WindowExt; use gdk::WindowExt;
use gtk::{ContainerExt, CssProviderExt, GtkWindowExt, StyleContextExt, WidgetExt}; use gtk::{ContainerExt, CssProviderExt, GtkWindowExt, StyleContextExt, WidgetExt};
use itertools::Itertools; use itertools::Itertools;
use std::collections::HashMap; use std::{collections::HashMap, path::PathBuf};
use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::UnboundedSender;
/// Response that the app may send as a response to a event. /// Response that the app may send as a response to a event.
@ -42,8 +42,9 @@ pub type DaemonResponseReceiver = tokio::sync::mpsc::UnboundedReceiver<DaemonRes
pub enum DaemonCommand { pub enum DaemonCommand {
NoOp, NoOp,
UpdateVars(Vec<(VarName, PrimitiveValue)>), UpdateVars(Vec<(VarName, PrimitiveValue)>),
ReloadConfig(config::EwwConfig), ReloadConfigAndCss(DaemonResponseSender),
ReloadCss(String), UpdateConfig(config::EwwConfig),
UpdateCss(String),
OpenMany { OpenMany {
windows: Vec<WindowName>, windows: Vec<WindowName>,
sender: DaemonResponseSender, sender: DaemonResponseSender,
@ -83,11 +84,16 @@ impl EwwWindow {
pub struct App { pub struct App {
pub eww_state: eww_state::EwwState, pub eww_state: eww_state::EwwState,
pub eww_config: config::EwwConfig, pub eww_config: config::EwwConfig,
pub windows: HashMap<WindowName, EwwWindow>, pub open_windows: HashMap<WindowName, EwwWindow>,
pub css_provider: gtk::CssProvider, pub css_provider: gtk::CssProvider,
#[debug_stub = "ScriptVarHandler(...)"]
pub app_evt_send: UnboundedSender<DaemonCommand>, pub app_evt_send: UnboundedSender<DaemonCommand>,
#[debug_stub = "ScriptVarHandler(...)"] #[debug_stub = "ScriptVarHandler(...)"]
pub script_var_handler: ScriptVarHandlerHandle, pub script_var_handler: ScriptVarHandlerHandle,
pub config_file_path: PathBuf,
pub scss_file_path: PathBuf,
} }
impl App { impl App {
@ -102,10 +108,32 @@ impl App {
self.update_state(var_name, new_value)?; self.update_state(var_name, new_value)?;
} }
} }
DaemonCommand::ReloadConfig(config) => { DaemonCommand::ReloadConfigAndCss(sender) => {
self.reload_all_windows(config)?; 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)?; self.load_css(&css)?;
} }
DaemonCommand::KillServer => { DaemonCommand::KillServer => {
@ -115,7 +143,7 @@ impl App {
} }
DaemonCommand::CloseAll => { DaemonCommand::CloseAll => {
log::info!("Received close command, closing all windows"); 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)?; self.close_window(&window_name)?;
} }
} }
@ -157,7 +185,7 @@ impl App {
.get_windows() .get_windows()
.keys() .keys()
.map(|window_name| { .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) format!("{}{}", if is_open { "*" } else { "" }, window_name)
}) })
.join("\n"); .join("\n");
@ -179,7 +207,7 @@ impl App {
fn stop_application(&mut self) { fn stop_application(&mut self) {
self.script_var_handler.stop_all(); 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(); gtk::main_quit();
} }
@ -194,7 +222,7 @@ impl App {
} }
let window = self let window = self
.windows .open_windows
.remove(window_name) .remove(window_name)
.context(format!("No window with name '{}' is running.", 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 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)?; 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. // initialize script var handlers for variables that where not used before opening this window.
// TODO somehow make this less shit // TODO somehow make this less shit
@ -245,7 +273,8 @@ impl App {
Ok(()) 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"); log::info!("Reloading windows");
// refresh script-var poll stuff // refresh script-var poll stuff
self.script_var_handler.stop_all(); self.script_var_handler.stop_all();
@ -253,7 +282,7 @@ impl App {
self.eww_config = config; self.eww_config = config;
self.eww_state.clear_all_window_states(); self.eww_state.clear_all_window_states();
let windows = self.windows.clone(); let windows = self.open_windows.clone();
for (window_name, window) in windows { for (window_name, window) in windows {
window.close(); window.close();
self.open_window(&window_name, None, None, None)?; 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. /// Get all variable names that are currently referenced in any of the open windows.
pub fn get_currently_used_variables(&self) -> impl Iterator<Item = &VarName> { pub fn get_currently_used_variables(&self) -> impl Iterator<Item = &VarName> {
self.windows self.open_windows
.keys() .keys()
.flat_map(move |window_name| self.eww_state.vars_referenced_in(window_name)) .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. /// 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>> { pub fn currently_used_variables<'a>(&'a self) -> HashMap<&'a VarName, Vec<&'a WindowName>> {
let mut vars: HashMap<&'a VarName, Vec<_>> = HashMap::new(); 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) { for var in self.eww_state.vars_referenced_in(window_name) {
vars.entry(var) vars.entry(var)
.and_modify(|l| l.push(window_name)) .and_modify(|l| l.push(window_name))

View file

@ -39,7 +39,7 @@ impl EwwConfig {
pub fn read_from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self> { pub fn read_from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
let result: Result<_> = try { let result: Result<_> = try {
let content = util::replace_env_var_references(std::fs::read_to_string(path.as_ref())?); 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_node = XmlNode::from(document.root_element());
let root_element = root_node.as_element()?; let root_element = root_node.as_element()?;
EwwConfig::from_xml_element(root_element.clone(), path.as_ref())? EwwConfig::from_xml_element(root_element.clone(), path.as_ref())?

View file

@ -87,6 +87,10 @@ pub enum ActionWithServer {
#[structopt(name = "close")] #[structopt(name = "close")]
CloseWindow { window_name: WindowName }, CloseWindow { window_name: WindowName },
/// Reload the configuration
#[structopt(name = "reload")]
Reload,
/// kill the eww daemon /// kill the eww daemon
#[structopt(name = "kill")] #[structopt(name = "kill")]
KillServer, KillServer,
@ -164,6 +168,7 @@ impl ActionWithServer {
ActionWithServer::CloseWindow { window_name } => { ActionWithServer::CloseWindow { window_name } => {
return with_response_channel(|sender| app::DaemonCommand::CloseWindow { window_name, sender }); 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::ShowWindows => return with_response_channel(app::DaemonCommand::PrintWindows),
ActionWithServer::ShowState => return with_response_channel(app::DaemonCommand::PrintState), ActionWithServer::ShowState => return with_response_channel(app::DaemonCommand::PrintState),
ActionWithServer::ShowDebug => return with_response_channel(app::DaemonCommand::PrintDebug), ActionWithServer::ShowDebug => return with_response_channel(app::DaemonCommand::PrintDebug),

View file

@ -38,22 +38,24 @@ pub fn initialize_server() -> Result<()> {
let mut app = app::App { let mut app = app::App {
eww_state: EwwState::from_default_vars(eww_config.generate_initial_state()?), eww_state: EwwState::from_default_vars(eww_config.generate_initial_state()?),
eww_config, eww_config,
windows: HashMap::new(), open_windows: HashMap::new(),
css_provider: gtk::CssProvider::new(), css_provider: gtk::CssProvider::new(),
script_var_handler, script_var_handler,
app_evt_send: ui_send.clone(), app_evt_send: ui_send.clone(),
config_file_path,
scss_file_path,
}; };
if let Some(screen) = gdk::Screen::get_default() { if let Some(screen) = gdk::Screen::get_default() {
gtk::StyleContext::add_provider_for_screen(&screen, &app.css_provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION); 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)?; app.load_css(&eww_css)?;
} }
// initialize all the handlers and tasks running asyncronously // 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 { glib::MainContext::default().spawn_local(async move {
while let Some(event) = ui_recv.recv().await { while let Some(event) = ui_recv.recv().await {
@ -127,11 +129,11 @@ async fn run_filewatch<P: AsRef<Path>>(
if event.wd == config_file_descriptor { if event.wd == config_file_descriptor {
log::info!("Reloading eww configuration"); log::info!("Reloading eww configuration");
let new_eww_config = config::EwwConfig::read_from_file(config_file_path.as_ref())?; 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 { } else if event.wd == scss_file_descriptor {
log::info!("reloading eww css file"); log::info!("reloading eww css file");
let eww_css = crate::util::parse_scss_from_file(scss_file_path.as_ref())?; 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 { } else {
eprintln!("Got inotify event for unknown thing: {:?}", event); eprintln!("Got inotify event for unknown thing: {:?}", event);
} }