From c9c9f25afb626acd59d118455470f069c05d3ee5 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Wed, 23 Sep 2020 01:06:17 +0200 Subject: [PATCH] Implement basic cli with IPC --- Cargo.lock | 326 +++++++++++++++++++++++++++++- Cargo.toml | 13 +- src/config/element.rs | 8 +- src/eww_state.rs | 6 + src/main.rs | 221 +++++++++++++------- src/value.rs | 30 ++- src/widgets/mod.rs | 2 +- src/widgets/widget_definitions.rs | 9 + 8 files changed, 527 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f9f26e..a884896 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,7 +30,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -65,6 +65,17 @@ dependencies = [ "system-deps", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.9", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -85,12 +96,28 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "bincode" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" +dependencies = [ + "byteorder", + "serde", +] + [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + [[package]] name = "cairo-rs" version = "0.9.1" @@ -129,6 +156,42 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "crossbeam-channel" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" +dependencies = [ + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + [[package]] name = "ctor" version = "0.1.15" @@ -232,17 +295,33 @@ version = "0.1.0" dependencies = [ "anyhow", "derive_more", + "extend", "gdk", "gio", "glib", "gtk", "hocon", + "ipc-channel", "maplit", "pretty_assertions", "regex", + "serde", + "structopt", "try_match", ] +[[package]] +name = "extend" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c635fdc695a9cbf89115695b04c27c864fa1bf5a94a253798a7bd0752fad5e5" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "failure" version = "0.1.8" @@ -265,6 +344,28 @@ dependencies = [ "synstructure", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + [[package]] name = "futures" version = "0.3.5" @@ -473,7 +574,7 @@ dependencies = [ "gobject-sys", "libc", "system-deps", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -587,6 +688,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "hermit-abi" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151" +dependencies = [ + "libc", +] + [[package]] name = "hocon" version = "0.3.5" @@ -601,6 +711,33 @@ dependencies = [ "uuid", ] +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "ipc-channel" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3698b8affd5656032a074a7d40b3c2a29b71971f3e1ff6042b9d40724e20d97c" +dependencies = [ + "bincode", + "crossbeam-channel", + "fnv", + "lazy_static", + "libc", + "mio", + "rand", + "serde", + "tempfile", + "uuid", +] + [[package]] name = "itertools" version = "0.9.0" @@ -620,6 +757,16 @@ dependencies = [ "regex", ] +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -632,12 +779,27 @@ version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +[[package]] +name = "log" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +dependencies = [ + "cfg-if", +] + [[package]] name = "maplit" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + [[package]] name = "memchr" version = "2.3.3" @@ -654,6 +816,48 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mio" +version = "0.6.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" +dependencies = [ + "cfg-if", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "net2" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853" +dependencies = [ + "cfg-if", + "libc", + "winapi 0.3.9", +] + [[package]] name = "nom" version = "4.2.3" @@ -682,7 +886,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -866,6 +1070,12 @@ dependencies = [ "rand_core", ] +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + [[package]] name = "regex" version = "1.3.9" @@ -884,6 +1094,15 @@ version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "rustc-demangle" version = "0.1.16" @@ -895,6 +1114,20 @@ name = "serde" version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "slab" @@ -902,6 +1135,36 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cc388d94ffabf39b5ed5fadddc40147cb21e605f53db6f8f36a625d27489ac5" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2513111825077552a6751dfad9e11ce0fba07d7276a3943a037d7e93e64c5f" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "strum" version = "0.18.0" @@ -958,6 +1221,29 @@ dependencies = [ "version-compare", ] +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.9", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.20" @@ -1025,6 +1311,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + [[package]] name = "unicode-xid" version = "0.2.1" @@ -1040,6 +1332,12 @@ dependencies = [ "rand", ] +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version-compare" version = "0.0.10" @@ -1064,6 +1362,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.9" @@ -1074,6 +1378,12 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -1085,3 +1395,13 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] diff --git a/Cargo.toml b/Cargo.toml index 663d1a2..2ea92af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,18 +13,17 @@ gio = { version = "", features = ["v2_44"] } glib = { version = "", features = ["v2_44"] } regex = "1" - - hocon = { version = "0.3", default-features = false, features = [ "serde-support" ]} - try_match = "0.2.2" - anyhow = "1.0" -#thiserror = "1.0" - - derive_more = "0.99" maplit = "1" +structopt = "0.3" +ipc-channel="0.14.1" +serde = {version = "1.0", features = ["derive"]} +extend = "0.3.0" + +#thiserror = "1.0" [dev-dependencies] pretty_assertions = "0.6.1" diff --git a/src/config/element.rs b/src/config/element.rs index b26fb15..d709096 100644 --- a/src/config/element.rs +++ b/src/config/element.rs @@ -37,13 +37,13 @@ impl WidgetDefinition { #[derive(Debug, Clone, PartialEq)] pub enum ElementUse { Widget(WidgetUse), - Text(String), + Text(AttrValue), } impl ElementUse { pub fn parse_hocon(hocon: Hocon) -> Result { match hocon { - Hocon::String(s) => Ok(ElementUse::Text(s)), + Hocon::String(s) => Ok(ElementUse::Text(AttrValue::from_string(s))), Hocon::Hash(hash) => WidgetUse::parse_hocon_hash(hash).map(ElementUse::Widget), _ => Err(anyhow!("'{:?}' is not a valid element", hocon)), } @@ -73,7 +73,7 @@ impl WidgetUse { // TODO allow for `layout_horizontal: [ elements ]` shorthand let children = match &widget_config.get("children") { - Some(Hocon::String(text)) => Ok(vec![ElementUse::Text(text.to_string())]), + Some(Hocon::String(text)) => Ok(vec![ElementUse::Text(AttrValue::from_string(text.to_string()))]), Some(Hocon::Array(children)) => children .clone() .into_iter() @@ -120,7 +120,7 @@ mod test { fn test_parse_text() { assert_eq!( ElementUse::parse_hocon(Hocon::String("hi".to_string())).unwrap(), - ElementUse::Text("hi".to_string()) + ElementUse::Text(AttrValue::Concrete(PrimitiveValue::String("hi".to_string()))) ); } diff --git a/src/eww_state.rs b/src/eww_state.rs index a36844f..5e00d14 100644 --- a/src/eww_state.rs +++ b/src/eww_state.rs @@ -10,6 +10,12 @@ pub struct EwwState { state: HashMap, } +impl std::fmt::Debug for EwwState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "EwwState {{ state: {:?} }}", self.state) + } +} + impl EwwState { pub fn from_default_vars(defaults: HashMap) -> Self { EwwState { diff --git a/src/main.rs b/src/main.rs index 0d668ec..eeea5ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,10 @@ use anyhow::*; use gdk::*; use gio::prelude::*; use gtk::prelude::*; -use gtk::{Application, ApplicationWindow}; +use ipc_channel::ipc; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use structopt::StructOpt; pub mod config; pub mod eww_state; @@ -43,7 +45,8 @@ const EXAMPLE_CONFIG: &str = r#"{ } } { layout: { children: [ - "hi", + "date" // TODO FIX!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + { label: { text: "$$date" } } { button: { children: "click me you" } } { slider: { value: "$$some_value", min: 0, max: 100, onchange: "notify-send 'changed' {}" } } { slider: { value: "$$some_value", orientation: "vertical" } } @@ -64,6 +67,7 @@ const EXAMPLE_CONFIG: &str = r#"{ }, default_vars: { ree: 12 + date: "never" } windows: { main_window: { @@ -80,95 +84,174 @@ const EXAMPLE_CONFIG: &str = r#"{ }, }"#; -#[derive(Debug)] -enum MuhhMsg { - UpdateValue(String, PrimitiveValue), -} - fn main() { if let Err(e) = try_main() { eprintln!("{:?}", e); } } +#[derive(StructOpt, Debug, Serialize, Deserialize)] +struct Opt { + #[structopt(subcommand)] + action: OptAction, +} +#[derive(StructOpt, Debug, Serialize, Deserialize)] +enum OptAction { + #[structopt(name = "update")] + Update(OptActionUpdate), + + #[structopt(name = "open")] + OpenWindow(OptActionOpen), +} + +#[derive(StructOpt, Debug, Serialize, Deserialize)] +struct OptActionUpdate { + fieldname: String, + value: PrimitiveValue, +} + +#[derive(StructOpt, Debug, Serialize, Deserialize)] +struct OptActionOpen { + window_name: String, +} + fn try_main() -> Result<()> { + let opts: Opt = StructOpt::from_args(); + if let Ok(sender) = find_server_process() { + sender.send(opts)?; + } else { + initialize_server(opts)?; + } + Ok(()) +} + +fn find_server_process() -> Result> { + let instance_path = std::fs::read_to_string("/tmp/eww-instance-path")?; + Ok(ipc::IpcSender::connect(instance_path)?) +} + +fn initialize_server(opts: Opt) -> Result<()> { let eww_config = config::EwwConfig::from_hocon(&config::parse_hocon(EXAMPLE_CONFIG)?)?; - let application = Application::new(Some("de.elkowar.eww"), gio::ApplicationFlags::FLAGS_NONE) - .expect("failed to initialize GTK application "); + let mut app = App { + eww_state: EwwState::from_default_vars(eww_config.get_default_vars().clone()), + eww_config, + }; - let window_def = eww_config.get_windows()["main_window"].clone(); + let (send, recv) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); - application.connect_activate(move |app| { - let result: Result<()> = try { - let app_window = ApplicationWindow::new(app); - app_window.set_title("Eww"); - app_window.set_wmclass("noswallow", "noswallow"); - app_window.set_type_hint(gdk::WindowTypeHint::Dock); - app_window.set_position(gtk::WindowPosition::Center); - app_window.set_keep_above(true); - app_window.set_default_size(window_def.size.0, window_def.size.1); - app_window.set_visual( - app_window - .get_display() - .get_default_screen() - .get_rgba_visual() - .or_else(|| app_window.get_display().get_default_screen().get_system_visual()) - .as_ref(), - ); + gtk::init()?; - app_window.fullscreen(); + app.handle_user_command(opts)?; - let mut eww_state = EwwState::from_default_vars(eww_config.get_default_vars().clone()); - let empty_local_state = HashMap::new(); - - app_window.add(&widgets::element_to_gtk_thing( - &eww_config.get_widgets(), - &mut eww_state, - &empty_local_state, - &window_def.widget, - )?); - - app_window.show_all(); - - let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); - std::thread::spawn(move || event_loop(tx)); - - rx.attach(None, move |msg| { - match msg { - MuhhMsg::UpdateValue(key, value) => eww_state.update_value(key, value), - } - - glib::Continue(true) - }); - - let window = app_window.get_window().unwrap(); - window.set_override_redirect(true); - window.move_(window_def.position.0, window_def.position.1); - window.show(); - window.raise(); - }; - if let Err(err) = result { - eprintln!("{:?}", err); - std::process::exit(1); - } + std::thread::spawn(move || run_ipc_server(send)); + recv.attach(None, move |msg| { + app.handle_event(msg); + glib::Continue(true) }); - application.run(&[]); + gtk::main(); Ok(()) } -fn event_loop(sender: glib::Sender) { +fn run_ipc_server(send: glib::Sender) -> Result<()> { + loop { + let (ipc_server, instance_path): (ipc::IpcOneShotServer, _) = ipc::IpcOneShotServer::new()?; + std::fs::write("/tmp/eww-instance-path", instance_path)?; + let (receiver, initial) = ipc_server.accept()?; + send.send(EwwEvent::UserCommand(initial))?; + } +} + +#[derive(Debug)] +struct App { + eww_state: EwwState, + eww_config: config::EwwConfig, +} + +impl App { + fn handle_user_command(&mut self, opts: Opt) -> Result<()> { + match opts.action { + OptAction::Update(update) => self.update_state(update), + OptAction::OpenWindow(update) => self.open_window(update)?, + } + Ok(()) + } + + fn update_state(&mut self, update: OptActionUpdate) { + self.eww_state.update_value(update.fieldname, update.value); + } + + fn open_window(&mut self, open_window: OptActionOpen) -> Result<()> { + let window_def = self.eww_config.get_windows()[&open_window.window_name].clone(); + + let window = gtk::Window::new(gtk::WindowType::Toplevel); + window.set_title("Eww"); + window.set_wmclass("noswallow", "noswallow"); + window.set_type_hint(gdk::WindowTypeHint::Dock); + window.set_position(gtk::WindowPosition::Center); + window.set_keep_above(true); + window.set_default_size(window_def.size.0, window_def.size.1); + window.set_visual( + window + .get_display() + .get_default_screen() + .get_rgba_visual() + .or_else(|| window.get_display().get_default_screen().get_system_visual()) + .as_ref(), + ); + + window.fullscreen(); + + let empty_local_state = HashMap::new(); + + window.add(&widgets::element_to_gtk_thing( + &self.eww_config.get_widgets(), + &mut self.eww_state, + &empty_local_state, + &window_def.widget, + )?); + + window.show_all(); + + let gdk_window = window.get_window().unwrap(); + gdk_window.set_override_redirect(true); + gdk_window.move_(window_def.position.0, window_def.position.1); + gdk_window.show(); + gdk_window.raise(); + + Ok(()) + } + + fn handle_event(&mut self, event: EwwEvent) { + let result: Result<_> = try { + match event { + EwwEvent::UserCommand(command) => self.handle_user_command(command)?, + } + }; + if let Err(err) = result { + eprintln!("Error while handling event: {:?}", err); + } + } +} + +#[derive(Debug)] +enum EwwEvent { + UserCommand(Opt), +} + +fn event_loop(sender: glib::Sender) { let mut x = 0; loop { x += 1; std::thread::sleep(std::time::Duration::from_millis(1000)); - sender - .send(MuhhMsg::UpdateValue( - "ree".to_string(), - PrimitiveValue::Number(x as f64 * 10.0), - )) - .unwrap(); + let event_opt = Opt { + action: OptAction::Update(OptActionUpdate { + fieldname: "ree".to_string(), + value: PrimitiveValue::Number(x as f64 * 10.0), + }), + }; + sender.send(EwwEvent::UserCommand(event_opt)).unwrap(); } } diff --git a/src/value.rs b/src/value.rs index ace7228..2595891 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,16 +1,32 @@ use anyhow::*; use derive_more; use hocon::Hocon; +use serde::{Deserialize, Serialize}; use std::convert::TryFrom; use try_match::try_match; -#[derive(Clone, Debug, PartialEq, derive_more::From)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, derive_more::From)] pub enum PrimitiveValue { String(String), Number(f64), Boolean(bool), } +impl std::str::FromStr for PrimitiveValue { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + Ok(s.parse() + .map(PrimitiveValue::Number) + .or_else(|_| s.parse().map(PrimitiveValue::Boolean)) + .unwrap_or_else(|_| PrimitiveValue::String(remove_surrounding(s, '\'').to_string()))) + } +} + +fn remove_surrounding(s: &str, surround: char) -> &str { + s.strip_prefix(surround).unwrap_or(s).strip_suffix(surround).unwrap_or(s) +} + impl TryFrom for String { type Error = anyhow::Error; fn try_from(x: PrimitiveValue) -> Result { @@ -102,8 +118,15 @@ impl AttrValue { pub fn as_var_ref(&self) -> Result<&String> { try_match!(AttrValue::VarRef(x) = self).map_err(|e| anyhow!("{:?} is not a VarRef", e)) } -} + pub fn from_string(s: String) -> Self { + if s.starts_with("$$") { + AttrValue::VarRef(s.trim_start_matches("$$").to_string()) + } else { + AttrValue::Concrete(PrimitiveValue::String(s.clone())) + } + } +} impl From for AttrValue { fn from(value: PrimitiveValue) -> Self { AttrValue::Concrete(value) @@ -114,8 +137,7 @@ impl std::convert::TryFrom<&Hocon> for AttrValue { type Error = anyhow::Error; fn try_from(value: &Hocon) -> Result { Ok(match value { - Hocon::String(s) if s.starts_with("$$") => AttrValue::VarRef(s.trim_start_matches("$$").to_string()), - Hocon::String(s) => AttrValue::Concrete(PrimitiveValue::String(s.clone())), + Hocon::String(s) => AttrValue::from_string(s.clone()), Hocon::Integer(n) => AttrValue::Concrete(PrimitiveValue::Number(*n as f64)), Hocon::Real(n) => AttrValue::Concrete(PrimitiveValue::Number(*n as f64)), Hocon::Boolean(b) => AttrValue::Concrete(PrimitiveValue::Boolean(*b)), diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index d6241b2..faf2fdb 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -30,7 +30,7 @@ pub fn element_to_gtk_thing( element: &element::ElementUse, ) -> Result { match element { - element::ElementUse::Text(text) => Ok(gtk::Label::new(Some(&text)).upcast()), + element::ElementUse::Text(text) => Ok(gtk::Label::new(Some(text.as_string()?)).upcast()), // TODO this should use resolve element::ElementUse::Widget(widget) => { let gtk_container = build_gtk_widget(widget_definitions, eww_state, local_env, widget)?; diff --git a/src/widgets/widget_definitions.rs b/src/widgets/widget_definitions.rs index 4f0218e..f1ec313 100644 --- a/src/widgets/widget_definitions.rs +++ b/src/widgets/widget_definitions.rs @@ -55,6 +55,7 @@ pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result build_gtk_image(bargs)?.upcast(), "layout" => build_gtk_layout(bargs)?.upcast(), "button" => build_gtk_button(bargs)?.upcast(), + "label" => build_gtk_label(bargs)?.upcast(), _ => return Ok(None), }; Ok(Some(gtk_widget)) @@ -100,6 +101,14 @@ fn build_gtk_layout(bargs: &mut BuilderArgs) -> Result { Ok(gtk_widget) } +fn build_gtk_label(bargs: &mut BuilderArgs) -> Result { + let gtk_widget = gtk::Label::new(None); + resolve!(bargs, gtk_widget, { + resolve_str => "text" = 10.0 => |v| gtk_widget.set_text(&v), + }); + Ok(gtk_widget) +} + fn parse_orientation(o: &str) -> gtk::Orientation { match o { "vertical" | "v" => gtk::Orientation::Vertical,