From 720ba7bfb01cee728d9aeab6f78218bd7e8f5e7e Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Sun, 25 Sep 2022 22:49:00 +0100 Subject: [PATCH] Major module refactor (#19) * refactor: major module restructuring Modules now implement a "controller", which allows for separation of logic from UI code and enforces a tighter structure around how modules should be written. The introduction of this change required major refactoring or even rewriting of all modules. This also better integrates the popup into modules, making it easier for data to be passed around without fetching the same thing twice The refactor also improves some client code, switching from `ksway` to the much more stable `swayipc-async`. Partial multi-monitor for the tray module has been added. BREAKING CHANGE: The `mpd` module config has changed, moving the icons to their own object. --- Cargo.lock | 499 +++++++++--------- Cargo.toml | 12 +- src/bar.rs | 177 +++++-- src/bridge_channel.rs | 43 ++ src/collection.rs | 15 + src/main.rs | 53 +- src/modules/clock.rs | 114 ++++ src/modules/clock/mod.rs | 71 --- src/modules/clock/popup.rs | 40 -- src/modules/focused.rs | 128 +++-- src/modules/launcher/item.rs | 489 ++++++++--------- src/modules/launcher/mod.rs | 762 +++++++++++++++++---------- src/modules/launcher/open_state.rs | 18 +- src/modules/launcher/popup.rs | 36 -- src/modules/mod.rs | 62 ++- src/modules/mpd/client.rs | 115 +++- src/modules/mpd/mod.rs | 435 ++++++++++----- src/modules/mpd/popup.rs | 175 ------ src/modules/script.rs | 84 +-- src/modules/sysinfo.rs | 64 ++- src/modules/tray/client.rs | 74 +++ src/modules/{tray.rs => tray/mod.rs} | 114 ++-- src/modules/workspaces.rs | 219 ++++---- src/popup.rs | 109 ++-- src/sway/mod.rs | 256 +++------ src/sway/node.rs | 63 +-- 26 files changed, 2381 insertions(+), 1846 deletions(-) create mode 100644 src/bridge_channel.rs create mode 100644 src/modules/clock.rs delete mode 100644 src/modules/clock/mod.rs delete mode 100644 src/modules/clock/popup.rs delete mode 100644 src/modules/launcher/popup.rs delete mode 100644 src/modules/mpd/popup.rs create mode 100644 src/modules/tray/client.rs rename src/modules/{tray.rs => tray/mod.rs} (64%) diff --git a/Cargo.lock b/Cargo.lock index 5f18ae6..d31563b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,6 +94,26 @@ dependencies = [ "slab", ] +[[package]] +name = "async-io" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7" +dependencies = [ + "autocfg", + "concurrent-queue", + "futures-lite", + "libc", + "log", + "once_cell", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "winapi", +] + [[package]] name = "async-lock" version = "2.5.0" @@ -103,15 +123,25 @@ dependencies = [ "event-listener", ] +[[package]] +name = "async-pidfd" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12177058299bb8e3507695941b6d0d7dc0e4e6515b8bc1bf4609d9e32ef51799" +dependencies = [ + "async-io", + "libc", +] + [[package]] name = "async-recursion" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -126,11 +156,17 @@ version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] +[[package]] +name = "async_once" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce4f10ea3abcd6617873bae9f91d1c5332b4a778bd9ce34d0cd517474c1de82" + [[package]] name = "atk" version = "0.15.1" @@ -180,7 +216,7 @@ checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", @@ -202,15 +238,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "memchr", -] - [[package]] name = "byteorder" version = "1.4.3" @@ -268,12 +295,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -318,9 +339,9 @@ checksum = "9ba52acd3b0a5c33aeada5cdaa3267cdc7c594a98731d4268cdc1532f4264cb4" dependencies = [ "heck", "proc-macro-error", - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -391,7 +412,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6981753b68f7642c3737b302cd37dee779189fcdad975a69d6a7bb165f134e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "clap", "colored", "pest", @@ -411,23 +432,14 @@ dependencies = [ "libc", ] -[[package]] -name = "crossbeam-channel" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" -dependencies = [ - "crossbeam-utils 0.6.6", -] - [[package]] name = "crossbeam-channel" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils 0.8.11", + "cfg-if", + "crossbeam-utils", ] [[package]] @@ -436,9 +448,9 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", - "crossbeam-utils 0.8.11", + "crossbeam-utils", ] [[package]] @@ -448,30 +460,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" dependencies = [ "autocfg", - "cfg-if 1.0.0", - "crossbeam-utils 0.8.11", + "cfg-if", + "crossbeam-utils", "memoffset", "once_cell", "scopeguard", ] -[[package]] -name = "crossbeam-utils" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -dependencies = [ - "cfg-if 0.1.10", - "lazy_static", -] - [[package]] name = "crossbeam-utils" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] @@ -485,29 +487,81 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "derivative" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "derive_more" -version = "0.15.0" +name = "derive_builder" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe" +checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3" dependencies = [ - "lazy_static", - "proc-macro2 0.4.30", - "quote 0.6.13", - "regex", - "rustc_version 0.2.3", - "syn 0.15.44", + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" +dependencies = [ + "derive_builder_core", + "syn", ] [[package]] @@ -562,9 +616,9 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -599,7 +653,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92" dependencies = [ "memoffset", - "rustc_version 0.3.3", + "rustc_version", ] [[package]] @@ -608,7 +662,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "windows-sys", @@ -682,9 +736,9 @@ version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -789,7 +843,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.11.0+wasi-snapshot-preview1", ] @@ -860,9 +914,9 @@ dependencies = [ "heck", "proc-macro-crate", "proc-macro-error", - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -875,29 +929,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "globset" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "globwalk" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9db17aec586697a93219b19726b5b68307eba92898c34b170857343fe67c99d" -dependencies = [ - "ignore", - "walkdir", -] - [[package]] name = "gobject-sys" version = "0.15.10" @@ -987,9 +1018,9 @@ dependencies = [ "anyhow", "proc-macro-crate", "proc-macro-error", - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1020,22 +1051,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "ignore" -version = "0.4.18" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" -dependencies = [ - "crossbeam-utils 0.8.11", - "globset", - "lazy_static", - "log", - "memchr", - "regex", - "same-file", - "thread_local", - "walkdir", - "winapi-util", -] +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indenter" @@ -1079,23 +1098,23 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] name = "ironbar" version = "0.5.2" dependencies = [ + "async_once", "chrono", "color-eyre", "cornfig", - "crossbeam-channel 0.5.6", + "derive_builder", "dirs", "futures-util", "glib", "gtk", "gtk-layer-shell", - "ksway", "lazy_static", "mpd_client", "notify", @@ -1105,6 +1124,7 @@ dependencies = [ "serde_yaml", "stray", "strip-ansi-escapes", + "swayipc-async", "sysinfo", "tokio", "toml", @@ -1115,15 +1135,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "itertools" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.2" @@ -1150,23 +1161,6 @@ dependencies = [ "libc", ] -[[package]] -name = "ksway" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7bda3675f034f78f763af40e633bcb0529c022e4d2ee063944dab9777004c5" -dependencies = [ - "byteorder", - "crossbeam-channel 0.3.9", - "derive_more", - "globwalk", - "itertools", - "num-derive", - "num-traits", - "serde", - "serde_json", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -1195,7 +1189,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1282,7 +1276,7 @@ checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ "bitflags", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "memoffset", ] @@ -1304,7 +1298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2c66da08abae1c024c01d635253e402341b4060a12e99b31c7594063bf490a" dependencies = [ "bitflags", - "crossbeam-channel 0.5.6", + "crossbeam-channel", "filetime", "fsevent-sys", "inotify", @@ -1324,17 +1318,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-derive" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", -] - [[package]] name = "num-integer" version = "0.1.45" @@ -1457,7 +1440,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "smallvec", @@ -1492,9 +1475,9 @@ checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1526,6 +1509,20 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +[[package]] +name = "polling" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899b00b9c8ab553c743b3e11e87c5c7d423b2a2de229ba95b24a756344748011" +dependencies = [ + "autocfg", + "cfg-if", + "libc", + "log", + "wepoll-ffi", + "winapi", +] + [[package]] name = "ppv-lite86" version = "0.2.16" @@ -1549,9 +1546,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", "version_check", ] @@ -1561,20 +1558,11 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", + "proc-macro2", + "quote", "version_check", ] -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid", -] - [[package]] name = "proc-macro2" version = "1.0.42" @@ -1584,22 +1572,13 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - [[package]] name = "quote" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ - "proc-macro2 1.0.42", + "proc-macro2", ] [[package]] @@ -1650,9 +1629,9 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" dependencies = [ - "crossbeam-channel 0.5.6", + "crossbeam-channel", "crossbeam-deque", - "crossbeam-utils 0.8.11", + "crossbeam-utils", "num_cpus", ] @@ -1717,22 +1696,13 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" dependencies = [ - "semver 0.11.0", + "semver", ] [[package]] @@ -1756,30 +1726,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser 0.7.0", -] - [[package]] name = "semver" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver-parser 0.10.2", + "semver-parser", ] -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "semver-parser" version = "0.10.2" @@ -1804,9 +1759,9 @@ version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1826,9 +1781,9 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1850,7 +1805,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", ] @@ -1913,16 +1868,17 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stray" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5f063390cf8e8b633159bd4fa682ad45508e56a40d9ac341cb322cfac626d56" +source = "git+https://github.com/JakeStanger/stray.git?branch=fix/tracing#719d921b769f85772caa181c4469e0fedd61df87" dependencies = [ "anyhow", "byteorder", "chrono", - "event-listener", + "log", "serde", + "thiserror", "tokio", "tokio-stream", + "tracing", "zbus", ] @@ -1942,14 +1898,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +name = "swayipc-async" +version = "2.0.1" +source = "git+https://github.com/JakeStanger/swayipc-rs.git?branch=feat/derive-clone#6464c41ac8329381f2171dcb38329bff29958baf" dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid", + "async-io", + "async-pidfd", + "futures-lite", + "serde", + "serde_json", + "swayipc-types", +] + +[[package]] +name = "swayipc-types" +version = "1.1.2" +source = "git+https://github.com/JakeStanger/swayipc-rs.git?branch=feat/derive-clone#6464c41ac8329381f2171dcb38329bff29958baf" +dependencies = [ + "serde", + "serde_json", + "thiserror", ] [[package]] @@ -1958,8 +1926,8 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", + "proc-macro2", + "quote", "unicode-ident", ] @@ -1969,7 +1937,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae2421f3e16b3afd4aa692d23b83d0ba42ee9b0081d5deeb7d21428d7195fb1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "core-foundation-sys", "libc", "ntapi", @@ -1997,7 +1965,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "libc", "redox_syscall", @@ -2035,9 +2003,9 @@ version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -2073,9 +2041,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.20.1" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" +checksum = "89797afd69d206ccd11fb0ea560a44bbb87731d020670e79416d442919257d42" dependencies = [ "autocfg", "bytes", @@ -2096,9 +2064,9 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -2127,7 +2095,7 @@ version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2139,7 +2107,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" dependencies = [ - "crossbeam-channel 0.5.6", + "crossbeam-channel", "time 0.3.13", "tracing-subscriber", ] @@ -2150,9 +2118,9 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -2232,12 +2200,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - [[package]] name = "unsafe-libyaml" version = "0.2.2" @@ -2285,8 +2247,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" dependencies = [ - "proc-macro2 1.0.42", - "quote 1.0.20", + "proc-macro2", + "quote", ] [[package]] @@ -2318,6 +2280,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wepoll-ffi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +dependencies = [ + "cc", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2439,10 +2410,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f8fb5186d1c87ae88cf234974c240671238b4a679158ad3b94ec465237349a6" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.42", - "quote 1.0.20", + "proc-macro2", + "quote", "regex", - "syn 1.0.98", + "syn", ] [[package]] @@ -2477,7 +2448,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08e977eaa3af652f63d479ce50d924254ad76722a6289ec1a1eac3231ca30430" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.42", - "quote 1.0.20", - "syn 1.0.98", + "proc-macro2", + "quote", + "syn", ] diff --git a/Cargo.toml b/Cargo.toml index b2a9947..b4863ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,11 @@ description = "Customisable wlroots/sway bar" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +derive_builder = "0.11.2" gtk = "0.15.5" gtk-layer-shell = "0.4.1" glib = "0.15.12" -tokio = { version = "1.20.1", features = ["macros", "rt-multi-thread", "time"] } +tokio = { version = "1.21.0", features = ["macros", "rt-multi-thread", "time"] } tracing = "0.1.36" tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } tracing-error = "0.2.0" @@ -26,13 +27,12 @@ serde_yaml = "0.9.4" toml = "0.5.9" cornfig = "0.3.0" lazy_static = "1.4.0" +async_once = "0.2.6" regex = "1.6.0" -stray = "0.1.1" +stray = { git = "https://github.com/JakeStanger/stray.git", branch = "fix/tracing" } dirs = "4.0.0" walkdir = "2.3.2" notify = "5.0.0" mpd_client = "1.0.0" -ksway = "0.1.0" -sysinfo = "0.26.2" -# required for wrapping ksway -crossbeam-channel = "0.5.6" \ No newline at end of file +swayipc-async = { git = "https://github.com/JakeStanger/swayipc-rs.git", branch = "feat/derive-clone" } +sysinfo = "0.26.2" \ No newline at end of file diff --git a/src/bar.rs b/src/bar.rs index e8d3b89..e72889f 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -1,10 +1,21 @@ +use crate::bridge_channel::BridgeChannel; use crate::config::{BarPosition, ModuleConfig}; -use crate::modules::{Module, ModuleInfo, ModuleLocation}; +use crate::modules::launcher::{ItemEvent, LauncherUpdate}; +use crate::modules::mpd::{PlayerCommand, SongUpdate}; +use crate::modules::workspaces::WorkspaceUpdate; +use crate::modules::{Module, ModuleInfoBuilder, ModuleLocation, ModuleUpdateEvent, WidgetContext}; +use crate::popup::Popup; use crate::Config; +use chrono::{DateTime, Local}; use color_eyre::Result; use gtk::gdk::Monitor; use gtk::prelude::*; use gtk::{Application, ApplicationWindow, Orientation}; +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; +use stray::message::NotifierItemCommand; +use stray::NotifierItemMessage; +use tokio::sync::mpsc; use tracing::{debug, info}; /// Creates a new window for a bar, @@ -65,40 +76,29 @@ fn load_modules( monitor: &Monitor, output_name: &str, ) -> Result<()> { - if let Some(modules) = config.left { - let info = ModuleInfo { - app, - location: ModuleLocation::Left, - bar_position: &config.position, - monitor, - output_name, - }; + let mut info_builder = ModuleInfoBuilder::default(); + let info_builder = info_builder + .app(app) + .bar_position(&config.position) + .monitor(monitor) + .output_name(output_name); - add_modules(left, modules, &info)?; + if let Some(modules) = config.left { + let info_builder = info_builder.location(ModuleLocation::Left); + + add_modules(left, modules, info_builder)?; } if let Some(modules) = config.center { - let info = ModuleInfo { - app, - location: ModuleLocation::Center, - bar_position: &config.position, - monitor, - output_name, - }; + let info_builder = info_builder.location(ModuleLocation::Center); - add_modules(center, modules, &info)?; + add_modules(center, modules, info_builder)?; } if let Some(modules) = config.right { - let info = ModuleInfo { - app, - location: ModuleLocation::Right, - bar_position: &config.position, - monitor, - output_name, - }; + let info_builder = info_builder.location(ModuleLocation::Right); - add_modules(right, modules, &info)?; + add_modules(right, modules, info_builder)?; } Ok(()) @@ -106,33 +106,124 @@ fn load_modules( /// Adds modules into a provided GTK box, /// which should be one of its left, center or right containers. -fn add_modules(content: >k::Box, modules: Vec, info: &ModuleInfo) -> Result<()> { +fn add_modules( + content: >k::Box, + modules: Vec, + info_builder: &mut ModuleInfoBuilder, +) -> Result<()> { + let base_popup_info = info_builder.module_name("").build()?; + let popup = Popup::new(&base_popup_info); + let popup = Arc::new(RwLock::new(popup)); + macro_rules! add_module { - ($module:expr, $name:literal) => {{ - let widget = $module.into_widget(&info)?; - widget.set_widget_name($name); - content.add(&widget); - debug!("Added module of type {}", $name); - }}; + ($module:expr, $id:expr, $name:literal, $send_message:ty, $receive_message:ty) => { + let info = info_builder.module_name($name).build()?; + + let (w_tx, w_rx) = glib::MainContext::channel::<$send_message>(glib::PRIORITY_DEFAULT); + let (p_tx, p_rx) = glib::MainContext::channel::<$send_message>(glib::PRIORITY_DEFAULT); + + let channel = BridgeChannel::>::new(); + let (ui_tx, ui_rx) = mpsc::channel::<$receive_message>(16); + + $module.spawn_controller(&info, channel.create_sender(), ui_rx)?; + + let context = WidgetContext { + id: $id, + widget_rx: w_rx, + popup_rx: p_rx, + tx: channel.create_sender(), + controller_tx: ui_tx, + }; + + let widget = $module.into_widget(context, &info)?; + + content.add(&widget.widget); + widget.widget.set_widget_name(info.module_name); + + let has_popup = widget.popup.is_some(); + if let Some(popup_content) = widget.popup { + popup + .write() + .expect("Failed to get write lock on popup") + .register_content($id, popup_content); + } + + let popup2 = Arc::clone(&popup); + channel.recv(move |ev| { + let popup = popup2.clone(); + match ev { + ModuleUpdateEvent::Update(update) => { + if has_popup { + p_tx.send(update.clone()) + .expect("Failed to send update to popup"); + } + + w_tx.send(update).expect("Failed to send update to module"); + } + ModuleUpdateEvent::TogglePopup((x, w)) => { + debug!("Toggling popup for {} [#{}]", $name, $id); + let popup = popup.read().expect("Failed to get read lock on popup"); + if popup.is_visible() { + popup.hide() + } else { + popup.show_content($id); + popup.show(x, w); + } + } + ModuleUpdateEvent::OpenPopup((x, w)) => { + debug!("Opening popup for {} [#{}]", $name, $id); + + let popup = popup.read().expect("Failed to get read lock on popup"); + popup.hide(); + popup.show(x, w); + popup.show_content($id); + } + ModuleUpdateEvent::ClosePopup => { + debug!("Closing popup for {} [#{}]", $name, $id); + + let popup = popup.read().expect("Failed to get read lock on popup"); + popup.hide(); + } + } + + Continue(true) + }); + }; } - for config in modules { + for (id, config) in modules.into_iter().enumerate() { match config { - ModuleConfig::Clock(module) => add_module!(module, "clock"), - ModuleConfig::Mpd(module) => add_module!(module, "mpd"), - ModuleConfig::Tray(module) => add_module!(module, "tray"), - ModuleConfig::Workspaces(module) => add_module!(module, "workspaces"), - ModuleConfig::SysInfo(module) => add_module!(module, "sysinfo"), - ModuleConfig::Launcher(module) => add_module!(module, "launcher"), - ModuleConfig::Script(module) => add_module!(module, "script"), - ModuleConfig::Focused(module) => add_module!(module, "focused"), + ModuleConfig::Clock(module) => { + add_module!(module, id, "clock", DateTime, ()); + } + ModuleConfig::Script(module) => { + add_module!(module, id, "script", String, ()); + } + ModuleConfig::SysInfo(module) => { + add_module!(module, id, "sysinfo", HashMap, ()); + } + ModuleConfig::Focused(module) => { + add_module!(module, id, "focused", (String, String), ()); + } + ModuleConfig::Workspaces(module) => { + add_module!(module, id, "workspaces", WorkspaceUpdate, String); + } + ModuleConfig::Tray(module) => { + add_module!(module, id, "tray", NotifierItemMessage, NotifierItemCommand); + } + ModuleConfig::Mpd(module) => { + add_module!(module, id, "mpd", Option, PlayerCommand); + } + ModuleConfig::Launcher(module) => { + add_module!(module, id, "launcher", LauncherUpdate, ItemEvent); + } } } Ok(()) } -/// Sets up GTK layer shell for a provided aplication window. +/// Sets up GTK layer shell for a provided application window. fn setup_layer_shell(win: &ApplicationWindow, monitor: &Monitor, position: &BarPosition) { gtk_layer_shell::init_for_window(win); gtk_layer_shell::set_monitor(win, monitor); diff --git a/src/bridge_channel.rs b/src/bridge_channel.rs new file mode 100644 index 0000000..ed516e5 --- /dev/null +++ b/src/bridge_channel.rs @@ -0,0 +1,43 @@ +use tokio::spawn; +use tokio::sync::mpsc; + +/// MPSC async -> sync channel. +/// The sender uses `tokio::sync::mpsc` +/// while the receiver uses `glib::MainContext::channel`. +/// +/// This makes it possible to send events asynchronously +/// and receive them on the main thread, +/// allowing UI updates to be handled on the receiving end. +pub struct BridgeChannel { + async_tx: mpsc::Sender, + sync_rx: glib::Receiver, +} + +impl BridgeChannel { + /// Creates a new channel + pub fn new() -> Self { + let (async_tx, mut async_rx) = mpsc::channel(32); + let (sync_tx, sync_rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); + + spawn(async move { + while let Some(val) = async_rx.recv().await { + sync_tx.send(val).expect("Failed to send message"); + } + }); + + Self { async_tx, sync_rx } + } + + /// Gets a clone of the sender. + pub fn create_sender(&self) -> mpsc::Sender { + self.async_tx.clone() + } + + /// Attaches a callback to the receiver. + pub fn recv(self, f: F) -> glib::SourceId + where + F: FnMut(T) -> glib::Continue + 'static, + { + self.sync_rx.attach(None, f) + } +} diff --git a/src/collection.rs b/src/collection.rs index 40581ce..ce19f3c 100644 --- a/src/collection.rs +++ b/src/collection.rs @@ -1,5 +1,6 @@ use serde::Serialize; use std::slice::{Iter, IterMut}; +use std::vec; /// An ordered map. /// Internally this is just two vectors - @@ -47,6 +48,11 @@ impl Collection { } } + /// Checks if a value for the given key exists inside the collection + pub fn contains(&self, key: &TKey) -> bool { + self.keys.contains(key) + } + /// Removes the key/value from the collection /// if it exists /// and returns the removed value. @@ -144,3 +150,12 @@ impl Default for Collection { Self::new() } } + +impl IntoIterator for Collection { + type Item = TData; + type IntoIter = vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.values.into_iter() + } +} diff --git a/src/main.rs b/src/main.rs index 058e9ea..419ea78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod bar; +mod bridge_channel; mod collection; mod config; mod icon; @@ -11,16 +12,18 @@ mod sway; use crate::bar::create_bar; use crate::config::{Config, MonitorConfig}; use crate::style::load_css; -use crate::sway::{get_client, SwayOutput}; +use crate::sway::get_client; use color_eyre::eyre::Result; use color_eyre::Report; use dirs::config_dir; use gtk::gdk::Display; use gtk::prelude::*; use gtk::Application; -use ksway::IpcCommand; use std::env; +use std::future::Future; use std::process::exit; +use tokio::runtime::Handle; +use tokio::task::block_in_place; use crate::logging::install_tracing; use tracing::{debug, error, info}; @@ -48,14 +51,14 @@ async fn main() -> Result<()> { .build(); app.connect_activate(move |app| { - let display = match Display::default() { - Some(display) => display, - None => { + let display = Display::default().map_or_else( + || { let report = Report::msg("Failed to get default GTK display"); error!("{:?}", report); exit(1) - } - }; + }, + |display| display, + ); let config = match Config::load() { Ok(config) => config, @@ -66,21 +69,21 @@ async fn main() -> Result<()> { }; debug!("Loaded config file"); - if let Err(err) = create_bars(app, &display, &config) { + if let Err(err) = await_sync(create_bars(app, &display, &config)) { error!("{:?}", err); exit(2); } debug!("Created bars"); - let style_path = match config_dir() { - Some(dir) => dir.join("ironbar").join("style.css"), - None => { + let style_path = config_dir().map_or_else( + || { let report = Report::msg("Failed to locate user config dir"); error!("{:?}", report); exit(3); - } - }; + }, + |dir| dir.join("ironbar").join("style.css"), + ); if style_path.exists() { load_css(style_path); @@ -96,12 +99,12 @@ async fn main() -> Result<()> { } /// Creates each of the bars across each of the (configured) outputs. -fn create_bars(app: &Application, display: &Display, config: &Config) -> Result<()> { +async fn create_bars(app: &Application, display: &Display, config: &Config) -> Result<()> { let outputs = { - let sway = get_client(); - let mut sway = sway.lock().expect("Failed to get lock on Sway IPC client"); + let sway = get_client().await; + let mut sway = sway.lock().await; - let outputs = sway.ipc(IpcCommand::GetOutputs); + let outputs = sway.get_outputs().await; match outputs { Ok(outputs) => Ok(outputs), @@ -109,8 +112,6 @@ fn create_bars(app: &Application, display: &Display, config: &Config) -> Result< } }?; - let outputs = serde_json::from_slice::>(&outputs)?; - debug!("Received {} outputs from Sway IPC", outputs.len()); let num_monitors = display.n_monitors(); @@ -121,7 +122,7 @@ fn create_bars(app: &Application, display: &Display, config: &Config) -> Result< info!("Creating bar on '{}'", monitor_name); - // TODO: Could we use an Arc here to avoid cloning? + // TODO: Could we use an Arc or `Cow` here to avoid cloning? config.monitors.as_ref().map_or_else( || create_bar(app, &monitor, monitor_name, config.clone()), |config| { @@ -145,3 +146,15 @@ fn create_bars(app: &Application, display: &Display, config: &Config) -> Result< Ok(()) } + +/// Blocks on a `Future` until it resolves. +/// +/// This is not an `async` operation +/// so can be used outside of an async function. +/// +/// Do note it must be called from within a Tokio runtime still. +/// +/// Use sparingly! Prefer async functions wherever possible. +pub fn await_sync(f: F) -> F::Output { + block_in_place(|| Handle::current().block_on(f)) +} diff --git a/src/modules/clock.rs b/src/modules/clock.rs new file mode 100644 index 0000000..eedb9fa --- /dev/null +++ b/src/modules/clock.rs @@ -0,0 +1,114 @@ +use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext}; +use crate::popup::Popup; +use chrono::{DateTime, Local}; +use color_eyre::Result; +use glib::Continue; +use gtk::prelude::*; +use gtk::{Align, Button, Calendar, Label, Orientation}; +use serde::Deserialize; +use tokio::spawn; +use tokio::sync::mpsc; +use tokio::time::sleep; + +#[derive(Debug, Deserialize, Clone)] +pub struct ClockModule { + /// Date/time format string. + /// Default: `%d/%m/%Y %H:%M` + /// + /// Detail on available tokens can be found here: + /// + #[serde(default = "default_format")] + pub(crate) format: String, +} + +fn default_format() -> String { + String::from("%d/%m/%Y %H:%M") +} + +impl Module