Add eww reload command
This commit is contained in:
parent
8530f90a7c
commit
47863a3e77
4 changed files with 58 additions and 22 deletions
61
src/app.rs
61
src/app.rs
|
@ -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),
|
||||||
}
|
}
|
||||||
DaemonCommand::ReloadCss(css) => {
|
|
||||||
|
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::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))
|
||||||
|
|
|
@ -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())?
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue