Inline some clones to make code more readable, add config, implement dimming -> locking -> sleeping into idle daemon, fix waiting on network thread, implement run menu with application launching and math evaluation,
This commit is contained in:
285
Cargo.lock
generated
285
Cargo.lock
generated
@@ -377,9 +377,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-rs"
|
||||
version = "1.18.2"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "faac5829c2b74c28f830747e7818ccfb684261b5f48a1118b1e2a13d36dfab13"
|
||||
checksum = "048006790404103c488e6c5616b3e7e702a71292aadda08e8f7698a9e0d2eb53"
|
||||
dependencies = [
|
||||
"aws-lc-sys",
|
||||
"untrusted 0.7.1",
|
||||
@@ -388,9 +388,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-sys"
|
||||
version = "0.46.0"
|
||||
version = "0.47.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1622d8446a2d4b2ce0c7eefc73dd43a99779028d5ee5c2dd8073a658ba8a2bc"
|
||||
checksum = "8bfbe32ac36b3c428696ce315464181bc4029d689fd58e3f2a4e58c252242f52"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cmake",
|
||||
@@ -550,6 +550,12 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.12.1"
|
||||
@@ -607,6 +613,17 @@ dependencies = [
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.20.3"
|
||||
@@ -1029,9 +1046,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crypto-bigint"
|
||||
version = "0.7.7"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc907c45bb7e9ef8fc3778defd0f3cd8c81288f1b4e748eba064948f20c47122"
|
||||
checksum = "9c035cb64cba03dad2fb921f3e218785e8cf9a41790da5eb3a1400f62fa2be11"
|
||||
dependencies = [
|
||||
"cpubits",
|
||||
"ctutils",
|
||||
@@ -1076,9 +1093,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ctutils"
|
||||
version = "0.4.5"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d28fb6aa7dd680b3ffd1a3e64e115c177bdba63c0ae7f9cd48129ff05c4fa0"
|
||||
checksum = "a2376ffd6f96d8a9db59875b4b6b0237d6900b5baf64279714e05493ce64828a"
|
||||
dependencies = [
|
||||
"cmov",
|
||||
"subtle",
|
||||
@@ -1242,9 +1259,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a878c850e9e421b20262e9b41f9c860e4785fa07541c266b62ff9d1ef998a80a"
|
||||
checksum = "6a996a108feb8b427a6e12fcf6af4aa83409b79d72c15337d7741368131ee004"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"pem-rfc7468",
|
||||
@@ -1417,7 +1434,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "edid"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/jmb05/rust-edid#509d792617f521ea3797b70b547ac64a5fa35935"
|
||||
source = "git+https://github.com/jmb05/rust-edid#ab42e7fa8139b35ace725dad55ef8e698d4feb52"
|
||||
dependencies = [
|
||||
"nom 8.0.0",
|
||||
]
|
||||
@@ -1430,9 +1447,9 @@ checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be"
|
||||
|
||||
[[package]]
|
||||
name = "elliptic-curve"
|
||||
version = "0.14.2"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ad4496221fcfc21015fd8c0e26fcfab00504832dc0604f52acdd7bad2a8dc81"
|
||||
checksum = "900f37e7e18d74a2347389af6cd69e3a30d5cc9e697f40004865679aa75e9c7c"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"crypto-bigint",
|
||||
@@ -1458,9 +1475,9 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.42"
|
||||
version = "0.8.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679"
|
||||
checksum = "89253175e704ab869b04f9db224d38630e0211a53841a79181deae0889e169f5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"core_detect",
|
||||
@@ -1678,6 +1695,21 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "freedesktop-desktop-entry"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42a69ad6111a2b572cb41e0f3542d546386e841013cee7c45d705b61a15a87dd"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gettext-rs",
|
||||
"log",
|
||||
"memchr",
|
||||
"thiserror 2.0.21",
|
||||
"unicase",
|
||||
"xdg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs_extra"
|
||||
version = "1.3.0"
|
||||
@@ -1897,6 +1929,26 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gettext-rs"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9df5e3fa8c077b15fdfa8ce130e2bc73d663b8aaa6d51b71421b8659980b1d80"
|
||||
dependencies = [
|
||||
"gettext-sys",
|
||||
"locale_config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gettext-sys"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4caa7e4460b196107cc1bb2629488e8b6dbb7f34f6683ea6753c4ac22f590785"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"temp-dir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ghash"
|
||||
version = "0.6.0"
|
||||
@@ -2415,8 +2467,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyprland"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/romanstingler/hyprland-rs-next?branch=master#80c1fc217c77873dc9f76c64419d1ed568410c06"
|
||||
version = "0.7.0"
|
||||
source = "git+https://github.com/romanstingler/hyprland-rs-next?branch=master#7c2f69f8be78d89b58720bce7cad03b82e99baa3"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"chardetng",
|
||||
@@ -2434,8 +2486,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyprland-macros"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/romanstingler/hyprland-rs-next?branch=master#80c1fc217c77873dc9f76c64419d1ed568410c06"
|
||||
version = "0.7.0"
|
||||
source = "git+https://github.com/romanstingler/hyprland-rs-next?branch=master#7c2f69f8be78d89b58720bce7cad03b82e99baa3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2487,7 +2539,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.61.2",
|
||||
"windows-core 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2709,6 +2761,7 @@ dependencies = [
|
||||
"crossbeam-channel",
|
||||
"ddc-hi",
|
||||
"eventfd",
|
||||
"freedesktop-desktop-entry",
|
||||
"futures-util",
|
||||
"glib",
|
||||
"glib-build-tools",
|
||||
@@ -2723,15 +2776,19 @@ dependencies = [
|
||||
"jmb-logger-rs",
|
||||
"libc",
|
||||
"libpulse-binding",
|
||||
"meval",
|
||||
"mpris",
|
||||
"nmrs",
|
||||
"notify",
|
||||
"nucleo-matcher",
|
||||
"rustsni",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sysinfo 0.40.0",
|
||||
"sysinfo 0.40.1",
|
||||
"thiserror 2.0.21",
|
||||
"time-format",
|
||||
"tokio",
|
||||
"toml",
|
||||
"wayland-client",
|
||||
"wayland-protocols",
|
||||
"zbus",
|
||||
@@ -2807,9 +2864,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.106"
|
||||
version = "0.3.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5"
|
||||
checksum = "8dc09d2154098bbf4ef54eab6b117a3c24cbbffe94046b16ee6d6d4510584d3a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
@@ -2982,6 +3039,19 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4744e383959f0db86ede514b809b1c53251889093803c05267acc7d4e7030d70"
|
||||
|
||||
[[package]]
|
||||
name = "locale_config"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
"regex",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.14"
|
||||
@@ -2993,9 +3063,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.34"
|
||||
version = "0.4.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
|
||||
checksum = "5d15f86d12da44cd8d4ec3c73984537eb7f4cadcb9776a575a0a8a05ca11005c"
|
||||
|
||||
[[package]]
|
||||
name = "lru-slab"
|
||||
@@ -3079,6 +3149,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.2.0"
|
||||
@@ -3179,6 +3258,16 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "meval"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f79496a5651c8d57cd033c5add8ca7ee4e3d5f7587a4777484640d9cb60392d9"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"nom 1.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
@@ -3352,6 +3441,12 @@ dependencies = [
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "1.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@@ -3417,6 +3512,16 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nucleo-matcher"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf33f538733d1a5a3494b836ba913207f14d9d4a1d3cd67030c5061bdd2cac85"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.5.1"
|
||||
@@ -3525,6 +3630,26 @@ dependencies = [
|
||||
"libloading 0.8.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||
dependencies = [
|
||||
"malloc_buf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-foundation"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||
dependencies = [
|
||||
"block",
|
||||
"objc",
|
||||
"objc_id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2"
|
||||
version = "0.6.5"
|
||||
@@ -3601,6 +3726,15 @@ dependencies = [
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc_id"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||
dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
@@ -3615,9 +3749,9 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
|
||||
checksum = "7e036b411754132fd6b74e94b74e9a13c5cf606fa93d1885c35860d3060820b1"
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
@@ -3678,9 +3812,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pageant"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0786409b5aaa884655c9b4065681db0835db0cc185a6fb19fb17a5d38656866"
|
||||
checksum = "e0bc922d9aa8cfcf598de27b3c6122cb2eeda9d6fe71527a22ebcb7f633540ff"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"byteorder",
|
||||
@@ -4242,9 +4376,9 @@ checksum = "263a3f48f01e7309e857138bd47f785585b4a005e8e56c6d2824ce91195999c3"
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.13.5"
|
||||
version = "0.13.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "278e9268c93b9e498a2da46c34d90ba93a3255eb99009646398f34bc73ab36eb"
|
||||
checksum = "3db2be46835f013dd3f4fa7f5f7402c537787b54ebb6fe2b94bbdd7e2669bb7b"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"memchr",
|
||||
@@ -4707,9 +4841,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.5"
|
||||
version = "1.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d"
|
||||
checksum = "e5e76742e5294153d4dde1207dbec5bdd81eef6fabdc0d2118babadabfd858aa"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"errno",
|
||||
@@ -5353,9 +5487,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.40.0"
|
||||
version = "0.40.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "110e37d98880fd804cd47509b90a8444f7aaaab655ae625e83cd442a8bc2ebf2"
|
||||
checksum = "0e8a3edbe0394ce115f3917a00349dd242be09eb5a091ed509eaf67b55cfb8a8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"memchr",
|
||||
@@ -5430,6 +5564,12 @@ version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
||||
|
||||
[[package]]
|
||||
name = "temp-dir"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83176759e9416cf81ee66cb6508dbfe9c96f20b8b56265a39917551c23c70964"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.27.0"
|
||||
@@ -5660,9 +5800,9 @@ checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770"
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.14.6"
|
||||
version = "0.14.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef"
|
||||
checksum = "e2cdfc673aabd30fe8fee92e65837b644c37c5d47f0f97ae6d5e0f1237d15e1b"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
@@ -5681,6 +5821,7 @@ dependencies = [
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
@@ -5689,9 +5830,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tonic-build"
|
||||
version = "0.14.6"
|
||||
version = "0.14.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c68f61875ac5293cf72e6c8cf0158086428c82c37229e98c840878f1706b0322"
|
||||
checksum = "ac6d916d206ed7bdda1778ddff9bda43303789c258877e7bc22fb44ee5c984b4"
|
||||
dependencies = [
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
@@ -5701,9 +5842,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tonic-prost"
|
||||
version = "0.14.6"
|
||||
version = "0.14.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0"
|
||||
checksum = "eba464054e2226f182a34489b8b079bf4c6e3e7ab5fd7fc30e024f24aa92a484"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost 0.14.4",
|
||||
@@ -5712,9 +5853,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tonic-prost-build"
|
||||
version = "0.14.6"
|
||||
version = "0.14.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "654e5643eff75d7f8c99197ce1440ed19a3474eada74c12bbac488b2cafdae27"
|
||||
checksum = "2ea216ddc448e08e7839ab09e20e60b06b6a1c32745ccb212c0ebd161c199f1b"
|
||||
dependencies = [
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
@@ -5920,9 +6061,9 @@ checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.2"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||
checksum = "ca718471876992059f251e33aafc334346ada08042b7661dd1fe313a9bced557"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
@@ -5988,9 +6129,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
checksum = "af3bd9d3e571c26fcce9d033b87ea5ab061b8d2ffe9b7a5675d810d68f03edf0"
|
||||
dependencies = [
|
||||
"utf_types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
@@ -5998,6 +6142,12 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "utf_types"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a3b425286980a367278453f3b6d28cdcb134b574e5a35824a6ff5eebad50bb6"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.29.0"
|
||||
@@ -6089,12 +6239,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.129"
|
||||
version = "0.2.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409"
|
||||
checksum = "a0181c14ddd6c7b8b0b0132a5f1ea2f32be0d893cd3ea97b6e3b28886b8a3d1c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-shared",
|
||||
@@ -6102,9 +6251,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.79"
|
||||
version = "0.4.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cbab34de2d982e9b48e18d216d04c4a6f641066ff19ffb699980f591ee3610e"
|
||||
checksum = "5e14e0327cb5368ad60ccb22d04a9827a693c95a926d8d125e9fa39e0baec501"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"tokio",
|
||||
@@ -6113,9 +6262,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.129"
|
||||
version = "0.2.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535"
|
||||
checksum = "6e931a02a39abdbf66966fc35902b5ed58344750a70885bed4ebb3d8eaf28ed9"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -6123,9 +6272,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.129"
|
||||
version = "0.2.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7"
|
||||
checksum = "2ca4b54280e455bd831e33a6b8e734baf432fe63fbc35c42ac14ce67a043a53a"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
@@ -6136,9 +6285,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.129"
|
||||
version = "0.2.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6"
|
||||
checksum = "3b1f9c3798725016c6ee5f2f57869ec0831e8bbc0ab0310a86e787e97f41389e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -6202,9 +6351,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.106"
|
||||
version = "0.3.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4"
|
||||
checksum = "d7d179596ff5ec0f6de4db64d54011bde6289cc49603d3a6e4ce3f329207ab88"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -6684,7 +6833,7 @@ dependencies = [
|
||||
"serde",
|
||||
"thiserror 2.0.21",
|
||||
"windows 0.62.2",
|
||||
"windows-core 0.61.2",
|
||||
"windows-core 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6719,14 +6868,20 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.6.1"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
|
||||
checksum = "963d6fab92d5504b971dc8bd90ca743c2575e590bc8071ea5bc571598667ae08"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xdg"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.29"
|
||||
@@ -6819,9 +6974,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zcheapstr"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1afec51604565183aeb5c54c20aeab286120d4e4460f7f76e3e8bb8c0d99473"
|
||||
checksum = "939f186d9ecebe044315a5cb6d6f78568bbc21152adc954d5a0c2f58bdbc9920"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -43,6 +43,11 @@ ddc-hi = { git = "https://github.com/jmb05/ddc-hi-rs" }
|
||||
wayland-protocols = { version = "0.32.13", features = ["staging", "client"] }
|
||||
wayland-client = "0.31.15"
|
||||
zbus = "5.19.0"
|
||||
serde = { version = "1.0.229", features = ["derive"] }
|
||||
freedesktop-desktop-entry = "0.8.4"
|
||||
nucleo-matcher = "0.3.1"
|
||||
meval = "0.2.0"
|
||||
toml = "1.1.8"
|
||||
#zbus = "6.1.0"
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
4
jmb-bar.conf
Normal file
4
jmb-bar.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
idle_timeout = 20
|
||||
dim_timeout = 60
|
||||
lock_timeout = 300
|
||||
sleep_timeout = 320
|
||||
@@ -1,12 +1,13 @@
|
||||
use crate::backend::{BackendThread, Registrator};
|
||||
use crate::config::Config;
|
||||
use crate::{APP_NAME, LOGGER};
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use jmb_logger_rs::*;
|
||||
use nmrs::raw::zbus::interface;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::process::Command;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::time::Duration;
|
||||
use tokio::sync::watch;
|
||||
use tokio::time::sleep;
|
||||
use wayland_client::globals::registry_queue_init;
|
||||
@@ -17,12 +18,11 @@ use wayland_protocols::ext::idle_notify::v1::client::ext_idle_notification_v1::{
|
||||
Event, ExtIdleNotificationV1,
|
||||
};
|
||||
use wayland_protocols::ext::idle_notify::v1::client::ext_idle_notifier_v1::ExtIdleNotifierV1;
|
||||
use zbus::conn::Builder;
|
||||
use zbus::interface;
|
||||
use zbus::message::Header;
|
||||
|
||||
const SERVICE: &str = "org.freedesktop.ScreenSaver";
|
||||
const OBJECT_PATH: &str = "/org/freedesktop/ScreenSaver";
|
||||
const LEGACY_OBJECT_PATH: &str = "/ScreenSaver";
|
||||
|
||||
struct WlState {
|
||||
idle: Option<bool>,
|
||||
@@ -53,14 +53,8 @@ impl Dispatch<ExtIdleNotificationV1, ()> for WlState {
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
match event {
|
||||
Event::Idled => {
|
||||
println!("Idled: {:?}", Instant::now());
|
||||
state.idle = Some(true);
|
||||
}
|
||||
Event::Resumed => {
|
||||
println!("Resumed: {:?}", Instant::now());
|
||||
state.idle = Some(false);
|
||||
}
|
||||
Event::Idled => state.idle = Some(true),
|
||||
Event::Resumed => state.idle = Some(false),
|
||||
_ => {}
|
||||
}
|
||||
if let Some(idle) = state.idle {
|
||||
@@ -85,15 +79,15 @@ impl Dispatch<ExtIdleNotifierV1, (), WlState> for WlState {
|
||||
struct Inhibitor {
|
||||
owner: String,
|
||||
application: String,
|
||||
_reason: String,
|
||||
reason: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum IdleState {
|
||||
Init(Sender<IdleMessage>),
|
||||
Dimmed,
|
||||
Inhibited,
|
||||
Caffeine,
|
||||
Inhibited(bool),
|
||||
Caffeine(bool),
|
||||
Active,
|
||||
}
|
||||
|
||||
@@ -128,73 +122,92 @@ impl BackendThread<IdleState, Sender<IdleMessage>> for IdleDaemon {
|
||||
}
|
||||
|
||||
fn init(registration_rx: Receiver<Sender<IdleState>>) {
|
||||
let config = Config::load();
|
||||
let (tx, rx) = crossbeam_channel::unbounded::<IdleMessage>();
|
||||
let tx_clone = tx.clone();
|
||||
let instance = Arc::new(Mutex::new(Self {
|
||||
subscribers: Vec::new(),
|
||||
}));
|
||||
let instance_clone = instance.clone();
|
||||
std::thread::spawn(move || {
|
||||
while let Ok(sender) = registration_rx.recv() {
|
||||
if sender.send(IdleState::Init(tx_clone.clone())).is_ok() {
|
||||
trace!(&LOGGER, "Added IdleDaemon Subscriber");
|
||||
instance_clone
|
||||
.lock()
|
||||
.expect("Couldn't get lock")
|
||||
.subscribers
|
||||
.push(sender);
|
||||
std::thread::spawn({
|
||||
let instance = instance.clone();
|
||||
let tx = tx.clone();
|
||||
move || {
|
||||
while let Ok(sender) = registration_rx.recv() {
|
||||
if sender.send(IdleState::Init(tx.clone())).is_ok() {
|
||||
trace!(&LOGGER, "Added IdleDaemon Subscriber");
|
||||
instance
|
||||
.lock()
|
||||
.expect("Couldn't get lock")
|
||||
.subscribers
|
||||
.push(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let (wl_tx, wl_rx) = watch::channel(false);
|
||||
let (dbus_tx, dbus_rx) = watch::channel((false, false));
|
||||
std::thread::spawn(move || {
|
||||
if let Err(err) = Self::start_idle_notifier(wl_tx) {
|
||||
error!(&LOGGER, "Idle Daemon unexpectedly quit, reason: {err}");
|
||||
let (dbus_tx, dbus_rx) = watch::channel(false);
|
||||
std::thread::spawn({
|
||||
let config = config.clone();
|
||||
move || {
|
||||
if let Err(err) = Self::start_idle_notifier(wl_tx, &config) {
|
||||
error!(&LOGGER, "Idle Daemon unexpectedly quit, reason: {err}");
|
||||
}
|
||||
}
|
||||
});
|
||||
std::thread::spawn(move || {
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Failed to create Tokio runtime");
|
||||
runtime.block_on(async move {
|
||||
let mut idle_inhibitor = None;
|
||||
while let Ok(msg) = rx.recv() {
|
||||
match msg {
|
||||
IdleMessage::Inhibit => {
|
||||
if idle_inhibitor.is_none()
|
||||
&& let Ok(ii) = IdleInhibitor::inhibit_idle().await
|
||||
{
|
||||
idle_inhibitor = Some(ii);
|
||||
std::thread::spawn({
|
||||
let instance = instance.clone();
|
||||
move || {
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Failed to create Tokio runtime");
|
||||
runtime.block_on(async move {
|
||||
let mut idle_inhibitor = None;
|
||||
while let Ok(msg) = rx.recv() {
|
||||
match msg {
|
||||
IdleMessage::Inhibit => {
|
||||
if idle_inhibitor.is_none()
|
||||
&& let Ok(ii) = IdleInhibitor::inhibit_idle().await
|
||||
{
|
||||
instance.lock().unwrap().publish(IdleState::Caffeine(true));
|
||||
idle_inhibitor = Some(ii);
|
||||
}
|
||||
}
|
||||
}
|
||||
IdleMessage::Release => {
|
||||
if let Some(ii) = idle_inhibitor.take()
|
||||
&& let Err(e) = ii.uninhibit_idle().await
|
||||
{
|
||||
warn!(&LOGGER, "Error uninhibiting {e}");
|
||||
IdleMessage::Release => {
|
||||
if let Some(ii) = idle_inhibitor.take() {
|
||||
match ii.uninhibit_idle().await {
|
||||
Ok(_) => {
|
||||
instance
|
||||
.lock()
|
||||
.unwrap()
|
||||
.publish(IdleState::Caffeine(false));
|
||||
}
|
||||
Err(e) => warn!(&LOGGER, "Error uninhibiting {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
std::thread::spawn(move || {
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Failed to create Tokio runtime");
|
||||
std::thread::spawn({
|
||||
let instance_clone = instance.clone();
|
||||
move || {
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Failed to create Tokio runtime");
|
||||
|
||||
runtime.block_on(async move {
|
||||
let res = IdleDaemon::start_dbus(dbus_tx).await;
|
||||
match res {
|
||||
Ok((_, _)) => {
|
||||
Self::run_idle_timer(instance, wl_rx, dbus_rx).await;
|
||||
runtime.block_on(async move {
|
||||
let res = IdleDaemon::start_dbus(dbus_tx, instance_clone).await;
|
||||
match res {
|
||||
Ok((_, _)) => {
|
||||
Self::run_idle_timer(instance, wl_rx, dbus_rx, &config).await;
|
||||
}
|
||||
Err(err) => error!(&LOGGER, "Error running D-Bus Screensaver: {err}"),
|
||||
}
|
||||
Err(err) => error!(&LOGGER, "Error running D-Bus Screensaver: {err}"),
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -215,20 +228,21 @@ impl IdleStage {
|
||||
}
|
||||
}
|
||||
|
||||
fn timeout(self) -> Duration {
|
||||
fn timeout(self, cfg: &Config) -> Duration {
|
||||
match self {
|
||||
Self::Dim => Duration::from_secs(20),
|
||||
Self::TurnOff => Duration::from_secs(20),
|
||||
Self::Sleep => Duration::from_secs(20),
|
||||
Self::Dim => Duration::from_secs(cfg.dim_timeout_delta()),
|
||||
Self::TurnOff => Duration::from_secs(cfg.lock_timeout_delta()),
|
||||
Self::Sleep => Duration::from_secs(cfg.sleep_timeout_delta()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IdleDaemon {
|
||||
async fn run_idle_timer(
|
||||
_instance: Arc<Mutex<Self>>,
|
||||
instance: Arc<Mutex<Self>>,
|
||||
mut wl_rx: watch::Receiver<bool>,
|
||||
mut dbus_rx: watch::Receiver<(bool, bool)>,
|
||||
mut dbus_rx: watch::Receiver<bool>,
|
||||
config: &Config,
|
||||
) {
|
||||
loop {
|
||||
if let Err(e) = wl_rx.changed().await {
|
||||
@@ -237,22 +251,26 @@ impl IdleDaemon {
|
||||
}
|
||||
let wl_idle = *wl_rx.borrow_and_update();
|
||||
let dbus_state = *dbus_rx.borrow_and_update();
|
||||
println!("Wayland idle state changed {wl_idle} (DBus state: {dbus_state:?})");
|
||||
if wl_idle && !dbus_state.0 {
|
||||
println!("Going into idle cycle");
|
||||
if wl_idle && !dbus_state {
|
||||
let mut stage = IdleStage::Dim;
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = sleep(stage.timeout()) => {
|
||||
_ = sleep(stage.timeout(config)) => {
|
||||
match stage {
|
||||
IdleStage::Dim => instance.lock().unwrap().publish(IdleState::Dimmed),
|
||||
IdleStage::TurnOff => _ = Command::new("hyprlock").spawn(),
|
||||
IdleStage::Sleep => _ = Command::new("systemctl").arg("sleep").spawn(),
|
||||
}
|
||||
stage = stage.next();
|
||||
println!("Reached next stage {stage:?}");
|
||||
}
|
||||
res = wl_rx.changed() => {
|
||||
if let Err(e) = res {
|
||||
warn!(&LOGGER, "Error getting Wayland idle state {e}");
|
||||
return;
|
||||
}
|
||||
println!("WL state change");
|
||||
if !*wl_rx.borrow_and_update() {
|
||||
instance.lock().unwrap().publish(IdleState::Active);
|
||||
}
|
||||
break;
|
||||
}
|
||||
res = dbus_rx.changed() => {
|
||||
@@ -260,7 +278,6 @@ impl IdleDaemon {
|
||||
warn!(&LOGGER, "Error getting D-Bus idle state {e}");
|
||||
return;
|
||||
}
|
||||
println!("D-Bus state change");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -269,7 +286,7 @@ impl IdleDaemon {
|
||||
}
|
||||
}
|
||||
|
||||
fn start_idle_notifier(tx: watch::Sender<bool>) -> Result<(), Box<dyn Error>> {
|
||||
fn start_idle_notifier(tx: watch::Sender<bool>, config: &Config) -> Result<(), Box<dyn Error>> {
|
||||
let conn = Connection::connect_to_env()?;
|
||||
let (globals, mut event_queue) = registry_queue_init::<WlState>(&conn)?;
|
||||
let queue_handle = event_queue.handle();
|
||||
@@ -280,7 +297,12 @@ impl IdleDaemon {
|
||||
|
||||
let mut state = WlState { idle: None, tx };
|
||||
|
||||
let _notification = notifier.get_idle_notification(10_000, &seat, &queue_handle, ());
|
||||
let _notification = notifier.get_idle_notification(
|
||||
(config.idle_timeout() * 1000) as u32,
|
||||
&seat,
|
||||
&queue_handle,
|
||||
(),
|
||||
);
|
||||
|
||||
loop {
|
||||
event_queue.blocking_dispatch(&mut state)?;
|
||||
@@ -288,16 +310,18 @@ impl IdleDaemon {
|
||||
}
|
||||
|
||||
async fn start_dbus(
|
||||
tx: watch::Sender<(bool, bool)>,
|
||||
tx: watch::Sender<bool>,
|
||||
daemon: Arc<Mutex<IdleDaemon>>,
|
||||
) -> zbus::Result<(ScreenSaver, zbus::connection::Connection)> {
|
||||
let service = ScreenSaver::new(tx);
|
||||
let service = ScreenSaver::new(tx, daemon);
|
||||
|
||||
let connection = Builder::session()?
|
||||
.name(SERVICE)?
|
||||
.serve_at(OBJECT_PATH, service.clone())?
|
||||
.serve_at(LEGACY_OBJECT_PATH, service.clone())?
|
||||
.build()
|
||||
let connection = zbus::Connection::session().await?;
|
||||
|
||||
connection
|
||||
.object_server()
|
||||
.at(OBJECT_PATH, service.clone())
|
||||
.await?;
|
||||
connection.request_name(SERVICE).await?;
|
||||
|
||||
info!(&LOGGER, "Providing {SERVICE}");
|
||||
|
||||
@@ -347,22 +371,24 @@ impl IdleInhibitor {
|
||||
#[derive(Clone)]
|
||||
struct ScreenSaver {
|
||||
inner: Arc<Mutex<Inner>>,
|
||||
daemon: Arc<Mutex<IdleDaemon>>,
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
next_cookie: u32,
|
||||
inhibitors: HashMap<u32, Inhibitor>,
|
||||
tx: watch::Sender<(bool, bool)>,
|
||||
tx: watch::Sender<bool>,
|
||||
}
|
||||
|
||||
impl ScreenSaver {
|
||||
fn new(tx: watch::Sender<(bool, bool)>) -> Self {
|
||||
fn new(tx: watch::Sender<bool>, daemon: Arc<Mutex<IdleDaemon>>) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(Mutex::new(Inner {
|
||||
next_cookie: 1,
|
||||
inhibitors: HashMap::new(),
|
||||
tx,
|
||||
})),
|
||||
daemon,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,21 +425,26 @@ impl ScreenSaver {
|
||||
}
|
||||
};
|
||||
|
||||
let caffeine_flag = application_name.eq(APP_NAME);
|
||||
|
||||
debug!(&LOGGER, "Inhibitor added: {application_name} {cookie}");
|
||||
debug!(
|
||||
&LOGGER,
|
||||
"Inhibitor added - Name: '{application_name}' Reason: '{reason_for_inhibit}' Value: {cookie}"
|
||||
);
|
||||
inner.inhibitors.insert(
|
||||
cookie,
|
||||
Inhibitor {
|
||||
owner,
|
||||
application: application_name,
|
||||
_reason: reason_for_inhibit,
|
||||
reason: reason_for_inhibit,
|
||||
},
|
||||
);
|
||||
|
||||
self.daemon
|
||||
.lock()
|
||||
.unwrap()
|
||||
.publish(IdleState::Inhibited(true));
|
||||
|
||||
inner.tx.send_modify(|state| {
|
||||
state.0 = !inner.inhibitors.is_empty();
|
||||
state.1 = caffeine_flag;
|
||||
*state = !inner.inhibitors.is_empty();
|
||||
});
|
||||
Ok(cookie)
|
||||
}
|
||||
@@ -432,25 +463,25 @@ impl ScreenSaver {
|
||||
if let Some(removed) = inner.inhibitors.remove(&cookie) {
|
||||
debug!(
|
||||
&LOGGER,
|
||||
"Inhibitor removed: {} {cookie}", removed.application
|
||||
"Inhibitor removed - Name: '{}' Reason: '{}' Value: {cookie}",
|
||||
removed.application,
|
||||
removed.reason
|
||||
);
|
||||
}
|
||||
let mut caffeine_flag = false;
|
||||
for inhibitor in inner.inhibitors.values() {
|
||||
if inhibitor.application.eq(APP_NAME) {
|
||||
caffeine_flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.daemon
|
||||
.lock()
|
||||
.unwrap()
|
||||
.publish(IdleState::Inhibited(!inner.inhibitors.is_empty()));
|
||||
|
||||
inner.tx.send_modify(|state| {
|
||||
state.0 = !inner.inhibitors.is_empty();
|
||||
state.1 = caffeine_flag;
|
||||
*state = !inner.inhibitors.is_empty();
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
Some(_) => Err(zbus::fdo::Error::AccessDenied(
|
||||
"Cookie belongs to another D-Bus client".into(),
|
||||
)),
|
||||
Some(_) => Err(zbus::fdo::Error::AccessDenied(format!(
|
||||
"Cookie {cookie} belongs to another D-Bus client"
|
||||
))),
|
||||
None => Err(zbus::fdo::Error::Failed("Unknown inhibition cookie".into())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +161,26 @@ impl BackendThread<NetworkState, UnboundedSender<NetworkCommand>> for NetworkBac
|
||||
}
|
||||
};
|
||||
|
||||
std::thread::spawn({
|
||||
let nm = nm.clone();
|
||||
let mut instance = instance.clone();
|
||||
move || {
|
||||
let runtime = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Failed to create Tokio runtime");
|
||||
|
||||
runtime.block_on(async move {
|
||||
while let Ok(tx) = registration_rx.recv() {
|
||||
if tx.send(NetworkState::Init(instance.command_tx.clone())).is_ok() {
|
||||
instance.subscribers.push(tx);
|
||||
let _ = instance.send_all_networks(&nm).await;
|
||||
let _ = instance.send_active_connection(&nm).await;
|
||||
}
|
||||
}
|
||||
});
|
||||
}});
|
||||
|
||||
let mut events = match nm.network_events().await {
|
||||
Ok(events) => events,
|
||||
Err(err) => {
|
||||
@@ -169,7 +189,6 @@ impl BackendThread<NetworkState, UnboundedSender<NetworkCommand>> for NetworkBac
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let mut debouncer = EventDebouncer {
|
||||
duration: Duration::from_millis(200),
|
||||
deadline: None,
|
||||
@@ -177,13 +196,6 @@ impl BackendThread<NetworkState, UnboundedSender<NetworkCommand>> for NetworkBac
|
||||
};
|
||||
debouncer.sleep.as_mut().reset(Instant::now() + Duration::from_secs(86400));
|
||||
loop {
|
||||
while let Ok(tx) = registration_rx.try_recv() {
|
||||
if tx.send(NetworkState::Init(instance.command_tx.clone())).is_ok() {
|
||||
instance.subscribers.push(tx);
|
||||
let _ = instance.send_all_networks(&nm).await;
|
||||
let _ = instance.send_active_connection(&nm).await;
|
||||
}
|
||||
}
|
||||
tokio::select! {
|
||||
command = command_rx.recv() => {
|
||||
let Some(command) = command else {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use crate::LOGGER;
|
||||
use crate::backend::{BackendThread, SimpleBackendThread};
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use hyprland::data::{Client, Monitor, Workspaces};
|
||||
use hyprland::data::{Client, CursorPosition, Monitor, Monitors, Workspaces};
|
||||
use hyprland::event_listener::EventListener;
|
||||
use hyprland::prelude::*;
|
||||
use hyprland::shared::{MonitorId, WorkspaceId, WorkspaceType};
|
||||
use hyprland::shared::{MonitorId, WorkspaceId};
|
||||
use jmb_logger_rs::*;
|
||||
use std::io;
|
||||
use std::process::{Command, Output};
|
||||
@@ -24,7 +24,6 @@ pub struct HyprlandComms {
|
||||
}
|
||||
|
||||
impl SimpleBackendThread<WindowManagerEvent> for HyprlandComms {
|
||||
|
||||
fn subscribers(&self) -> &Vec<Sender<WindowManagerEvent>> {
|
||||
&self.subscribers
|
||||
}
|
||||
@@ -38,9 +37,7 @@ impl SimpleBackendThread<WindowManagerEvent> for HyprlandComms {
|
||||
|
||||
let inst_clone = instance.clone();
|
||||
listener.add_workspace_changed_handler(move |workspace| {
|
||||
if let WorkspaceType::Regular(name) = workspace.name
|
||||
&& let Ok(id) = name.parse::<i32>()
|
||||
{
|
||||
if let Ok(id) = workspace.name.parse::<i32>() {
|
||||
inst_clone
|
||||
.lock()
|
||||
.expect("Couldn't get Subscribers")
|
||||
@@ -50,26 +47,24 @@ impl SimpleBackendThread<WindowManagerEvent> for HyprlandComms {
|
||||
|
||||
let inst_clone = instance.clone();
|
||||
listener.add_workspace_added_handler(move |workspace| {
|
||||
if let WorkspaceType::Regular(name) = workspace.name {
|
||||
//unpacks the name of the workspace
|
||||
if let Ok(wss) = Workspaces::get() {
|
||||
//gets all workspaces
|
||||
if let Some(ws) = wss
|
||||
.to_vec()
|
||||
.iter()
|
||||
.find(|ws| ws.id().unwrap() == workspace.id)
|
||||
{
|
||||
//find the current workspace Object from its id
|
||||
if let Ok(id) = name.parse::<i32>() {
|
||||
// parse the id as an int
|
||||
inst_clone
|
||||
.lock()
|
||||
.expect("Couldn't get Subscribers")
|
||||
.publish(WindowManagerEvent::WorkspaceAdded(
|
||||
id,
|
||||
ws.monitor_id.unwrap(),
|
||||
));
|
||||
}
|
||||
//unpacks the name of the workspace
|
||||
if let Ok(wss) = Workspaces::get() {
|
||||
//gets all workspaces
|
||||
if let Some(ws) = wss
|
||||
.to_vec()
|
||||
.iter()
|
||||
.find(|ws| ws.id().unwrap() == workspace.id().unwrap())
|
||||
{
|
||||
//find the current workspace Object from its id
|
||||
if let Ok(id) = workspace.name.parse::<i32>() {
|
||||
// parse the id as an int
|
||||
inst_clone
|
||||
.lock()
|
||||
.expect("Couldn't get Subscribers")
|
||||
.publish(WindowManagerEvent::WorkspaceAdded(
|
||||
id,
|
||||
ws.monitor_id.unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,9 +72,7 @@ impl SimpleBackendThread<WindowManagerEvent> for HyprlandComms {
|
||||
|
||||
let inst_clone = instance.clone();
|
||||
listener.add_workspace_deleted_handler(move |workspace| {
|
||||
if let WorkspaceType::Regular(name) = workspace.name
|
||||
&& let Ok(id) = name.parse::<i32>()
|
||||
{
|
||||
if let Ok(id) = workspace.name.parse::<i32>() {
|
||||
inst_clone
|
||||
.lock()
|
||||
.expect("Couldn't get Subscribers")
|
||||
@@ -92,7 +85,9 @@ impl SimpleBackendThread<WindowManagerEvent> for HyprlandComms {
|
||||
inst_clone
|
||||
.lock()
|
||||
.expect("Couldn't get Subscribers")
|
||||
.publish(WindowManagerEvent::WorkspaceChanged(evt.workspace_id));
|
||||
.publish(WindowManagerEvent::WorkspaceChanged(
|
||||
evt.workspace.id().unwrap(),
|
||||
));
|
||||
});
|
||||
|
||||
let inst_clone = instance.clone();
|
||||
@@ -106,15 +101,22 @@ impl SimpleBackendThread<WindowManagerEvent> for HyprlandComms {
|
||||
|
||||
let inst_clone = instance.clone();
|
||||
listener.add_workspace_moved_handler(move |event| {
|
||||
if let Some(monitor_id) = Self::monitor_id_from_workspace_id(event.id) {
|
||||
if let Some(monitor_id) =
|
||||
Self::monitor_id_from_workspace_id(event.workspace.id().unwrap())
|
||||
{
|
||||
inst_clone
|
||||
.lock()
|
||||
.expect("Couldn't get Subscribers")
|
||||
.publish(WindowManagerEvent::WorkspaceRemoved(event.id));
|
||||
.publish(WindowManagerEvent::WorkspaceRemoved(
|
||||
event.workspace.id().unwrap(),
|
||||
));
|
||||
inst_clone
|
||||
.lock()
|
||||
.expect("Couldn't get Subscribers")
|
||||
.publish(WindowManagerEvent::WorkspaceAdded(event.id, monitor_id));
|
||||
.publish(WindowManagerEvent::WorkspaceAdded(
|
||||
event.workspace.id().unwrap(),
|
||||
monitor_id,
|
||||
));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -160,7 +162,7 @@ impl HyprlandComms {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn _current_monitor() -> MonitorId {
|
||||
pub fn current_monitor() -> MonitorId {
|
||||
if let Ok(monitor) = Monitor::get_active() {
|
||||
return monitor.id;
|
||||
}
|
||||
@@ -197,4 +199,22 @@ impl HyprlandComms {
|
||||
.arg(format!("hyprctl dispatch \"{dispatcher}\""))
|
||||
.output()
|
||||
}
|
||||
|
||||
pub fn cursor_monitor() -> Option<MonitorId> {
|
||||
if let Ok(pos) = CursorPosition::get()
|
||||
&& let Ok(monitors) = Monitors::get()
|
||||
{
|
||||
for monitor in monitors {
|
||||
if pos.x > monitor.x as i64
|
||||
&& pos.x < (monitor.x as i64 + monitor.width as i64)
|
||||
&& pos.y > monitor.y as i64
|
||||
&& pos.y < (monitor.y as i64 + monitor.height as i64)
|
||||
{
|
||||
return Some(monitor.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
59
src/config.rs
Normal file
59
src/config.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use serde::Deserialize;
|
||||
use std::fs;
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub(crate) struct Config {
|
||||
idle_timeout: u64,
|
||||
dim_timeout: u64,
|
||||
lock_timeout: u64,
|
||||
sleep_timeout: u64,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
idle_timeout: 20,
|
||||
dim_timeout: 60,
|
||||
lock_timeout: 300,
|
||||
sleep_timeout: 320,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn load() -> Config {
|
||||
fs::read_to_string("jmb-bar.conf")
|
||||
.ok()
|
||||
.map(|s| toml::from_str::<Config>(&s).ok())
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn idle_timeout(&self) -> u64 {
|
||||
self.idle_timeout
|
||||
}
|
||||
|
||||
pub fn dim_timeout(&self) -> u64 {
|
||||
self.dim_timeout
|
||||
}
|
||||
|
||||
pub fn lock_timeout(&self) -> u64 {
|
||||
self.lock_timeout
|
||||
}
|
||||
|
||||
pub fn sleep_timeout(&self) -> u64 {
|
||||
self.sleep_timeout
|
||||
}
|
||||
|
||||
pub fn dim_timeout_delta(&self) -> u64 {
|
||||
self.dim_timeout - self.idle_timeout
|
||||
}
|
||||
|
||||
pub fn lock_timeout_delta(&self) -> u64 {
|
||||
self.lock_timeout - self.dim_timeout_delta()
|
||||
}
|
||||
|
||||
pub fn sleep_timeout_delta(&self) -> u64 {
|
||||
self.sleep_timeout - self.lock_timeout_delta()
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
use crate::backend::Backend;
|
||||
mod backend;
|
||||
mod config;
|
||||
mod css;
|
||||
mod ctl;
|
||||
mod ui;
|
||||
|
||||
use crate::config::Config;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Application, CssProvider, gdk, gio};
|
||||
|
||||
12
src/ui.rs
12
src/ui.rs
@@ -39,7 +39,7 @@ pub fn create_bars(app: &Application, backend: Backend) {
|
||||
monitor,
|
||||
create_and_show_bar(
|
||||
app_clone.clone(),
|
||||
&display,
|
||||
display.clone(),
|
||||
monitor,
|
||||
action_centre.clone(),
|
||||
channels,
|
||||
@@ -61,11 +61,11 @@ pub fn create_bars(app: &Application, backend: Backend) {
|
||||
let action_centre = action_centre.clone();
|
||||
let channels = backend_clone.subscribe_all();
|
||||
let bars = bars.clone();
|
||||
let display = display.clone();
|
||||
glib::idle_add_local_once(move || {
|
||||
let display = Display::default().expect("Couldn't find GDK Display");
|
||||
bars.lock().expect("Couldn't get active bars").insert(
|
||||
pos,
|
||||
create_and_show_bar(app_clone, &display, pos, action_centre, channels),
|
||||
create_and_show_bar(app_clone, display, pos, action_centre, channels),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -74,7 +74,7 @@ pub fn create_bars(app: &Application, backend: Backend) {
|
||||
let mut ctl_channel = backend.subscribe(&[ChannelType::Control]);
|
||||
let ctl_rx = ctl_channel.take_ctl_rx().unwrap();
|
||||
let app_clone = app.clone();
|
||||
let menu = RunMenu::create(app_clone);
|
||||
let mut menu = RunMenu::create(app_clone);
|
||||
glib::timeout_add_local(Duration::from_millis(100), move || {
|
||||
while let Ok(cmd) = ctl_rx.try_recv() {
|
||||
match cmd {
|
||||
@@ -89,7 +89,7 @@ pub fn create_bars(app: &Application, backend: Backend) {
|
||||
|
||||
fn create_and_show_bar(
|
||||
app: Application,
|
||||
display: &Display,
|
||||
display: Display,
|
||||
monitor_idx: u32,
|
||||
action_centre: ActionCentre,
|
||||
mut channels: BackendChannels,
|
||||
@@ -138,7 +138,7 @@ fn create_and_show_bar(
|
||||
let title_button: Option<Button>;
|
||||
let title = title_panel::build();
|
||||
|
||||
let utilities = utilities_panel::build(&app, action_centre, channels, monitor_idx, display);
|
||||
let utilities = utilities_panel::build(&app, action_centre, channels, monitor_idx, &display);
|
||||
|
||||
let dock = gtk::Box::new(Orientation::Horizontal, 10);
|
||||
dock.add_css_class("dock");
|
||||
|
||||
@@ -111,106 +111,111 @@ impl ActionCentre {
|
||||
|
||||
window.set_child(Some(&scrolled));
|
||||
|
||||
let instance_clone = instance.clone();
|
||||
let key_controller = gtk::EventControllerKey::new();
|
||||
key_controller.connect_key_pressed(move |_, key, _, _| {
|
||||
if key == gdk::Key::Escape {
|
||||
instance_clone.hide_action_centre();
|
||||
glib::Propagation::Stop
|
||||
} else {
|
||||
glib::Propagation::Proceed
|
||||
key_controller.connect_key_pressed({
|
||||
let instance = instance.clone();
|
||||
move |_, key, _, _| {
|
||||
if key == gdk::Key::Escape {
|
||||
instance.hide_action_centre();
|
||||
glib::Propagation::Stop
|
||||
} else {
|
||||
glib::Propagation::Proceed
|
||||
}
|
||||
}
|
||||
});
|
||||
window.add_controller(key_controller);
|
||||
|
||||
let wifi_networks: Rc<RefCell<HashMap<String, WifiWidget>>> =
|
||||
Rc::new(RefCell::new(HashMap::new()));
|
||||
let wifi_networks_clone = wifi_networks.clone();
|
||||
window.connect_focus_widget_notify(move |window| {
|
||||
Self::focus_callback(&wifi_networks_clone, window)
|
||||
window.connect_focus_widget_notify({
|
||||
let wifi_networks = wifi_networks.clone();
|
||||
move |window| Self::focus_callback(&wifi_networks, window)
|
||||
});
|
||||
|
||||
let net_rx = channels.take_net_rx().unwrap();
|
||||
let window_clone = window.clone();
|
||||
let wifi_networks_clone = wifi_networks.clone();
|
||||
glib::timeout_add_local(Duration::from_millis(100), move || {
|
||||
while let Ok(message) = net_rx.try_recv() {
|
||||
match message {
|
||||
NetworkState::ChangeNetwork(Some(info)) => {
|
||||
for (name, widget) in wifi_networks_clone.borrow().iter() {
|
||||
if name.eq(&info.name) {
|
||||
widget.add_css_class("connected");
|
||||
} else {
|
||||
widget.remove_css_class("connected");
|
||||
glib::timeout_add_local(Duration::from_millis(100), {
|
||||
let window = window.clone();
|
||||
let wifi_networks = wifi_networks.clone();
|
||||
let net_rx = channels.take_net_rx().unwrap();
|
||||
move || {
|
||||
while let Ok(message) = net_rx.try_recv() {
|
||||
match message {
|
||||
NetworkState::ChangeNetwork(Some(info)) => {
|
||||
for (name, widget) in wifi_networks.borrow().iter() {
|
||||
if name.eq(&info.name) {
|
||||
widget.add_css_class("connected");
|
||||
} else {
|
||||
widget.remove_css_class("connected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NetworkState::Networks(networks) => {
|
||||
for network in &networks {
|
||||
let borrowed_wifi_networks_clone = wifi_networks_clone.borrow_mut();
|
||||
let widget = borrowed_wifi_networks_clone.get(&network.name);
|
||||
if let Some(widget) = widget {
|
||||
let idx = ((network.signal as f32 / 100.0)
|
||||
* (WIFI_ICONS.len() - 1) as f32
|
||||
+ 0.5) as usize;
|
||||
widget.set_wifi_icon_from_name(WIFI_ICONS[idx]);
|
||||
} else {
|
||||
let widget = Self::create_wifi_widget(
|
||||
&channels,
|
||||
network,
|
||||
borrowed_wifi_networks_clone,
|
||||
);
|
||||
content.append(&widget);
|
||||
NetworkState::Networks(networks) => {
|
||||
for network in &networks {
|
||||
let borrowed_wifi_networks = wifi_networks.borrow_mut();
|
||||
let widget = borrowed_wifi_networks.get(&network.name);
|
||||
if let Some(widget) = widget {
|
||||
let idx = ((network.signal as f32 / 100.0)
|
||||
* (WIFI_ICONS.len() - 1) as f32
|
||||
+ 0.5)
|
||||
as usize;
|
||||
widget.set_wifi_icon_from_name(WIFI_ICONS[idx]);
|
||||
} else {
|
||||
let widget = Self::create_wifi_widget(
|
||||
&channels,
|
||||
network,
|
||||
borrowed_wifi_networks,
|
||||
);
|
||||
content.append(&widget);
|
||||
}
|
||||
}
|
||||
let mut removal: Vec<String> = Vec::new();
|
||||
for (ssid, widget) in wifi_networks.borrow().iter() {
|
||||
let network = &networks.iter().find(|n| n.name.eq(ssid));
|
||||
if network.is_none() {
|
||||
content.remove(widget);
|
||||
removal.push(ssid.clone());
|
||||
}
|
||||
}
|
||||
for ssid in removal {
|
||||
wifi_networks.borrow_mut().remove(&ssid);
|
||||
}
|
||||
}
|
||||
let mut removal: Vec<String> = Vec::new();
|
||||
for (ssid, widget) in wifi_networks_clone.borrow().iter() {
|
||||
let network = &networks.iter().find(|n| n.name.eq(ssid));
|
||||
if network.is_none() {
|
||||
content.remove(widget);
|
||||
removal.push(ssid.clone());
|
||||
}
|
||||
}
|
||||
for ssid in removal {
|
||||
wifi_networks_clone.borrow_mut().remove(&ssid);
|
||||
}
|
||||
}
|
||||
NetworkState::Auth(ssid, auth) => {
|
||||
if let Some(widget) = Self::find_focused_widget(window_clone.as_ref()) {
|
||||
match auth {
|
||||
AuthType::Password => {
|
||||
if widget.ssid().eq(&ssid) {
|
||||
widget.show_password_entry();
|
||||
widget.stop_spinner();
|
||||
widget.grab_focus_password_entry();
|
||||
NetworkState::Auth(ssid, auth) => {
|
||||
if let Some(widget) = Self::find_focused_widget(window.as_ref()) {
|
||||
match auth {
|
||||
AuthType::Password => {
|
||||
if widget.ssid().eq(&ssid) {
|
||||
widget.show_password_entry();
|
||||
widget.stop_spinner();
|
||||
widget.grab_focus_password_entry();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NetworkState::ConnectFail(ssid, err) => {
|
||||
let mut networks = wifi_networks_clone.borrow_mut();
|
||||
if let Some(widget) = networks.get(&ssid) {
|
||||
widget.stop_spinner();
|
||||
match err {
|
||||
ConnectError::AuthFailed => widget.show_password_entry(),
|
||||
ConnectError::NotFound => {
|
||||
content.remove(widget);
|
||||
networks.remove(&ssid);
|
||||
NetworkState::ConnectFail(ssid, err) => {
|
||||
let mut networks = wifi_networks.borrow_mut();
|
||||
if let Some(widget) = networks.get(&ssid) {
|
||||
widget.stop_spinner();
|
||||
match err {
|
||||
ConnectError::AuthFailed => widget.show_password_entry(),
|
||||
ConnectError::NotFound => {
|
||||
content.remove(widget);
|
||||
networks.remove(&ssid);
|
||||
}
|
||||
ConnectError::Unknown => {}
|
||||
}
|
||||
ConnectError::Unknown => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
NetworkState::ConnectSuccess(ssid) => {
|
||||
if let Some(widget) = wifi_networks_clone.borrow().get(&ssid) {
|
||||
widget.stop_spinner();
|
||||
NetworkState::ConnectSuccess(ssid) => {
|
||||
if let Some(widget) = wifi_networks.borrow().get(&ssid) {
|
||||
widget.stop_spinner();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ControlFlow::Continue
|
||||
}
|
||||
ControlFlow::Continue
|
||||
});
|
||||
|
||||
instance
|
||||
@@ -219,7 +224,7 @@ impl ActionCentre {
|
||||
fn create_wifi_widget(
|
||||
channels: &BackendChannels,
|
||||
network: &NetworkInfo,
|
||||
mut borrowed_wifi_networks_clone: RefMut<HashMap<String, WifiWidget>>,
|
||||
mut borrowed_wifi_networks: RefMut<HashMap<String, WifiWidget>>,
|
||||
) -> WifiWidget {
|
||||
let ssid = network.name.clone();
|
||||
let widget = WifiWidget::new();
|
||||
@@ -229,7 +234,7 @@ impl ActionCentre {
|
||||
widget.set_known(network.known);
|
||||
let idx = ((network.signal as f32 / 100.0) * (WIFI_ICONS.len() - 1) as f32 + 0.5) as usize;
|
||||
widget.set_wifi_icon_from_name(WIFI_ICONS[idx]);
|
||||
borrowed_wifi_networks_clone.insert(ssid.clone(), widget.clone());
|
||||
borrowed_wifi_networks.insert(ssid.clone(), widget.clone());
|
||||
let net_tx = channels.net_tx().unwrap();
|
||||
widget.connect_clicked(clone!(
|
||||
#[strong]
|
||||
|
||||
@@ -1,27 +1,44 @@
|
||||
use gtk::prelude::{BoxExt, GtkWindowExt, WidgetExt};
|
||||
use crate::LOGGER;
|
||||
use crate::backend::window_manager_hypr::HyprlandComms;
|
||||
use freedesktop_desktop_entry::{default_paths, get_languages_from_env};
|
||||
use glib::clone;
|
||||
use glib::prelude::Cast;
|
||||
use gtk::gdk::{Display, Monitor};
|
||||
use gtk::prelude::{
|
||||
BoxExt, ButtonExt, DisplayExt, EditableExt, EntryExt, GtkWindowExt, ListModelExt, MonitorExt,
|
||||
WidgetExt,
|
||||
};
|
||||
use gtk::{Align, Application, ApplicationWindow, Orientation, PolicyType, gdk};
|
||||
use gtk4_layer_shell::{KeyboardMode, Layer, LayerShell};
|
||||
use gtk4_layer_shell::{Edge, KeyboardMode, Layer, LayerShell};
|
||||
use jmb_logger_rs::*;
|
||||
use nucleo_matcher::pattern::{CaseMatching, Normalization, Pattern};
|
||||
use nucleo_matcher::{Config, Matcher};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::process::Command;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RunMenu {
|
||||
window: ApplicationWindow,
|
||||
entry: gtk::Entry,
|
||||
entries: Rc<RefCell<HashMap<String, Vec<String>>>>,
|
||||
}
|
||||
|
||||
impl RunMenu {
|
||||
pub fn create(application: Application) -> Self {
|
||||
let window = gtk::ApplicationWindow::builder()
|
||||
let window = ApplicationWindow::builder()
|
||||
.application(&application)
|
||||
.title("JmbRunMenu")
|
||||
.default_width(500)
|
||||
.default_height(300)
|
||||
.css_classes(["run-menu"])
|
||||
.build();
|
||||
|
||||
window.init_layer_shell();
|
||||
window.set_layer(Layer::Overlay);
|
||||
window.set_halign(Align::Center);
|
||||
window.set_valign(Align::Center);
|
||||
window.set_size_request(500, 300);
|
||||
window.set_width_request(500);
|
||||
window.set_anchor(Edge::Top, true);
|
||||
window.set_keyboard_mode(KeyboardMode::Exclusive);
|
||||
|
||||
let v_box = gtk::Box::new(Orientation::Vertical, 0);
|
||||
@@ -31,28 +48,109 @@ impl RunMenu {
|
||||
|
||||
let scrolled = gtk::ScrolledWindow::new();
|
||||
scrolled.set_policy(PolicyType::Never, PolicyType::Automatic);
|
||||
scrolled.set_vexpand(true);
|
||||
scrolled.set_valign(Align::Fill);
|
||||
scrolled.set_vexpand(false);
|
||||
scrolled.set_propagate_natural_height(true);
|
||||
scrolled.set_min_content_height(0);
|
||||
scrolled.set_max_content_height(300);
|
||||
|
||||
let content_box = gtk::Box::new(Orientation::Vertical, 0);
|
||||
content_box.add_css_class("content-box");
|
||||
|
||||
for _ in 0..10 {
|
||||
let label = gtk::Label::new(Some("Test"));
|
||||
content_box.append(&label);
|
||||
}
|
||||
|
||||
content_box.set_hexpand(true);
|
||||
scrolled.set_child(Some(&content_box));
|
||||
|
||||
v_box.set_vexpand(false);
|
||||
v_box.set_valign(Align::Start);
|
||||
v_box.append(&entry);
|
||||
v_box.append(&scrolled);
|
||||
|
||||
window.set_child(Some(&v_box));
|
||||
|
||||
let display = Display::default().expect("Couldn't get display");
|
||||
let monitor = display
|
||||
.monitors()
|
||||
.item(HyprlandComms::current_monitor() as u32)
|
||||
.expect("Couldn't get monitor")
|
||||
.downcast::<Monitor>()
|
||||
.ok();
|
||||
window.set_monitor(monitor.as_ref());
|
||||
if let Some(monitor) = monitor {
|
||||
let geometry = monitor.geometry();
|
||||
let (_, natural_height, _, _) =
|
||||
window.child().unwrap().measure(Orientation::Vertical, -1);
|
||||
println!("Monitor height: {}", geometry.height());
|
||||
let top_margin = (geometry.height()) / 2;
|
||||
window.set_margin(Edge::Top, top_margin - 100);
|
||||
} else {
|
||||
window.set_valign(Align::Center);
|
||||
}
|
||||
|
||||
content_box
|
||||
.observe_children()
|
||||
.connect_items_changed(move |model, _, _, _| {
|
||||
if model.n_items() == 0 {
|
||||
println!("Hide");
|
||||
} else {
|
||||
println!("Reveal");
|
||||
}
|
||||
});
|
||||
|
||||
let window_clone = window.clone();
|
||||
let instance = Self {
|
||||
window: window_clone,
|
||||
entry: entry.clone(),
|
||||
entries: Rc::new(RefCell::new(HashMap::new())),
|
||||
};
|
||||
let instance_clone = instance.clone();
|
||||
let matcher_rc = Rc::new(RefCell::new(Matcher::new(Config::DEFAULT)));
|
||||
entry.connect_changed(clone!(
|
||||
#[strong]
|
||||
content_box,
|
||||
move |e| {
|
||||
while let Some(child) = content_box.first_child() {
|
||||
content_box.remove(&child);
|
||||
}
|
||||
if e.text_length() > 0 {
|
||||
let text = e.text();
|
||||
if text.starts_with("=") {
|
||||
if let Ok(eval) = meval::eval_str(&text[1..]) {
|
||||
let label = gtk::Label::new(Some(&format!("{eval}")));
|
||||
label.add_css_class("exec-button");
|
||||
label.set_halign(Align::Start);
|
||||
label.set_hexpand(true);
|
||||
content_box.append(&label);
|
||||
}
|
||||
} else {
|
||||
instance_clone.list_matching(e, &content_box, &mut matcher_rc.borrow_mut());
|
||||
instance_clone.window.set_default_size(500, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
entry.connect_has_focus_notify(clone!(
|
||||
#[strong]
|
||||
content_box,
|
||||
move |e| {
|
||||
if let Some(child) = content_box.first_child() {
|
||||
if e.has_focus() {
|
||||
child.add_css_class("suggested");
|
||||
} else {
|
||||
child.remove_css_class("suggested");
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
entry.connect_activate(clone!(
|
||||
#[strong]
|
||||
content_box,
|
||||
move |_| {
|
||||
if let Some(child) = content_box.first_child()
|
||||
&& let Ok(button) = child.downcast::<gtk::Button>()
|
||||
{
|
||||
button.activate();
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
let instance_clone = instance.clone();
|
||||
let key_controller = gtk::EventControllerKey::new();
|
||||
key_controller.connect_key_pressed(move |_, key, _, _| {
|
||||
@@ -69,9 +167,82 @@ impl RunMenu {
|
||||
|
||||
pub fn hide(&self) {
|
||||
self.window.set_visible(false);
|
||||
self.entry.set_text("");
|
||||
}
|
||||
|
||||
pub fn show(&self) {
|
||||
pub fn show(&mut self) {
|
||||
self.load_desktop_files();
|
||||
self.window.present();
|
||||
}
|
||||
|
||||
fn create_entry(&self, content_box: >k::Box, entry: &String) -> gtk::Button {
|
||||
let entry_clone = entry.clone();
|
||||
let button = gtk::Button::new();
|
||||
button.set_halign(Align::Fill);
|
||||
button.set_hexpand(true);
|
||||
|
||||
let label = gtk::Label::new(Some(entry));
|
||||
label.set_halign(Align::Start);
|
||||
button.set_child(Some(&label));
|
||||
|
||||
button.add_css_class("exec-button");
|
||||
let entry_map = self.entries.clone();
|
||||
let instance = self.clone();
|
||||
button.connect_clicked(move |_| {
|
||||
let map = entry_map.borrow();
|
||||
let exec = map.get(&entry_clone);
|
||||
if let Some(exec) = exec {
|
||||
let executable = &exec[0];
|
||||
if let Err(err) = Command::new(executable).args(&exec[1..]).spawn() {
|
||||
warn!(&LOGGER, "Couldn't execute app: {err}");
|
||||
}
|
||||
instance.hide();
|
||||
}
|
||||
});
|
||||
content_box.append(&button);
|
||||
button
|
||||
}
|
||||
|
||||
fn list_matching(
|
||||
&self,
|
||||
entry: >k::Entry,
|
||||
content_box: >k::Box,
|
||||
matcher: &mut Matcher,
|
||||
) -> bool {
|
||||
let keys: Vec<String> = self.entries.borrow().keys().map(|i| i.clone()).collect();
|
||||
let mut first = true;
|
||||
let mut added = false;
|
||||
for (entry, _) in Pattern::parse(&entry.text(), CaseMatching::Ignore, Normalization::Smart)
|
||||
.match_list(keys, matcher)
|
||||
.iter()
|
||||
{
|
||||
let button = self.create_entry(content_box, &entry);
|
||||
if first {
|
||||
button.add_css_class("suggested");
|
||||
first = false;
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
added
|
||||
}
|
||||
|
||||
fn load_desktop_files(&mut self) {
|
||||
let locales = get_languages_from_env();
|
||||
|
||||
let entries = freedesktop_desktop_entry::Iter::new(default_paths())
|
||||
.entries(Some(&locales))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut entry_map = self.entries.borrow_mut();
|
||||
entry_map.clear();
|
||||
|
||||
for entry in entries {
|
||||
if let Ok(exec) = entry.parse_exec() {
|
||||
let name = entry.full_name(&locales);
|
||||
if let Some(name) = name {
|
||||
entry_map.insert(name.to_string(), exec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,14 +78,16 @@ pub fn build(
|
||||
|
||||
let media_tx = channels.media_tx().unwrap();
|
||||
let changed_progr = Rc::new(Cell::new(false));
|
||||
let changed_progr_clone = changed_progr.clone();
|
||||
volume.connect_value_changed(move |slider, button, _| {
|
||||
if !changed_progr_clone.get() {
|
||||
let _ = media_tx.send(MediaCommand::Cmd(
|
||||
slider.value() as u8,
|
||||
button.is_active(),
|
||||
false,
|
||||
));
|
||||
volume.connect_value_changed({
|
||||
let changed_progr = changed_progr.clone();
|
||||
move |slider, button, _| {
|
||||
if !changed_progr.get() {
|
||||
let _ = media_tx.send(MediaCommand::Cmd(
|
||||
slider.value() as u8,
|
||||
button.is_active(),
|
||||
false,
|
||||
));
|
||||
}
|
||||
}
|
||||
});
|
||||
let media_tx = channels.media_tx().unwrap();
|
||||
@@ -189,7 +191,7 @@ pub fn build(
|
||||
let network_button = Button::new();
|
||||
network_button.add_css_class("network");
|
||||
let network_button_content = gtk::Box::new(Orientation::Horizontal, 0);
|
||||
let network_icon = Image::from_file("../../icons/disconnected.svg");
|
||||
let network_icon = Image::from_file("icons/disconnected.svg");
|
||||
network_icon.add_css_class("network-icon");
|
||||
network_button_content.append(&network_icon);
|
||||
let network_label = Label::new(None);
|
||||
@@ -312,184 +314,188 @@ pub fn build(
|
||||
ControlFlow::Continue
|
||||
});
|
||||
|
||||
let media_rx = channels.take_media_rx().unwrap();
|
||||
let br_rx = channels.take_br_rx().unwrap();
|
||||
let net_rx = channels.take_net_rx().unwrap();
|
||||
let stats_rx = channels.take_stats_rx().unwrap();
|
||||
let netbird_rx = channels.take_netbird_rx().unwrap();
|
||||
let idle_rx = channels.take_idle_rx().unwrap();
|
||||
let monitor_clone = monitor.clone();
|
||||
let br_tx = channels.br_tx().unwrap();
|
||||
glib::timeout_add_local(Duration::from_millis(100), move || {
|
||||
while let Ok(command) = media_rx.try_recv() {
|
||||
if let MediaCommand::Cmd(vol, mute, bt) = command {
|
||||
changed_progr.set(true);
|
||||
volume.set_value(vol as f64);
|
||||
changed_progr.set(false);
|
||||
volume.show_scale(!mute);
|
||||
volume.imp().button.set_active(mute);
|
||||
if mute {
|
||||
volume.imp().button.add_css_class("muted");
|
||||
volume.imp().second_icon.add_child_css_class("muted");
|
||||
volume
|
||||
glib::timeout_add_local(Duration::from_millis(100), {
|
||||
let media_rx = channels.take_media_rx().unwrap();
|
||||
let br_rx = channels.take_br_rx().unwrap();
|
||||
let net_rx = channels.take_net_rx().unwrap();
|
||||
let stats_rx = channels.take_stats_rx().unwrap();
|
||||
let netbird_rx = channels.take_netbird_rx().unwrap();
|
||||
let idle_rx = channels.take_idle_rx().unwrap();
|
||||
let monitor = monitor.clone();
|
||||
let br_tx = channels.br_tx().unwrap();
|
||||
move || {
|
||||
while let Ok(command) = media_rx.try_recv() {
|
||||
if let MediaCommand::Cmd(vol, mute, bt) = command {
|
||||
changed_progr.set(true);
|
||||
volume.set_value(vol as f64);
|
||||
changed_progr.set(false);
|
||||
volume.show_scale(!mute);
|
||||
volume.imp().button.set_active(mute);
|
||||
if mute {
|
||||
volume.imp().button.add_css_class("muted");
|
||||
volume.imp().second_icon.add_child_css_class("muted");
|
||||
volume
|
||||
.imp()
|
||||
.main_icon
|
||||
.set_icon_path("icons/volume-mute.svg");
|
||||
} else {
|
||||
volume.imp().button.remove_css_class("muted");
|
||||
volume.imp().second_icon.remove_child_css_class("muted");
|
||||
let idx = ((volume.value() / 100.0) * (VOLUME_ICON_PATHS.len() - 1) as f64
|
||||
+ 0.5) as usize;
|
||||
volume.imp().main_icon.set_icon_path(VOLUME_ICON_PATHS[idx]);
|
||||
}
|
||||
volume.imp().second_icon.set_visible(bt);
|
||||
}
|
||||
}
|
||||
while let Ok(message) = br_rx.try_recv() {
|
||||
if let BrightnessMessage::Value(mon, value, _) = message
|
||||
&& monitor.eq(&mon)
|
||||
{
|
||||
brightness.set_value(value as f64);
|
||||
let idx = ((value as f32 / 100.0) * (BRIGHTNESS_ICONS.len() - 1) as f32 + 0.5)
|
||||
as usize;
|
||||
brightness
|
||||
.imp()
|
||||
.main_icon
|
||||
.set_icon_path("icons/volume-mute.svg");
|
||||
} else {
|
||||
volume.imp().button.remove_css_class("muted");
|
||||
volume.imp().second_icon.remove_child_css_class("muted");
|
||||
let idx = ((volume.value() / 100.0) * (VOLUME_ICON_PATHS.len() - 1) as f64
|
||||
+ 0.5) as usize;
|
||||
volume.imp().main_icon.set_icon_path(VOLUME_ICON_PATHS[idx]);
|
||||
.set_font_icon(BRIGHTNESS_ICONS[idx]);
|
||||
}
|
||||
volume.imp().second_icon.set_visible(bt);
|
||||
}
|
||||
}
|
||||
while let Ok(message) = br_rx.try_recv() {
|
||||
if let BrightnessMessage::Value(mon, value, _) = message
|
||||
&& monitor.eq(&mon)
|
||||
{
|
||||
brightness.set_value(value as f64);
|
||||
let idx =
|
||||
((value as f32 / 100.0) * (BRIGHTNESS_ICONS.len() - 1) as f32 + 0.5) as usize;
|
||||
brightness
|
||||
.imp()
|
||||
.main_icon
|
||||
.set_font_icon(BRIGHTNESS_ICONS[idx]);
|
||||
}
|
||||
}
|
||||
while let Ok(state) = idle_rx.try_recv() {
|
||||
match state {
|
||||
IdleState::Dimmed => {
|
||||
if !caffeine_button.has_css_class("idle") && monitor_valid {
|
||||
let _ =
|
||||
br_tx.send(BrightnessMessage::Value(monitor_clone.clone(), 20, true));
|
||||
brightness.set_value(20.0);
|
||||
while let Ok(state) = idle_rx.try_recv() {
|
||||
match state {
|
||||
IdleState::Dimmed => {
|
||||
if !caffeine_button.has_css_class("idle") && monitor_valid {
|
||||
let _ = br_tx.send(BrightnessMessage::Value(monitor.clone(), 20, true));
|
||||
brightness.set_value(20.0);
|
||||
}
|
||||
caffeine_button.add_css_class("idle");
|
||||
caffeine_button.remove_css_class("inhibit");
|
||||
caffeine_button.remove_css_class("on");
|
||||
}
|
||||
caffeine_button.add_css_class("idle");
|
||||
caffeine_button.remove_css_class("inhibit");
|
||||
caffeine_button.remove_css_class("on");
|
||||
}
|
||||
other => {
|
||||
caffeine_button.remove_css_class("idle");
|
||||
caffeine_button.remove_css_class("inhibit");
|
||||
caffeine_button.remove_css_class("on");
|
||||
if monitor_valid {
|
||||
let _ = br_tx.send(BrightnessMessage::Revert(monitor_clone.clone()));
|
||||
}
|
||||
match other {
|
||||
IdleState::Caffeine => caffeine_button.add_css_class("on"),
|
||||
IdleState::Inhibited => caffeine_button.add_css_class("inhibit"),
|
||||
IdleState::Active => {}
|
||||
_ => {}
|
||||
other => {
|
||||
caffeine_button.remove_css_class("idle");
|
||||
if monitor_valid {
|
||||
let _ = br_tx.send(BrightnessMessage::Revert(monitor.clone()));
|
||||
}
|
||||
match other {
|
||||
IdleState::Caffeine(true) => caffeine_button.add_css_class("on"),
|
||||
IdleState::Inhibited(true) => caffeine_button.add_css_class("inhibit"),
|
||||
IdleState::Caffeine(false) => caffeine_button.remove_css_class("on"),
|
||||
IdleState::Inhibited(false) => {
|
||||
caffeine_button.remove_css_class("inhibit")
|
||||
}
|
||||
IdleState::Active => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while let Ok(result) = net_rx.try_recv() {
|
||||
trace!(&LOGGER, "NetworkResult: {:?}", result);
|
||||
match result {
|
||||
NetworkState::ChangeNetwork(cfg) => {
|
||||
match cfg {
|
||||
Some(network) => {
|
||||
match network.network_type {
|
||||
NetworkType::Wifi => {
|
||||
//let idx = ((20.0 / 100.0) * (WIFI_ICON_PATHS.len() - 1) as f32 + 0.5) as usize;
|
||||
let idx = ((network.signal as f32 / 100.0)
|
||||
* (WIFI_ICON_PATHS.len() - 1) as f32
|
||||
+ 0.5)
|
||||
as usize;
|
||||
network_icon.set_from_file(Some(WIFI_ICON_PATHS[idx]));
|
||||
network_label.set_label(&network.name);
|
||||
network_label.set_visible(true);
|
||||
}
|
||||
NetworkType::Wired => {
|
||||
network_icon.set_from_file(Some("icons/ethernet.svg"));
|
||||
network_label.set_visible(false);
|
||||
while let Ok(result) = net_rx.try_recv() {
|
||||
trace!(&LOGGER, "NetworkResult: {:?}", result);
|
||||
match result {
|
||||
NetworkState::ChangeNetwork(cfg) => {
|
||||
match cfg {
|
||||
Some(network) => {
|
||||
match network.network_type {
|
||||
NetworkType::Wifi => {
|
||||
//let idx = ((20.0 / 100.0) * (WIFI_ICON_PATHS.len() - 1) as f32 + 0.5) as usize;
|
||||
let idx = ((network.signal as f32 / 100.0)
|
||||
* (WIFI_ICON_PATHS.len() - 1) as f32
|
||||
+ 0.5)
|
||||
as usize;
|
||||
network_icon.set_from_file(Some(WIFI_ICON_PATHS[idx]));
|
||||
network_label.set_label(&network.name);
|
||||
network_label.set_visible(true);
|
||||
}
|
||||
NetworkType::Wired => {
|
||||
network_icon.set_from_file(Some("icons/ethernet.svg"));
|
||||
network_label.set_visible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
network_icon.set_from_file(Some("icons/disconnected.svg"));
|
||||
network_label.set_visible(false);
|
||||
None => {
|
||||
network_icon.set_from_file(Some("icons/disconnected.svg"));
|
||||
network_label.set_visible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
NetworkState::VpnState { connected, profile } if profile.as_str() == "wg" => {
|
||||
if connected {
|
||||
wg_button.add_css_class("on");
|
||||
} else {
|
||||
wg_button.remove_css_class("on");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
NetworkState::VpnState { connected, profile } if profile.as_str() == "wg" => {
|
||||
if connected {
|
||||
wg_button.add_css_class("on");
|
||||
} else {
|
||||
wg_button.remove_css_class("on");
|
||||
}
|
||||
while let Ok(tailscale_state) = netbird_rx.try_recv() {
|
||||
match tailscale_state {
|
||||
json_socket::State::Disconnected => {
|
||||
netbird_button.remove_css_class("on");
|
||||
netbird_button.remove_css_class("starting");
|
||||
netbird_button.remove_css_class("unknown");
|
||||
netbird_button.remove_css_class("login");
|
||||
}
|
||||
json_socket::State::Connecting => {
|
||||
netbird_button.remove_css_class("on");
|
||||
netbird_button.add_css_class("starting");
|
||||
netbird_button.remove_css_class("unknown");
|
||||
netbird_button.remove_css_class("login");
|
||||
}
|
||||
json_socket::State::Connected => {
|
||||
netbird_button.add_css_class("on");
|
||||
netbird_button.remove_css_class("starting");
|
||||
netbird_button.remove_css_class("unknown");
|
||||
netbird_button.remove_css_class("login");
|
||||
}
|
||||
json_socket::State::NeedsLogin => {
|
||||
netbird_button.remove_css_class("on");
|
||||
netbird_button.remove_css_class("starting");
|
||||
netbird_button.remove_css_class("unknown");
|
||||
netbird_button.add_css_class("login");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
while let Ok(tailscale_state) = netbird_rx.try_recv() {
|
||||
match tailscale_state {
|
||||
json_socket::State::Disconnected => {
|
||||
netbird_button.remove_css_class("on");
|
||||
netbird_button.remove_css_class("starting");
|
||||
netbird_button.remove_css_class("unknown");
|
||||
netbird_button.remove_css_class("login");
|
||||
}
|
||||
json_socket::State::Connecting => {
|
||||
netbird_button.remove_css_class("on");
|
||||
netbird_button.add_css_class("starting");
|
||||
netbird_button.remove_css_class("unknown");
|
||||
netbird_button.remove_css_class("login");
|
||||
}
|
||||
json_socket::State::Connected => {
|
||||
netbird_button.add_css_class("on");
|
||||
netbird_button.remove_css_class("starting");
|
||||
netbird_button.remove_css_class("unknown");
|
||||
netbird_button.remove_css_class("login");
|
||||
}
|
||||
json_socket::State::NeedsLogin => {
|
||||
netbird_button.remove_css_class("on");
|
||||
netbird_button.remove_css_class("starting");
|
||||
netbird_button.remove_css_class("unknown");
|
||||
netbird_button.add_css_class("login");
|
||||
}
|
||||
if wg_button.has_css_class("on") || netbird_button.has_css_class("on") {
|
||||
vpn_button.add_css_class("on");
|
||||
vpn_button.remove_css_class("login");
|
||||
} else if wg_button.has_css_class("login") || netbird_button.has_css_class("login") {
|
||||
vpn_button.add_css_class("login");
|
||||
vpn_button.remove_css_class("on");
|
||||
} else {
|
||||
vpn_button.remove_css_class("on");
|
||||
vpn_button.remove_css_class("login");
|
||||
}
|
||||
}
|
||||
if wg_button.has_css_class("on") || netbird_button.has_css_class("on") {
|
||||
vpn_button.add_css_class("on");
|
||||
vpn_button.remove_css_class("login");
|
||||
} else if wg_button.has_css_class("login") || netbird_button.has_css_class("login") {
|
||||
vpn_button.add_css_class("login");
|
||||
vpn_button.remove_css_class("on");
|
||||
} else {
|
||||
vpn_button.remove_css_class("on");
|
||||
vpn_button.remove_css_class("login");
|
||||
}
|
||||
while let Ok(stats) = stats_rx.try_recv() {
|
||||
if let Some(cpu) = stats.cpu {
|
||||
cpu_label.set_label(&format!("{}%", cpu));
|
||||
}
|
||||
if let Some(ram) = stats.ram {
|
||||
ram_label.set_label(&format!("{}%", ram));
|
||||
}
|
||||
for disk in stats.disks {
|
||||
if disk.0.eq("/") {
|
||||
disk_label.set_label(&format!("{}%", disk.1));
|
||||
break;
|
||||
while let Ok(stats) = stats_rx.try_recv() {
|
||||
if let Some(cpu) = stats.cpu {
|
||||
cpu_label.set_label(&format!("{}%", cpu));
|
||||
}
|
||||
if let Some(ram) = stats.ram {
|
||||
ram_label.set_label(&format!("{}%", ram));
|
||||
}
|
||||
for disk in stats.disks {
|
||||
if disk.0.eq("/") {
|
||||
disk_label.set_label(&format!("{}%", disk.1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(gpu) = stats.gpus.into_iter().next() {
|
||||
gpu_label.set_label(&format!("{}%", gpu.1));
|
||||
}
|
||||
if let Some(gpu) = stats.gpus.into_iter().next() {
|
||||
gpu_label.set_label(&format!("{}%", gpu.1));
|
||||
}
|
||||
|
||||
set_battery_css_classes(&battery_widget, stats.battery_state, stats.battery_charge);
|
||||
let idx = ((stats.battery_charge as f32 / 100.0) * (BATTERY_ICONS.len() - 1) as f32
|
||||
+ 0.5) as usize;
|
||||
let idx = idx.min(BATTERY_ICONS.len() - 1);
|
||||
battery_widget.set_title(&format!("{} {}%", BATTERY_ICONS[idx], stats.battery_charge));
|
||||
wattage.set_label(&format!(" {:.1}W", stats.battery_draw));
|
||||
remaining_time.set_label(&format!(" {}h", format_remaining(stats.battery_time)));
|
||||
set_battery_css_classes(&battery_widget, stats.battery_state, stats.battery_charge);
|
||||
let idx = ((stats.battery_charge as f32 / 100.0) * (BATTERY_ICONS.len() - 1) as f32
|
||||
+ 0.5) as usize;
|
||||
let idx = idx.min(BATTERY_ICONS.len() - 1);
|
||||
battery_widget
|
||||
.set_title(&format!("{} {}%", BATTERY_ICONS[idx], stats.battery_charge));
|
||||
wattage.set_label(&format!(" {:.1}W", stats.battery_draw));
|
||||
remaining_time.set_label(&format!(" {}h", format_remaining(stats.battery_time)));
|
||||
}
|
||||
ControlFlow::Continue
|
||||
}
|
||||
ControlFlow::Continue
|
||||
});
|
||||
utilities
|
||||
}
|
||||
|
||||
@@ -125,10 +125,6 @@ button {
|
||||
background: $background1;
|
||||
}
|
||||
|
||||
.caffeine.on {
|
||||
background: $red;
|
||||
}
|
||||
|
||||
.caffeine.idle {
|
||||
background: $yellow;
|
||||
}
|
||||
@@ -137,6 +133,10 @@ button {
|
||||
background: $green;
|
||||
}
|
||||
|
||||
.caffeine.on {
|
||||
background: $red;
|
||||
}
|
||||
|
||||
.stats {
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
@@ -2,4 +2,25 @@
|
||||
|
||||
.run-menu {
|
||||
background: $background;
|
||||
padding: 5px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid $orange;
|
||||
}
|
||||
|
||||
.exec-button {
|
||||
padding: 3px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid $background1;
|
||||
}
|
||||
|
||||
.exec-button:focus {
|
||||
border-color: $orange;
|
||||
}
|
||||
|
||||
.suggested {
|
||||
border-color: $orange;
|
||||
}
|
||||
|
||||
.exec-button:active {
|
||||
border-color: $orange;
|
||||
}
|
||||
Reference in New Issue
Block a user