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 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<DaemonRes
pub enum DaemonCommand {
NoOp,
UpdateVars(Vec<(VarName, PrimitiveValue)>),
ReloadConfig(config::EwwConfig),
ReloadCss(String),
ReloadConfigAndCss(DaemonResponseSender),
UpdateConfig(config::EwwConfig),
UpdateCss(String),
OpenMany {
windows: Vec<WindowName>,
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<WindowName, EwwWindow>,
pub open_windows: HashMap<WindowName, EwwWindow>,
pub css_provider: gtk::CssProvider,
#[debug_stub = "ScriptVarHandler(...)"]
pub app_evt_send: UnboundedSender<DaemonCommand>,
#[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<Item = &VarName> {
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))

View file

@ -39,7 +39,7 @@ impl EwwConfig {
pub fn read_from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
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())?

View file

@ -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),

View file

@ -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<P: AsRef<Path>>(
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);
}