status bar
git clone https://git.lucas.co/cce-status-interface.git
feat: add D-Bus status tray (system tray) support
Cargo.lock | 648 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Cargo.toml | 3 +
src/main.rs | 292 ++++++++++++++++++++++++++-
3 files changed, 917 insertions(+), 26 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 50c6683..da8327a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -25,12 +25,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if",
- "getrandom",
+ "getrandom 0.3.4",
"once_cell",
"version_check",
"zerocopy",
]
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "android-activity"
version = "0.6.1"
@@ -65,6 +74,12 @@ dependencies = [
"libc",
]
+[[package]]
+name = "anyhow"
+version = "1.0.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
+
[[package]]
name = "arrayref"
version = "0.3.9"
@@ -92,6 +107,79 @@ dependencies = [
"libloading",
]
+[[package]]
+name = "async-broadcast"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d26004fe83b2d1cd3a97609b21e39f9a31535822210fe83205d2ce48866ea61"
+dependencies = [
+ "event-listener",
+ "futures-core",
+ "parking_lot",
+]
+
+[[package]]
+name = "async-channel"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
+dependencies = [
+ "concurrent-queue",
+ "event-listener",
+ "futures-core",
+]
+
+[[package]]
+name = "async-executor"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a"
+dependencies = [
+ "async-task",
+ "concurrent-queue",
+ "fastrand",
+ "futures-lite",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "async-lock"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
+dependencies = [
+ "event-listener",
+]
+
+[[package]]
+name = "async-recursion"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "async-task"
+version = "4.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
+
+[[package]]
+name = "async-trait"
+version = "0.1.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
[[package]]
name = "atomic-waker"
version = "1.1.2"
@@ -172,9 +260,15 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
[[package]]
name = "bytes"
version = "1.11.1"
@@ -255,7 +349,9 @@ dependencies = [
"pollster",
"serde",
"serde_json",
+ "stray",
"tokio",
+ "tokio-stream",
"wgpu",
"winit",
]
@@ -395,6 +491,37 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
+[[package]]
+name = "derivative"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "dirs"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
[[package]]
name = "dispatch"
version = "0.2.0"
@@ -437,6 +564,27 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
+[[package]]
+name = "enumflags2"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
+dependencies = [
+ "enumflags2_derive",
+ "serde",
+]
+
+[[package]]
+name = "enumflags2_derive"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
[[package]]
name = "equivalent"
version = "1.0.2"
@@ -472,6 +620,18 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "event-listener"
+version = "2.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
+
+[[package]]
+name = "fastrand"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
+
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
@@ -534,7 +694,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -549,6 +709,31 @@ version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
+[[package]]
+name = "futures-io"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
+
+[[package]]
+name = "futures-lite"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
+dependencies = [
+ "fastrand",
+ "futures-core",
+ "futures-io",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
+
[[package]]
name = "futures-task"
version = "0.3.32"
@@ -562,6 +747,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-core",
+ "futures-sink",
"futures-task",
"pin-project-lite",
"slab",
@@ -577,6 +763,17 @@ dependencies = [
"windows-link",
]
+[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
[[package]]
name = "getrandom"
version = "0.3.4"
@@ -712,6 +909,12 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
[[package]]
name = "hexf-parse"
version = "0.2.1"
@@ -785,7 +988,7 @@ dependencies = [
"quote",
"rustc_version",
"simd_cesu8",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -813,7 +1016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
dependencies = [
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -822,7 +1025,7 @@ version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [
- "getrandom",
+ "getrandom 0.3.4",
"libc",
]
@@ -855,6 +1058,12 @@ version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
[[package]]
name = "libc"
version = "0.2.186"
@@ -952,6 +1161,24 @@ dependencies = [
"libc",
]
+[[package]]
+name = "memoffset"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
[[package]]
name = "metal"
version = "0.31.0"
@@ -1039,6 +1266,19 @@ dependencies = [
"jni-sys 0.3.1",
]
+[[package]]
+name = "nix"
+version = "0.23.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
+dependencies = [
+ "bitflags 1.3.2",
+ "cc",
+ "cfg-if",
+ "libc",
+ "memoffset 0.6.5",
+]
+
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -1064,10 +1304,10 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 3.5.0",
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -1307,6 +1547,16 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "ordered-stream"
+version = "0.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+]
+
[[package]]
name = "owned_ttf_parser"
version = "0.25.1"
@@ -1316,6 +1566,12 @@ dependencies = [
"ttf-parser 0.25.1",
]
+[[package]]
+name = "parking"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
+
[[package]]
name = "parking_lot"
version = "0.12.5"
@@ -1368,7 +1624,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -1409,19 +1665,38 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
[[package]]
name = "presser"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa"
+[[package]]
+name = "proc-macro-crate"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
+dependencies = [
+ "once_cell",
+ "toml_edit 0.19.15",
+]
+
[[package]]
name = "proc-macro-crate"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
dependencies = [
- "toml_edit",
+ "toml_edit 0.25.11+spec-1.1.0",
]
[[package]]
@@ -1463,6 +1738,36 @@ version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+[[package]]
+name = "rand"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.17",
+]
+
[[package]]
name = "range-alloc"
version = "0.1.5"
@@ -1538,6 +1843,46 @@ dependencies = [
"bitflags 2.11.1",
]
+[[package]]
+name = "redox_users"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+dependencies = [
+ "getrandom 0.2.17",
+ "libredox",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "regex"
+version = "1.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
+
[[package]]
name = "renderdoc-sys"
version = "1.1.0"
@@ -1693,7 +2038,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -1709,6 +2054,32 @@ dependencies = [
"zmij",
]
+[[package]]
+name = "serde_repr"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "sha1"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
+dependencies = [
+ "sha1_smol",
+]
+
+[[package]]
+name = "sha1_smol"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
+
[[package]]
name = "shlex"
version = "1.3.0"
@@ -1831,6 +2202,24 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+[[package]]
+name = "stray"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "358c1637c5ba4ccf1b6a0698de81454db644866cc426d1abc6d357b2efede511"
+dependencies = [
+ "anyhow",
+ "byteorder",
+ "chrono",
+ "log",
+ "serde",
+ "thiserror 1.0.69",
+ "tokio",
+ "tokio-stream",
+ "tracing",
+ "zbus",
+]
+
[[package]]
name = "strict-num"
version = "0.1.1"
@@ -1856,7 +2245,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -1876,6 +2265,17 @@ dependencies = [
"zeno",
]
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
[[package]]
name = "syn"
version = "2.0.117"
@@ -1896,6 +2296,19 @@ dependencies = [
"libc",
]
+[[package]]
+name = "tempfile"
+version = "3.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
+dependencies = [
+ "fastrand",
+ "getrandom 0.3.4",
+ "once_cell",
+ "rustix 1.1.4",
+ "windows-sys 0.61.2",
+]
+
[[package]]
name = "termcolor"
version = "1.4.1"
@@ -1931,7 +2344,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -1942,7 +2355,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -2010,9 +2423,26 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "tokio-stream"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
]
+[[package]]
+name = "toml_datetime"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
+
[[package]]
name = "toml_datetime"
version = "1.1.1+spec-1.1.0"
@@ -2022,6 +2452,17 @@ dependencies = [
"serde_core",
]
+[[package]]
+name = "toml_edit"
+version = "0.19.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
+dependencies = [
+ "indexmap",
+ "toml_datetime 0.6.11",
+ "winnow 0.5.40",
+]
+
[[package]]
name = "toml_edit"
version = "0.25.11+spec-1.1.0"
@@ -2029,9 +2470,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
dependencies = [
"indexmap",
- "toml_datetime",
+ "toml_datetime 1.1.1+spec-1.1.0",
"toml_parser",
- "winnow",
+ "winnow 1.0.3",
]
[[package]]
@@ -2040,7 +2481,7 @@ version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [
- "winnow",
+ "winnow 1.0.3",
]
[[package]]
@@ -2050,14 +2491,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"pin-project-lite",
+ "tracing-attributes",
"tracing-core",
]
+[[package]]
+name = "tracing-attributes"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
[[package]]
name = "tracing-core"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+]
[[package]]
name = "ttf-parser"
@@ -2077,6 +2533,17 @@ version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
+[[package]]
+name = "uds_windows"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
+dependencies = [
+ "memoffset 0.9.1",
+ "tempfile",
+ "windows-sys 0.61.2",
+]
+
[[package]]
name = "unicode-bidi"
version = "0.3.18"
@@ -2210,7 +2677,7 @@ dependencies = [
"bumpalo",
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
"wasm-bindgen-shared",
]
@@ -2461,6 +2928,22 @@ dependencies = [
"web-sys",
]
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
[[package]]
name = "winapi-util"
version = "0.1.11"
@@ -2470,6 +2953,12 @@ dependencies = [
"windows-sys 0.61.2",
]
+[[package]]
+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 = "windows"
version = "0.58.0"
@@ -2514,7 +3003,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -2525,7 +3014,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -2536,7 +3025,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -2547,7 +3036,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -2736,6 +3225,15 @@ dependencies = [
"xkbcommon-dl",
]
+[[package]]
+name = "winnow"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "winnow"
version = "1.0.3"
@@ -2820,6 +3318,70 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1"
+[[package]]
+name = "zbus"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d8f1a037b2c4a67d9654dc7bdfa8ff2e80555bbefdd3c1833c1d1b27c963a6b"
+dependencies = [
+ "async-broadcast",
+ "async-channel",
+ "async-executor",
+ "async-lock",
+ "async-recursion",
+ "async-task",
+ "async-trait",
+ "byteorder",
+ "derivative",
+ "dirs",
+ "enumflags2",
+ "event-listener",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "hex",
+ "lazy_static",
+ "nix",
+ "once_cell",
+ "ordered-stream",
+ "rand",
+ "serde",
+ "serde_repr",
+ "sha1",
+ "static_assertions",
+ "tokio",
+ "tracing",
+ "uds_windows",
+ "winapi",
+ "zbus_macros",
+ "zbus_names",
+ "zvariant",
+]
+
+[[package]]
+name = "zbus_macros"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f8fb5186d1c87ae88cf234974c240671238b4a679158ad3b94ec465237349a6"
+dependencies = [
+ "proc-macro-crate 1.3.1",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "zbus_names"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d"
+dependencies = [
+ "serde",
+ "static_assertions",
+ "zvariant",
+]
+
[[package]]
name = "zeno"
version = "0.2.3"
@@ -2843,7 +3405,7 @@ checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.117",
]
[[package]]
@@ -2851,3 +3413,41 @@ name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+
+[[package]]
+name = "zvariant"
+version = "3.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db"
+dependencies = [
+ "byteorder",
+ "enumflags2",
+ "libc",
+ "serde",
+ "static_assertions",
+ "zvariant_derive",
+]
+
+[[package]]
+name = "zvariant_derive"
+version = "3.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9"
+dependencies = [
+ "proc-macro-crate 1.3.1",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+ "zvariant_utils",
+]
+
+[[package]]
+name = "zvariant_utils"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 9d204d6..902cea7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,3 +14,6 @@ tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
chrono = "0.4"
+stray = "0.1"
+tokio-stream = "0.1"
+
diff --git a/src/main.rs b/src/main.rs
index feab439..cf34851 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
use std::sync::Arc;
+use std::collections::HashMap;
use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop, EventLoopProxy};
@@ -9,6 +10,36 @@ use glyphon::{
TextAtlas, TextBounds, TextRenderer, Viewport,
};
use clear_ui::color;
+use stray::StatusNotifierWatcher;
+use stray::message::NotifierItemMessage;
+
+#[derive(Debug, Clone)]
+struct TrayPixmap {
+ width: i32,
+ height: i32,
+ pixels: Vec<u8>,
+}
+
+#[allow(dead_code)]
+#[derive(Debug, Clone)]
+struct TrayItem {
+ id: String,
+ icon_name: Option<String>,
+ icon_theme_path: Option<String>,
+ pixmaps: Option<Vec<TrayPixmap>>,
+ title: Option<String>,
+}
+
+
+#[derive(Debug, Clone)]
+struct TrayIconBounds {
+ id: String,
+ x: f32,
+ y: f32,
+ w: f32,
+ h: f32,
+ title: Option<String>,
+}
#[derive(Debug, Clone)]
struct SystemStats {
@@ -24,8 +55,11 @@ enum CustomEvent {
LayoutUpdated(String),
TitleUpdated(String),
SystemStatsUpdated(SystemStats),
+ TrayUpdated(TrayItem),
+ TrayRemoved(String),
}
+
#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
struct Vertex {
@@ -193,6 +227,10 @@ struct StatusApp {
layout: String,
title: String,
stats: Option<SystemStats>,
+ tray_items: HashMap<String, TrayItem>,
+ cursor_pos: (f64, f64),
+ hovered_tray_item: Option<String>,
+ tray_item_bounds: Vec<TrayIconBounds>,
font_system: FontSystem,
swash_cache: SwashCache,
@@ -299,12 +337,17 @@ impl StatusApp {
layout: String::new(),
title: String::new(),
stats: None,
+ tray_items: HashMap::new(),
+ cursor_pos: (0.0, 0.0),
+ hovered_tray_item: None,
+ tray_item_bounds: Vec::new(),
font_system, swash_cache, text_atlas, text_renderer, text_viewport,
rects: Vec::new(), text_items: Vec::new(),
scale_factor,
width: size.width, height: size.height,
needs_rebuild: true,
};
+
app.rebuild_layout();
app
}
@@ -391,9 +434,8 @@ impl StatusApp {
}
// 5. Right Side Stats (CPU, Mem, Bat, Clock)
+ let mut right_x = sw - 12.0 * s;
if let Some(ref stats) = self.stats {
- let mut right_x = sw - 12.0 * s;
-
// Clock
let buf = make_text_buffer(&mut self.font_system, &stats.clock, 11.0 * s);
let w = buf.layout_runs().next().map(|r| r.line_w).unwrap_or(0.0);
@@ -460,6 +502,146 @@ impl StatusApp {
});
}
+ // 5b. System Tray Icons (render to the left of the CPU/stats block)
+ self.tray_item_bounds.clear();
+ if !self.tray_items.is_empty() {
+ right_x -= 16.0 * s; // Separator padding
+ let mut sorted_tray: Vec<&TrayItem> = self.tray_items.values().collect();
+ sorted_tray.sort_by_key(|item| &item.id);
+
+ for item in sorted_tray.iter().rev() {
+ let icon_size = 16.0 * s;
+ right_x -= icon_size;
+ let x = right_x;
+ let y = (bar_h - icon_size) / 2.0;
+
+ // Record bounds for hit-testing
+ self.tray_item_bounds.push(TrayIconBounds {
+ id: item.id.clone(),
+ x,
+ y,
+ w: icon_size,
+ h: icon_size,
+ title: item.title.clone(),
+ });
+
+ // Attempt to draw pixmap
+ let mut drawn_pixmap = false;
+ if let Some(ref pixmaps) = item.pixmaps {
+ if !pixmaps.is_empty() {
+ // Find pixmap closest to 16 pixels wide
+ if let Some(pixmap) = pixmaps.iter().min_by_key(|p| (p.width - 16).abs()) {
+ if pixmap.width > 0 && pixmap.height > 0 {
+ let pixel_w = icon_size / pixmap.width as f32;
+ let pixel_h = icon_size / pixmap.height as f32;
+ for row in 0..pixmap.height {
+ for col in 0..pixmap.width {
+ let idx = ((row * pixmap.width + col) * 4) as usize;
+ if idx + 3 < pixmap.pixels.len() {
+ let a = pixmap.pixels[idx] as f32 / 255.0;
+ if a > 0.0 {
+ let r = pixmap.pixels[idx + 1] as f32 / 255.0;
+ let g = pixmap.pixels[idx + 2] as f32 / 255.0;
+ let b = pixmap.pixels[idx + 3] as f32 / 255.0;
+ self.rects.push(RectWidget {
+ x: x + col as f32 * pixel_w,
+ y: y + row as f32 * pixel_h,
+ w: pixel_w,
+ h: pixel_h,
+ color: [r, g, b, a],
+ });
+ }
+ }
+ }
+ }
+ drawn_pixmap = true;
+ }
+ }
+ }
+ }
+
+ // Fallback to text icon symbol
+ if !drawn_pixmap {
+ let symbol = if let Some(ref name) = item.icon_name {
+ let name_lower = name.to_lowercase();
+ if name_lower.contains("volume") || name_lower.contains("sound") || name_lower.contains("audio") {
+ if name_lower.contains("mute") { "🔇" } else { "🔊" }
+ } else if name_lower.contains("wifi") || name_lower.contains("network") || name_lower.contains("ethernet") {
+ "📶"
+ } else if name_lower.contains("battery") {
+ "🔋"
+ } else if name_lower.contains("bluetooth") {
+ "á›’"
+ } else if name_lower.contains("mail") || name_lower.contains("envelope") {
+ "✉"
+ } else if name_lower.contains("chat") || name_lower.contains("messenger") || name_lower.contains("discord") || name_lower.contains("slack") || name_lower.contains("telegram") {
+ "💬"
+ } else if name_lower.contains("steam") || name_lower.contains("game") {
+ "🎮"
+ } else {
+ "âš™"
+ }
+ } else {
+ "âš™"
+ };
+
+ let buf = make_text_buffer(&mut self.font_system, symbol, 11.0 * s);
+ let tw = buf.layout_runs().next().map(|r| r.line_w).unwrap_or(0.0);
+ let tx = x + (icon_size - tw) / 2.0;
+ let ty = y + (icon_size - 11.0 * s * 1.4) / 2.0;
+ self.text_items.push(TextItem {
+ buffer: buf,
+ x: tx,
+ y: ty,
+ color: glyphon::Color::rgb(
+ (color::TEXT_ACCENT[0] * 255.0) as u8,
+ (color::TEXT_ACCENT[1] * 255.0) as u8,
+ (color::TEXT_ACCENT[2] * 255.0) as u8,
+ ),
+ });
+ }
+
+ right_x -= 8.0 * s; // Gap between icons
+ }
+ }
+
+ // 5c. Tooltip Rendering (if hovered)
+ if let Some(ref hovered_id) = self.hovered_tray_item {
+ if let Some(bound) = self.tray_item_bounds.iter().find(|b| &b.id == hovered_id) {
+ let tooltip_text = bound.title.as_deref().unwrap_or(bound.id.as_str());
+ let font_size = 10.0 * s;
+ let buf = make_text_buffer(&mut self.font_system, tooltip_text, font_size);
+ let text_w = buf.layout_runs().next().map(|r| r.line_w).unwrap_or(0.0);
+ let padding = 6.0 * s;
+
+ let tooltip_w = text_w + padding * 2.0;
+ let tooltip_h = font_size * 1.4 + padding * 2.0;
+ let tx = bound.x + (bound.w - tooltip_w) / 2.0;
+ let ty = bar_h + 4.0 * s;
+
+ // Tooltip background
+ self.rects.push(RectWidget {
+ x: tx,
+ y: ty,
+ w: tooltip_w,
+ h: tooltip_h,
+ color: [0.08, 0.08, 0.12, 0.95],
+ });
+
+ // Tooltip text
+ self.text_items.push(TextItem {
+ buffer: buf,
+ x: tx + padding,
+ y: ty + padding,
+ color: glyphon::Color::rgb(
+ (color::TEXT_FG[0] * 255.0) as u8,
+ (color::TEXT_FG[1] * 255.0) as u8,
+ (color::TEXT_FG[2] * 255.0) as u8,
+ ),
+ });
+ }
+ }
+
self.needs_rebuild = false;
}
@@ -607,6 +789,28 @@ impl ApplicationHandler<CustomEvent> for AppWrapper {
}
true
}
+ WindowEvent::CursorMoved { position, .. } => {
+ if let Some(st) = &mut self.state {
+ let cx = position.x / st.scale_factor;
+ let cy = position.y / st.scale_factor;
+ st.cursor_pos = (cx, cy);
+
+ let mut newly_hovered = None;
+ for bound in &st.tray_item_bounds {
+ if cx >= bound.x as f64 && cx <= (bound.x + bound.w) as f64
+ && cy >= bound.y as f64 && cy <= (bound.y + bound.h) as f64 {
+ newly_hovered = Some(bound.id.clone());
+ break;
+ }
+ }
+ if st.hovered_tray_item != newly_hovered {
+ st.hovered_tray_item = newly_hovered;
+ st.needs_rebuild = true;
+ st.window.request_redraw();
+ }
+ }
+ true
+ }
_ => false,
};
if redraw {
@@ -616,6 +820,7 @@ impl ApplicationHandler<CustomEvent> for AppWrapper {
}
}
+
fn user_event(&mut self, _event_loop: &ActiveEventLoop, event: CustomEvent) {
if let Some(ref mut st) = self.state {
match event {
@@ -631,11 +836,18 @@ impl ApplicationHandler<CustomEvent> for AppWrapper {
CustomEvent::SystemStatsUpdated(s) => {
st.stats = Some(s);
}
+ CustomEvent::TrayUpdated(item) => {
+ st.tray_items.insert(item.id.clone(), item);
+ }
+ CustomEvent::TrayRemoved(id) => {
+ st.tray_items.remove(&id);
+ }
}
st.needs_rebuild = true;
st.window.request_redraw();
}
}
+
}
async fn spawn_status_listener(sub: &'static str, proxy: EventLoopProxy<CustomEvent>) {
@@ -698,6 +910,58 @@ async fn spawn_system_stats(proxy: EventLoopProxy<CustomEvent>) {
}
}
+async fn spawn_status_tray(
+ proxy: EventLoopProxy<CustomEvent>,
+ cmd_rx: tokio::sync::mpsc::Receiver<stray::message::NotifierItemCommand>,
+) {
+ let watcher = match StatusNotifierWatcher::new(cmd_rx).await {
+ Ok(w) => w,
+ Err(e) => {
+ eprintln!("Failed to create StatusNotifierWatcher: {:?}", e);
+ return;
+ }
+ };
+ let mut host = match watcher.create_notifier_host("clear-status-bar").await {
+ Ok(h) => h,
+ Err(e) => {
+ eprintln!("Failed to create NotifierHost: {:?}", e);
+ return;
+ }
+ };
+ loop {
+ match host.recv().await {
+ Ok(msg) => match msg {
+ NotifierItemMessage::Update { address, item, menu: _ } => {
+ let pixmaps = item.icon_pixmap.map(|v| {
+ v.into_iter()
+ .map(|p| TrayPixmap {
+ width: p.width,
+ height: p.height,
+ pixels: p.pixels,
+ })
+ .collect()
+ });
+ let tray_item = TrayItem {
+ id: address.clone(),
+ icon_name: item.icon_name,
+ icon_theme_path: item.icon_theme_path,
+ pixmaps,
+ title: item.title,
+ };
+ let _ = proxy.send_event(CustomEvent::TrayUpdated(tray_item));
+ }
+ NotifierItemMessage::Remove { address } => {
+ let _ = proxy.send_event(CustomEvent::TrayRemoved(address));
+ }
+ },
+ Err(e) => {
+ eprintln!("Tray host recv error: {:?}", e);
+ tokio::time::sleep(std::time::Duration::from_secs(2)).await;
+ }
+ }
+ }
+}
+
fn main() {
let event_loop = EventLoop::<CustomEvent>::with_user_event().build().unwrap();
event_loop.set_control_flow(ControlFlow::Wait);
@@ -706,6 +970,9 @@ fn main() {
let proxy_layout = event_loop.create_proxy();
let proxy_title = event_loop.create_proxy();
let proxy_stats = event_loop.create_proxy();
+ let proxy_tray = event_loop.create_proxy();
+
+ let (_cmd_tx, cmd_rx) = tokio::sync::mpsc::channel(32);
// Spawn Tokio Runtime for async listeners
std::thread::spawn(move || {
@@ -715,6 +982,7 @@ fn main() {
tokio::spawn(spawn_status_listener("layout", proxy_layout));
tokio::spawn(spawn_status_listener("title", proxy_title));
tokio::spawn(spawn_system_stats(proxy_stats));
+ tokio::spawn(spawn_status_tray(proxy_tray, cmd_rx));
// Keep the runtime thread alive
loop {
@@ -726,3 +994,23 @@ fn main() {
let mut wrapper = AppWrapper { state: None };
event_loop.run_app(&mut wrapper).unwrap();
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+