Implement command (fixes #9)

This commit is contained in:
elkowar 2020-10-17 16:41:08 +02:00
parent 3d07a84d1b
commit 0ea3d2255b
4 changed files with 80 additions and 41 deletions

View file

@ -1,12 +1,19 @@
use crate::config::WindowStacking; use crate::{
use crate::{config, script_var_handler::*, util, widgets}; config,
use crate::{config::WindowName, util::Coords, value::PrimitiveValue}; config::{WindowName, WindowStacking},
use crate::{eww_state, value::VarName}; eww_state,
script_var_handler::*,
util,
util::Coords,
value::{PrimitiveValue, VarName},
widgets,
};
use anyhow::*; use anyhow::*;
use crossbeam_channel::Sender; use crossbeam_channel;
use debug_stub_derive::*; 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 std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug)] #[derive(Debug)]
@ -23,7 +30,7 @@ pub enum EwwCommand {
window_name: WindowName, window_name: WindowName,
}, },
KillServer, KillServer,
PrintState, PrintState(crossbeam_channel::Sender<String>),
} }
#[derive(DebugStub)] #[derive(DebugStub)]
@ -38,7 +45,7 @@ pub struct App {
} }
impl App { impl App {
pub fn handle_command(&mut self, event: EwwCommand, response_sender: Option<Sender<String>>) { pub fn handle_command(&mut self, event: EwwCommand) {
log::debug!("Handling event: {:?}", &event); log::debug!("Handling event: {:?}", &event);
let result: Result<_> = match event { let result: Result<_> = match event {
EwwCommand::UpdateVar(key, value) => self.update_state(key, value), EwwCommand::UpdateVar(key, value) => self.update_state(key, value),
@ -50,16 +57,18 @@ impl App {
} }
EwwCommand::OpenWindow { window_name, pos, size } => self.open_window(&window_name, pos, size), EwwCommand::OpenWindow { window_name, pos, size } => self.open_window(&window_name, pos, size),
EwwCommand::CloseWindow { window_name } => self.close_window(&window_name), EwwCommand::CloseWindow { window_name } => self.close_window(&window_name),
EwwCommand::PrintState => Ok(()), EwwCommand::PrintState(sender) => {
let output = self
.eww_state
.get_variables()
.iter()
.map(|(key, value)| format!("{}: {}", key, value))
.join("\n");
sender.send(output).context("sending response from main thread")
}
}; };
if let Err(err) = result { util::print_result_err("while handling event", &result);
if let Some(response_sender) = response_sender {
let _ = response_sender.send(format!("Error while handling event: {:?}", err));
} else {
eprintln!("Error while handling event: {:?}", err);
}
}
} }
fn update_state(&mut self, fieldname: VarName, value: PrimitiveValue) -> Result<()> { fn update_state(&mut self, fieldname: VarName, value: PrimitiveValue) -> Result<()> {
@ -144,9 +153,10 @@ impl App {
pub fn reload_all_windows(&mut self, config: config::EwwConfig) -> Result<()> { pub fn reload_all_windows(&mut self, config: config::EwwConfig) -> Result<()> {
// refresh script-var poll stuff // refresh script-var poll stuff
if let Err(e) = self.script_var_handler.initialize_clean(config.get_script_vars().clone()) { util::print_result_err(
eprintln!("Error while setting up script-var commands: {:?}", e); "while setting up script-var commands",
} &self.script_var_handler.initialize_clean(config.get_script_vars().clone()),
);
self.eww_config = config; self.eww_config = config;
self.eww_state.clear_all_window_states(); self.eww_state.clear_all_window_states();

View file

@ -76,6 +76,10 @@ impl EwwState {
} }
} }
pub fn get_variables(&self) -> &HashMap<VarName, PrimitiveValue> {
&self.variables_state
}
/// remove all state stored specific to one window /// remove all state stored specific to one window
pub fn clear_window_state(&mut self, window_name: &WindowName) { pub fn clear_window_state(&mut self, window_name: &WindowName) {
self.windows.remove(window_name); self.windows.remove(window_name);

View file

@ -9,9 +9,6 @@ extern crate gtk;
use anyhow::*; use anyhow::*;
use eww_state::*; use eww_state::*;
use gdk::*;
use gtk::prelude::*;
use hotwatch;
use log; use log;
use pretty_env_logger; use pretty_env_logger;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -79,10 +76,10 @@ pub struct Opt {
} }
#[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)] #[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)]
pub enum OptAction { pub enum OptAction {
#[structopt(name = "update")] #[structopt(name = "update", help = "update the value of a variable")]
Update { fieldname: VarName, value: PrimitiveValue }, Update { fieldname: VarName, value: PrimitiveValue },
#[structopt(name = "open")] #[structopt(name = "open", help = "open a window")]
OpenWindow { OpenWindow {
window_name: config::WindowName, window_name: config::WindowName,
@ -93,24 +90,27 @@ pub enum OptAction {
size: Option<util::Coords>, size: Option<util::Coords>,
}, },
#[structopt(name = "close")] #[structopt(name = "close", help = "close the window with the given name")]
CloseWindow { window_name: config::WindowName }, CloseWindow { window_name: config::WindowName },
#[structopt(name = "kill")] #[structopt(name = "kill", help = "kill the eww daemon")]
KillServer, KillServer,
#[structopt(name = "state")] #[structopt(name = "state", help = "Print the current eww-state")]
ShowState, ShowState,
} }
impl Into<app::EwwCommand> for OptAction { impl OptAction {
fn into(self) -> app::EwwCommand { fn into_eww_command(self) -> (app::EwwCommand, Option<crossbeam_channel::Receiver<String>>) {
match self { match self {
OptAction::Update { fieldname, value } => app::EwwCommand::UpdateVar(fieldname, value), OptAction::Update { fieldname, value } => (app::EwwCommand::UpdateVar(fieldname, value), None),
OptAction::OpenWindow { window_name, pos, size } => app::EwwCommand::OpenWindow { window_name, pos, size }, OptAction::OpenWindow { window_name, pos, size } => (app::EwwCommand::OpenWindow { window_name, pos, size }, None),
OptAction::CloseWindow { window_name } => app::EwwCommand::CloseWindow { window_name }, OptAction::CloseWindow { window_name } => (app::EwwCommand::CloseWindow { window_name }, None),
OptAction::KillServer => app::EwwCommand::KillServer, OptAction::KillServer => (app::EwwCommand::KillServer, None),
OptAction::ShowState => unimplemented!(), OptAction::ShowState => {
let (send, recv) = crossbeam_channel::unbounded();
(app::EwwCommand::PrintState(send), Some(recv))
}
} }
} }
} }
@ -121,6 +121,10 @@ fn try_main() -> Result<()> {
if let Ok(mut stream) = net::UnixStream::connect(&*IPC_SOCKET_PATH) { if let Ok(mut stream) = net::UnixStream::connect(&*IPC_SOCKET_PATH) {
log::info!("Forwarding options to server"); log::info!("Forwarding options to server");
stream.write_all(&bincode::serialize(&opts)?)?; stream.write_all(&bincode::serialize(&opts)?)?;
let mut buf = String::new();
stream.read_to_string(&mut buf)?;
println!("{}", buf);
} else { } else {
log::info!("No instance found... Initializing server."); log::info!("No instance found... Initializing server.");
@ -175,13 +179,19 @@ fn initialize_server(opts: Opt) -> Result<()> {
} }
// run the command that eww was started with // run the command that eww was started with
app.handle_command(opts.action.into(), None); let (command, maybe_response_recv) = opts.action.into_eww_command();
app.handle_command(command);
if let Some(response_recv) = maybe_response_recv {
if let Ok(response) = response_recv.recv_timeout(std::time::Duration::from_millis(100)) {
println!("{}", response);
}
}
run_server_thread(evt_send.clone())?; run_server_thread(evt_send.clone())?;
let _hotwatch = run_filewatch_thread(&config_file_path, &scss_file_path, evt_send.clone())?; let _hotwatch = run_filewatch_thread(&config_file_path, &scss_file_path, evt_send.clone())?;
evt_recv.attach(None, move |msg| { evt_recv.attach(None, move |msg| {
app.handle_command(msg, None); app.handle_command(msg);
glib::Continue(true) glib::Continue(true)
}); });
@ -196,9 +206,19 @@ fn run_server_thread(evt_send: glib::Sender<app::EwwCommand>) -> Result<()> {
log::info!("Starting up eww server"); log::info!("Starting up eww server");
let listener = net::UnixListener::bind(&*IPC_SOCKET_PATH)?; let listener = net::UnixListener::bind(&*IPC_SOCKET_PATH)?;
for stream in listener.incoming() { for stream in listener.incoming() {
let command: Opt = bincode::deserialize_from(stream?)?; try_logging_errors!("handling message from IPC client" => {
log::info!("received command from IPC: {:?}", &command); let mut stream = stream?;
evt_send.send(command.action.into())?; let opts: Opt = bincode::deserialize_from(&stream)?;
log::info!("received command from IPC: {:?}", &opts);
let (command, maybe_response_recv) = opts.action.into_eww_command();
evt_send.send(command)?;
if let Some(response_recv) = maybe_response_recv {
if let Ok(response) = response_recv.recv_timeout(std::time::Duration::from_millis(100)) {
let result = &stream.write_all(response.as_bytes());
util::print_result_err("Sending text response to ipc client", &result);
}
}
});
} }
}; };
if let Err(err) = result { if let Err(err) = result {
@ -233,9 +253,7 @@ fn run_filewatch_thread<P: AsRef<Path>>(
evt_send.send(app::EwwCommand::ReloadCss(eww_css))?; evt_send.send(app::EwwCommand::ReloadCss(eww_css))?;
}) })
}); });
if let Err(e) = result { util::print_result_err("while loading CSS file for hot-reloading", &result);
eprintln!("WARN: error while loading CSS file for hot-reloading: \n{}", e)
};
Ok(hotwatch) Ok(hotwatch)
} }

View file

@ -79,3 +79,10 @@ pub fn replace_env_var_references(input: String) -> String {
}) })
.into_owned() .into_owned()
} }
/// If the given result is `Err`, prints out the error value using `{:?}`
pub fn print_result_err<T, E: std::fmt::Debug>(context: &str, result: &std::result::Result<T, E>) {
if let Err(err) = result {
eprintln!("Error {}: {:?}", context, err);
}
}