1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-07-01 18:51:04 +02:00

Merge pull request #43 from JakeStanger/refactor/general

General refactoring and tidy-up
This commit is contained in:
Jake Stanger 2022-12-12 19:56:34 +00:00 committed by GitHub
commit bb81f8e583
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 686 additions and 748 deletions

257
Cargo.lock generated
View file

@ -71,11 +71,11 @@ dependencies = [
[[package]]
name = "async-channel"
version = "1.7.1"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
dependencies = [
"concurrent-queue 1.2.4",
"concurrent-queue",
"event-listener",
"futures-core",
]
@ -88,7 +88,7 @@ checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b"
dependencies = [
"async-lock",
"async-task",
"concurrent-queue 2.0.0",
"concurrent-queue",
"fastrand",
"futures-lite",
"slab",
@ -102,7 +102,7 @@ checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794"
dependencies = [
"async-lock",
"autocfg",
"concurrent-queue 2.0.0",
"concurrent-queue",
"futures-lite",
"libc",
"log",
@ -153,9 +153,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
[[package]]
name = "async-trait"
version = "0.1.58"
version = "0.1.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c"
checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
dependencies = [
"proc-macro2",
"quote",
@ -246,12 +246,6 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
[[package]]
name = "cache-padded"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
[[package]]
name = "cairo-rs"
version = "0.16.3"
@ -279,12 +273,12 @@ dependencies = [
[[package]]
name = "calloop"
version = "0.10.3"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bcf530afb40e45e14440701e5e996d7fd139e84a912a4d83a8d6a0fb3e58663"
checksum = "19457a0da465234abd76134a5c2a910c14bd3c5558463e4396ab9a37a328e465"
dependencies = [
"log",
"nix 0.25.0",
"nix 0.25.1",
"slotmap",
"thiserror",
"vec_map",
@ -363,15 +357,6 @@ dependencies = [
"tracing-error",
]
[[package]]
name = "concurrent-queue"
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c"
dependencies = [
"cache-padded",
]
[[package]]
name = "concurrent-queue"
version = "2.0.0"
@ -451,9 +436,9 @@ dependencies = [
[[package]]
name = "cxx"
version = "1.0.82"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453"
checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf"
dependencies = [
"cc",
"cxxbridge-flags",
@ -463,9 +448,9 @@ dependencies = [
[[package]]
name = "cxx-build"
version = "1.0.82"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0"
checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39"
dependencies = [
"cc",
"codespan-reporting",
@ -478,56 +463,21 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
version = "1.0.82"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71"
checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12"
[[package]]
name = "cxxbridge-macro"
version = "1.0.82"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470"
checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "darling"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "derivative"
version = "2.2.0"
@ -539,37 +489,6 @@ dependencies = [
"syn",
]
[[package]]
name = "derive_builder"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3"
dependencies = [
"derive_builder_macro",
]
[[package]]
name = "derive_builder_core"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive_builder_macro"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68"
dependencies = [
"derive_builder_core",
"syn",
]
[[package]]
name = "digest"
version = "0.10.6"
@ -679,9 +598,9 @@ dependencies = [
[[package]]
name = "filetime"
version = "0.2.18"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3"
checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9"
dependencies = [
"cfg-if",
"libc",
@ -689,12 +608,6 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "futures-channel"
version = "0.3.25"
@ -782,9 +695,9 @@ dependencies = [
[[package]]
name = "gdk"
version = "0.16.0"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f0a4a7aa015962d02634258715164977eb151b48fd250dcac48fab8d312a5aa"
checksum = "aa9cb33da481c6c040404a11f8212d193889e9b435db2c14fd86987f630d3ce1"
dependencies = [
"bitflags",
"cairo-rs",
@ -798,9 +711,9 @@ dependencies = [
[[package]]
name = "gdk-pixbuf"
version = "0.16.3"
version = "0.16.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ba3e42776d1466938add08211734738d5c76e863a25b7a8064c4433a74a1a26"
checksum = "d3094f2b8578136d1929cade4e0fff82f573521b579e96cfc24af2458431f176"
dependencies = [
"bitflags",
"gdk-pixbuf-sys",
@ -901,9 +814,9 @@ dependencies = [
[[package]]
name = "glib"
version = "0.16.3"
version = "0.16.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50feee2f1e73be50e6634c901bfced69a0937c5e4e4673067ade85e093fa9bd7"
checksum = "0cd04d150a2c63e6779f43aec7e04f5374252479b7bed5f45146d9c0e821f161"
dependencies = [
"bitflags",
"futures-channel",
@ -959,9 +872,9 @@ dependencies = [
[[package]]
name = "gtk"
version = "0.16.1"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca4ab4a5a19d45748f405d2e00201e86d351e80cc13b9d43dfb9be35033a8bd6"
checksum = "e4d3507d43908c866c805f74c9dd593c0ce7ba5c38e576e41846639cdcd4bee6"
dependencies = [
"atk",
"bitflags",
@ -1091,12 +1004,6 @@ dependencies = [
"cxx-build",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indenter"
version = "0.3.3"
@ -1149,7 +1056,6 @@ dependencies = [
"async_once",
"chrono",
"color-eyre",
"derive_builder",
"dirs",
"futures-util",
"glib",
@ -1223,9 +1129,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.137"
version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "libcorn"
@ -1374,9 +1280,9 @@ dependencies = [
[[package]]
name = "nix"
version = "0.23.1"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
dependencies = [
"bitflags",
"cc",
@ -1387,9 +1293,9 @@ dependencies = [
[[package]]
name = "nix"
version = "0.24.2"
version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc"
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
dependencies = [
"bitflags",
"cfg-if",
@ -1399,9 +1305,9 @@ dependencies = [
[[package]]
name = "nix"
version = "0.25.0"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
dependencies = [
"autocfg",
"bitflags",
@ -1523,9 +1429,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "pango"
version = "0.16.3"
version = "0.16.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6a83cd4015382dbb0f4fcf3ab7b277d4885711a62b2f2c1e6582a120094edad"
checksum = "cdff66b271861037b89d028656184059e03b0b6ccb36003820be19f7200b1e94"
dependencies = [
"bitflags",
"gio",
@ -1565,9 +1471,9 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.4"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
dependencies = [
"cfg-if",
"libc",
@ -1578,9 +1484,9 @@ dependencies = [
[[package]]
name = "pest"
version = "2.5.0"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f400b0f7905bf702f9f3dc3df5a121b16c54e9e8012c082905fdf09a931861a"
checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0"
dependencies = [
"thiserror",
"ucd-trie",
@ -1588,9 +1494,9 @@ dependencies = [
[[package]]
name = "pest_derive"
version = "2.5.0"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "423c2ba011d6e27b02b482a3707c773d19aec65cc024637aec44e19652e66f63"
checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344"
dependencies = [
"pest",
"pest_generator",
@ -1598,9 +1504,9 @@ dependencies = [
[[package]]
name = "pest_generator"
version = "2.5.0"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e64e6c2c85031c02fdbd9e5c72845445ca0a724d419aa0bc068ac620c9935c1"
checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c"
dependencies = [
"pest",
"pest_meta",
@ -1611,9 +1517,9 @@ dependencies = [
[[package]]
name = "pest_meta"
version = "2.5.0"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57959b91f0a133f89a68be874a5c88ed689c19cd729ecdb5d762ebf16c64d662"
checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20"
dependencies = [
"once_cell",
"pest",
@ -1640,9 +1546,9 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]]
name = "polling"
version = "2.5.0"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7d73f1eaed1ca1fb37b54dcc9b38e3b17d6c7b8ecb7abfffcac8d0351f17d4"
checksum = "166ca89eb77fd403230b9c156612965a81e094ec6ec3aa13663d4c8b113fa748"
dependencies = [
"autocfg",
"cfg-if",
@ -1743,11 +1649,10 @@ dependencies = [
[[package]]
name = "rayon"
version = "1.6.0"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b"
checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
dependencies = [
"crossbeam-deque",
"either",
"rayon-core",
]
@ -1881,18 +1786,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.147"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.147"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4"
dependencies = [
"proc-macro2",
"quote",
@ -2014,7 +1919,7 @@ dependencies = [
"lazy_static",
"log",
"memmap2",
"nix 0.24.2",
"nix 0.24.3",
"pkg-config",
"wayland-client",
"wayland-cursor",
@ -2064,12 +1969,6 @@ dependencies = [
"vte",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "swayipc-async"
version = "2.0.1"
@ -2097,9 +1996,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.103"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
dependencies = [
"proc-macro2",
"quote",
@ -2108,9 +2007,9 @@ dependencies = [
[[package]]
name = "sysinfo"
version = "0.26.8"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29ddf41e393a9133c81d5f0974195366bd57082deac6e0eb02ed39b8341c2bb6"
checksum = "0d08ba83d6dde63d053e42d7230f0dc7f8d8efeb8d30d3681580d158156461ba"
dependencies = [
"cfg-if",
"core-foundation-sys",
@ -2226,9 +2125,9 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.22.0"
version = "1.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
dependencies = [
"autocfg",
"bytes",
@ -2240,14 +2139,14 @@ dependencies = [
"signal-hook-registry",
"socket2",
"tokio-macros",
"winapi",
"windows-sys",
]
[[package]]
name = "tokio-macros"
version = "1.8.0"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
dependencies = [
"proc-macro2",
"quote",
@ -2359,9 +2258,9 @@ dependencies = [
[[package]]
name = "typenum"
version = "1.15.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "ucd-trie"
@ -2540,7 +2439,7 @@ dependencies = [
"bitflags",
"downcast-rs",
"libc",
"nix 0.24.2",
"nix 0.24.3",
"wayland-commons",
"wayland-scanner",
"wayland-sys",
@ -2552,7 +2451,7 @@ version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902"
dependencies = [
"nix 0.24.2",
"nix 0.24.3",
"once_cell",
"smallvec",
"wayland-sys",
@ -2564,7 +2463,7 @@ version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661"
dependencies = [
"nix 0.24.2",
"nix 0.24.3",
"wayland-client",
"xcursor",
]
@ -2736,7 +2635,7 @@ dependencies = [
"futures-util",
"hex",
"lazy_static",
"nix 0.23.1",
"nix 0.23.2",
"once_cell",
"ordered-stream",
"rand",
@ -2768,9 +2667,9 @@ dependencies = [
[[package]]
name = "zbus_names"
version = "2.3.0"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d69bb79b44e1901ed8b217e485d0f01991aec574479b68cb03415f142bc7ae67"
checksum = "6c737644108627748a660d038974160e0cbb62605536091bdfa28fd7f64d43c8"
dependencies = [
"serde",
"static_assertions",
@ -2779,9 +2678,9 @@ dependencies = [
[[package]]
name = "zvariant"
version = "3.8.0"
version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c817f416f05fcbc833902f1e6064b72b1778573978cfeac54731451ccc9e207"
checksum = "56f8c89c183461e11867ded456db252eae90874bc6769b7adbea464caa777e51"
dependencies = [
"byteorder",
"enumflags2",
@ -2793,9 +2692,9 @@ dependencies = [
[[package]]
name = "zvariant_derive"
version = "3.8.0"
version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdd24fffd02794a76eb10109de463444064c88f5adb9e9d1a78488adc332bfef"
checksum = "155247a5d1ab55e335421c104ccd95d64f17cebbd02f50cdbc1c33385f9c4d81"
dependencies = [
"proc-macro-crate",
"proc-macro2",

View file

@ -6,7 +6,6 @@ license = "MIT"
description = "Customisable GTK Layer Shell wlroots/sway bar"
[dependencies]
derive_builder = "0.11.2"
gtk = "0.16.0"
gtk-layer-shell = "0.5.0"
glib = "0.16.2"
@ -34,7 +33,7 @@ walkdir = "2.3.2"
notify = { version = "5.0.0", default-features = false }
mpd_client = "1.0.0"
swayipc-async = { version = "2.0.1" }
sysinfo = "0.26.4"
sysinfo = "0.27.0"
wayland-client = "0.29.5"
wayland-protocols = { version = "0.29.5", features = ["unstable_protocols", "client"] }
smithay-client-toolkit = { version = "0.16.0", default-features = false, features = ["calloop"] }

View file

@ -1,23 +1,15 @@
use crate::bridge_channel::BridgeChannel;
use crate::config::{BarPosition, ModuleConfig};
use crate::config::{BarPosition, CommonConfig, ModuleConfig};
use crate::dynamic_string::DynamicString;
use crate::modules::custom::ExecEvent;
use crate::modules::launcher::{ItemEvent, LauncherUpdate};
use crate::modules::mpd::{PlayerCommand, SongUpdate};
use crate::modules::workspaces::WorkspaceUpdate;
use crate::modules::{Module, ModuleInfoBuilder, ModuleLocation, ModuleUpdateEvent, WidgetContext};
use crate::modules::{Module, ModuleInfo, ModuleLocation, ModuleUpdateEvent, WidgetContext};
use crate::popup::Popup;
use crate::script::{OutputStream, Script};
use crate::{await_sync, Config};
use chrono::{DateTime, Local};
use crate::{await_sync, read_lock, send, write_lock, Config};
use color_eyre::Result;
use gtk::gdk::Monitor;
use gtk::prelude::*;
use gtk::{Application, ApplicationWindow, Orientation};
use std::collections::HashMap;
use gtk::{Application, ApplicationWindow, EventBox, Orientation, Widget};
use std::sync::{Arc, RwLock};
use stray::message::NotifierItemCommand;
use stray::NotifierItemMessage;
use tokio::spawn;
use tokio::sync::mpsc;
use tracing::{debug, error, info, trace};
@ -49,26 +41,11 @@ pub fn create_bar(
}
.build();
let start = gtk::Box::builder()
.orientation(orientation)
.spacing(0)
.name("start")
.build();
let center = gtk::Box::builder()
.orientation(orientation)
.spacing(0)
.name("center")
.build();
let end = gtk::Box::builder()
.orientation(orientation)
.spacing(0)
.name("end")
.build();
content.style_context().add_class("container");
start.style_context().add_class("container");
center.style_context().add_class("container");
end.style_context().add_class("container");
let start = create_container("start", orientation);
let center = create_container("center", orientation);
let end = create_container("end", orientation);
content.add(&start);
content.set_center_widget(Some(&center));
@ -84,6 +61,9 @@ pub fn create_bar(
});
debug!("Showing bar");
// show each box but do not use `show_all`.
// this ensures `show_if` option works as intended.
start.show();
center.show();
end.show();
@ -93,218 +73,6 @@ pub fn create_bar(
Ok(())
}
/// Loads the configured modules onto a bar.
fn load_modules(
left: &gtk::Box,
center: &gtk::Box,
right: &gtk::Box,
app: &Application,
config: Config,
monitor: &Monitor,
output_name: &str,
) -> Result<()> {
let mut info_builder = ModuleInfoBuilder::default();
let info_builder = info_builder
.app(app)
.bar_position(config.position)
.monitor(monitor)
.output_name(output_name);
if let Some(modules) = config.start {
let info_builder = info_builder.location(ModuleLocation::Left);
add_modules(left, modules, info_builder)?;
}
if let Some(modules) = config.center {
let info_builder = info_builder.location(ModuleLocation::Center);
add_modules(center, modules, info_builder)?;
}
if let Some(modules) = config.end {
let info_builder = info_builder.location(ModuleLocation::Right);
add_modules(right, modules, info_builder)?;
}
Ok(())
}
/// Adds modules into a provided GTK box,
/// which should be one of its left, center or right containers.
fn add_modules(
content: &gtk::Box,
modules: Vec<ModuleConfig>,
info_builder: &mut ModuleInfoBuilder,
) -> Result<()> {
let base_popup_info = info_builder.module_name("").build()?;
let popup = Popup::new(&base_popup_info);
let popup = Arc::new(RwLock::new(popup));
macro_rules! add_module {
($module:expr, $id:expr, $name:literal, $send_message:ty, $receive_message:ty) => {
let info = info_builder.module_name($name).build()?;
let (w_tx, w_rx) = glib::MainContext::channel::<$send_message>(glib::PRIORITY_DEFAULT);
let (p_tx, p_rx) = glib::MainContext::channel::<$send_message>(glib::PRIORITY_DEFAULT);
let channel = BridgeChannel::<ModuleUpdateEvent<$send_message>>::new();
let (ui_tx, ui_rx) = mpsc::channel::<$receive_message>(16);
$module.spawn_controller(&info, channel.create_sender(), ui_rx)?;
let context = WidgetContext {
id: $id,
widget_rx: w_rx,
popup_rx: p_rx,
tx: channel.create_sender(),
controller_tx: ui_tx,
};
let common = $module.common.clone();
let widget = $module.into_widget(context, &info)?;
let container = gtk::EventBox::new();
container.add(&widget.widget);
content.add(&container);
widget.widget.set_widget_name(info.module_name);
if let Some(show_if) = common.show_if {
let script = Script::new_polling(show_if);
let container = container.clone();
let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
spawn(async move {
script
.run(|(_, success)| {
tx.send(success)
.expect("Failed to send widget visibility toggle message");
})
.await;
});
rx.attach(None, move |success| {
if success {
container.show_all()
} else {
container.hide()
};
Continue(true)
});
} else {
container.show_all();
}
if let Some(on_click) = common.on_click {
let script = Script::new_polling(on_click);
container.connect_button_press_event(move |_, _| {
trace!("Running on-click script");
match await_sync(async { script.get_output().await }) {
Ok((OutputStream::Stderr(out), _)) => error!("{out}"),
Err(err) => error!("{err:?}"),
_ => {}
}
Inhibit(false)
});
}
if let Some(tooltip) = common.tooltip {
DynamicString::new(&tooltip, move |string| {
container.set_tooltip_text(Some(&string));
Continue(true)
});
}
let has_popup = widget.popup.is_some();
if let Some(popup_content) = widget.popup {
popup
.write()
.expect("Failed to get write lock on popup")
.register_content($id, popup_content);
}
let popup2 = Arc::clone(&popup);
channel.recv(move |ev| {
let popup = popup2.clone();
match ev {
ModuleUpdateEvent::Update(update) => {
if has_popup {
p_tx.send(update.clone())
.expect("Failed to send update to popup");
}
w_tx.send(update).expect("Failed to send update to module");
}
ModuleUpdateEvent::TogglePopup(geometry) => {
debug!("Toggling popup for {} [#{}]", $name, $id);
let popup = popup.read().expect("Failed to get read lock on popup");
if popup.is_visible() {
popup.hide()
} else {
popup.show_content($id);
popup.show(geometry);
}
}
ModuleUpdateEvent::OpenPopup(geometry) => {
debug!("Opening popup for {} [#{}]", $name, $id);
let popup = popup.read().expect("Failed to get read lock on popup");
popup.hide();
popup.show_content($id);
popup.show(geometry);
}
ModuleUpdateEvent::ClosePopup => {
debug!("Closing popup for {} [#{}]", $name, $id);
let popup = popup.read().expect("Failed to get read lock on popup");
popup.hide();
}
}
Continue(true)
});
};
}
for (id, config) in modules.into_iter().enumerate() {
match config {
ModuleConfig::Clock(module) => {
add_module!(module, id, "clock", DateTime<Local>, ());
}
ModuleConfig::Script(module) => {
add_module!(module, id, "script", String, ());
}
ModuleConfig::SysInfo(module) => {
add_module!(module, id, "sysinfo", HashMap<String, String>, ());
}
ModuleConfig::Focused(module) => {
add_module!(module, id, "focused", (String, String), ());
}
ModuleConfig::Workspaces(module) => {
add_module!(module, id, "workspaces", WorkspaceUpdate, String);
}
ModuleConfig::Tray(module) => {
add_module!(module, id, "tray", NotifierItemMessage, NotifierItemCommand);
}
ModuleConfig::Mpd(module) => {
add_module!(module, id, "mpd", Option<SongUpdate>, PlayerCommand);
}
ModuleConfig::Launcher(module) => {
add_module!(module, id, "launcher", LauncherUpdate, ItemEvent);
}
ModuleConfig::Custom(module) => {
add_module!(module, id, "custom", (), ExecEvent);
}
}
}
Ok(())
}
/// Sets up GTK layer shell for a provided application window.
fn setup_layer_shell(
win: &ApplicationWindow,
@ -349,3 +117,251 @@ fn setup_layer_shell(
|| (bar_orientation == Orientation::Horizontal && anchor_to_edges),
);
}
/// Creates a `gtk::Box` container to place widgets inside.
fn create_container(name: &str, orientation: Orientation) -> gtk::Box {
let container = gtk::Box::builder()
.orientation(orientation)
.spacing(0)
.name(name)
.build();
container.style_context().add_class("container");
container
}
/// Loads the configured modules onto a bar.
fn load_modules(
left: &gtk::Box,
center: &gtk::Box,
right: &gtk::Box,
app: &Application,
config: Config,
monitor: &Monitor,
output_name: &str,
) -> Result<()> {
macro_rules! info {
($location:expr) => {
ModuleInfo {
app,
bar_position: config.position,
monitor,
output_name,
location: $location,
}
};
}
if let Some(modules) = config.start {
let info = info!(ModuleLocation::Left);
add_modules(left, modules, &info)?;
}
if let Some(modules) = config.center {
let info = info!(ModuleLocation::Center);
add_modules(center, modules, &info)?;
}
if let Some(modules) = config.end {
let info = info!(ModuleLocation::Right);
add_modules(right, modules, &info)?;
}
Ok(())
}
/// Adds modules into a provided GTK box,
/// which should be one of its left, center or right containers.
fn add_modules(content: &gtk::Box, modules: Vec<ModuleConfig>, info: &ModuleInfo) -> Result<()> {
let popup = Popup::new(info);
let popup = Arc::new(RwLock::new(popup));
macro_rules! add_module {
($module:expr, $id:expr) => {{
let common = $module.common.take().expect("Common config did not exist");
let widget = create_module($module, $id, &info, &Arc::clone(&popup))?;
let container = wrap_widget(&widget);
content.add(&container);
setup_module_common_options(container, common);
}};
}
for (id, config) in modules.into_iter().enumerate() {
match config {
ModuleConfig::Clock(mut module) => add_module!(module, id),
ModuleConfig::Script(mut module) => add_module!(module, id),
ModuleConfig::SysInfo(mut module) => add_module!(module, id),
ModuleConfig::Focused(mut module) => add_module!(module, id),
ModuleConfig::Workspaces(mut module) => add_module!(module, id),
ModuleConfig::Tray(mut module) => add_module!(module, id),
ModuleConfig::Mpd(mut module) => add_module!(module, id),
ModuleConfig::Launcher(mut module) => add_module!(module, id),
ModuleConfig::Custom(mut module) => add_module!(module, id),
}
}
Ok(())
}
/// Creates a module and sets it up.
/// This setup includes widget/popup content and event channels.
fn create_module<TModule, TWidget, TSend, TRec>(
module: TModule,
id: usize,
info: &ModuleInfo,
popup: &Arc<RwLock<Popup>>,
) -> Result<TWidget>
where
TModule: Module<TWidget, SendMessage = TSend, ReceiveMessage = TRec>,
TWidget: IsA<Widget>,
TSend: Clone + Send + 'static,
{
let (w_tx, w_rx) = glib::MainContext::channel::<TSend>(glib::PRIORITY_DEFAULT);
let (p_tx, p_rx) = glib::MainContext::channel::<TSend>(glib::PRIORITY_DEFAULT);
let channel = BridgeChannel::<ModuleUpdateEvent<TSend>>::new();
let (ui_tx, ui_rx) = mpsc::channel::<TRec>(16);
module.spawn_controller(info, channel.create_sender(), ui_rx)?;
let context = WidgetContext {
id,
widget_rx: w_rx,
popup_rx: p_rx,
tx: channel.create_sender(),
controller_tx: ui_tx,
};
let name = TModule::name();
let module_parts = module.into_widget(context, info)?;
module_parts.widget.set_widget_name(name);
let mut has_popup = false;
if let Some(popup_content) = module_parts.popup {
register_popup_content(popup, id, popup_content);
has_popup = true;
}
setup_receiver(channel, w_tx, p_tx, popup.clone(), name, id, has_popup);
Ok(module_parts.widget)
}
/// Registers the popup content with the popup.
fn register_popup_content(popup: &Arc<RwLock<Popup>>, id: usize, popup_content: gtk::Box) {
write_lock!(popup).register_content(id, popup_content);
}
/// Sets up the bridge channel receiver
/// to pick up events from the controller, widget or popup.
///
/// Handles opening/closing popups
/// and communicating update messages between controllers and widgets/popups.
fn setup_receiver<TSend>(
channel: BridgeChannel<ModuleUpdateEvent<TSend>>,
w_tx: glib::Sender<TSend>,
p_tx: glib::Sender<TSend>,
popup: Arc<RwLock<Popup>>,
name: &'static str,
id: usize,
has_popup: bool,
) where
TSend: Clone + Send + 'static,
{
channel.recv(move |ev| {
match ev {
ModuleUpdateEvent::Update(update) => {
if has_popup {
send!(p_tx, update.clone());
}
send!(w_tx, update);
}
ModuleUpdateEvent::TogglePopup(geometry) => {
debug!("Toggling popup for {} [#{}]", name, id);
let popup = read_lock!(popup);
if popup.is_visible() {
popup.hide();
} else {
popup.show_content(id);
popup.show(geometry);
}
}
ModuleUpdateEvent::OpenPopup(geometry) => {
debug!("Opening popup for {} [#{}]", name, id);
let popup = read_lock!(popup);
popup.hide();
popup.show_content(id);
popup.show(geometry);
}
ModuleUpdateEvent::ClosePopup => {
debug!("Closing popup for {} [#{}]", name, id);
let popup = read_lock!(popup);
popup.hide();
}
}
Continue(true)
});
}
/// Takes a widget and adds it into a new `gtk::EventBox`.
/// The event box container is returned.
fn wrap_widget<W: IsA<Widget>>(widget: &W) -> EventBox {
let container = EventBox::new();
container.add(widget);
container
}
/// Configures the module's container according to the common config options.
fn setup_module_common_options(container: EventBox, common: CommonConfig) {
common.show_if.map_or_else(
|| {
container.show_all();
},
|show_if| {
let script = Script::new_polling(show_if);
let container = container.clone();
let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
spawn(async move {
script
.run(|(_, success)| {
send!(tx, success);
})
.await;
});
rx.attach(None, move |success| {
if success {
container.show_all();
} else {
container.hide();
};
Continue(true)
});
},
);
if let Some(on_click) = common.on_click {
let script = Script::new_polling(on_click);
container.connect_button_press_event(move |_, _| {
trace!("Running on-click script");
match await_sync(async { script.get_output().await }) {
Ok((OutputStream::Stderr(out), _)) => error!("{out}"),
Err(err) => error!("{err:?}"),
_ => {}
}
Inhibit(false)
});
}
if let Some(tooltip) = common.tooltip {
DynamicString::new(&tooltip, move |string| {
container.set_tooltip_text(Some(&string));
Continue(true)
});
}
}

View file

@ -1,3 +1,4 @@
use crate::send;
use tokio::spawn;
use tokio::sync::mpsc;
@ -21,7 +22,7 @@ impl<T: Send + 'static> BridgeChannel<T> {
spawn(async move {
while let Some(val) = async_rx.recv().await {
sync_tx.send(val).expect("Failed to send message");
send!(sync_tx, val);
}
});

View file

@ -2,6 +2,7 @@ use super::toplevel::{ToplevelEvent, ToplevelInfo};
use super::toplevel_manager::listen_for_toplevels;
use super::ToplevelChange;
use super::{Env, ToplevelHandler};
use crate::{error as err, send, write_lock};
use color_eyre::Report;
use indexmap::IndexMap;
use smithay_client_toolkit::environment::Environment;
@ -46,19 +47,16 @@ impl WaylandClient {
.expect("Failed to connect to Wayland compositor");
let outputs = Self::get_outputs(&env);
output_tx
.send(outputs)
.expect("Failed to send outputs out of task");
send!(output_tx, outputs);
let seats = env.get_all_seats();
seat_tx
.send(
seats
.into_iter()
.map(|seat| seat.detach())
.collect::<Vec<WlSeat>>(),
)
.expect("Failed to send seats out of task");
send!(
seat_tx,
seats
.into_iter()
.map(|seat| seat.detach())
.collect::<Vec<WlSeat>>()
);
let _toplevel_manager = env.require_global::<ZwlrForeignToplevelManagerV1>();
@ -66,20 +64,13 @@ impl WaylandClient {
trace!("Received toplevel event: {:?}", event);
if event.change == ToplevelChange::Close {
toplevels2
.write()
.expect("Failed to get write lock on toplevels")
.remove(&event.toplevel.id);
write_lock!(toplevels2).remove(&event.toplevel.id);
} else {
toplevels2
.write()
.expect("Failed to get write lock on toplevels")
write_lock!(toplevels2)
.insert(event.toplevel.id, (event.toplevel.clone(), handle));
}
toplevel_tx2
.send(event)
.expect("Failed to send toplevel event");
send!(toplevel_tx2, event);
});
let mut event_loop =
@ -99,11 +90,9 @@ impl WaylandClient {
}
});
let outputs = output_rx
.await
.expect("Failed to receive outputs from task");
let outputs = output_rx.await.expect(err::ERR_CHANNEL_RECV);
let seats = seat_rx.await.expect("Failed to receive seats from task");
let seats = seat_rx.await.expect(err::ERR_CHANNEL_RECV);
Self {
outputs,

View file

@ -4,11 +4,13 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use tracing::trace;
use wayland_client::{DispatchData, Main};
use wayland_protocols::wlr::unstable::foreign_toplevel::v1::client::zwlr_foreign_toplevel_handle_v1::{Event, ZwlrForeignToplevelHandleV1};
use crate::write_lock;
const STATE_ACTIVE: u32 = 2;
const STATE_FULLSCREEN: u32 = 3;
static COUNTER: AtomicUsize = AtomicUsize::new(1);
fn get_id() -> usize {
COUNTER.fetch_add(1, Ordering::Relaxed)
}
@ -108,9 +110,9 @@ where
None
}
}
Event::OutputEnter { output: _ } => None,
Event::OutputLeave { output: _ } => None,
Event::Parent { parent: _ } => None,
Event::OutputEnter { output: _ }
| Event::OutputLeave { output: _ }
| Event::Parent { parent: _ } => None,
Event::Done => {
if info.ready || info.app_id.is_empty() {
None
@ -119,6 +121,7 @@ where
Some(ToplevelChange::New)
}
}
_ => unreachable!(),
};
@ -140,9 +143,7 @@ impl Toplevel {
let inner = Arc::new(RwLock::new(ToplevelInfo::new()));
handle.quick_assign(move |_handle, event, ddata| {
let mut inner = inner
.write()
.expect("Failed to get write lock on toplevel inner state");
let mut inner = write_lock!(inner);
toplevel_implem(event, &mut inner, &mut callback, ddata);
});

View file

@ -63,6 +63,8 @@ impl Default for BarPosition {
}
impl BarPosition {
/// Gets the orientation the bar and widgets should use
/// based on this position.
pub fn get_orientation(self) -> Orientation {
if self == Self::Top || self == Self::Bottom {
Orientation::Horizontal
@ -71,6 +73,8 @@ impl BarPosition {
}
}
/// Gets the angle that label text should be displayed at
/// based on this position.
pub const fn get_angle(self) -> f64 {
match self {
Self::Top | Self::Bottom => 0.0,

View file

@ -1,4 +1,5 @@
use crate::script::{OutputStream, Script};
use crate::{lock, send};
use gtk::prelude::*;
use indexmap::IndexMap;
use std::sync::{Arc, Mutex};
@ -10,9 +11,7 @@ enum DynamicStringSegment {
Dynamic(Script),
}
pub struct DynamicString {
// pub label: gtk::Label,
}
pub struct DynamicString;
impl DynamicString {
pub fn new<F>(input: &str, f: F) -> Self
@ -67,10 +66,7 @@ impl DynamicString {
for (i, segment) in segments.into_iter().enumerate() {
match segment {
DynamicStringSegment::Static(str) => {
label_parts
.lock()
.expect("Failed to get lock on label parts")
.insert(i, str);
lock!(label_parts).insert(i, str);
}
DynamicStringSegment::Dynamic(script) => {
let tx = tx.clone();
@ -80,21 +76,16 @@ impl DynamicString {
script
.run(|(out, _)| {
if let OutputStream::Stdout(out) = out {
let mut label_parts = label_parts
.lock()
.expect("Failed to get lock on label parts");
let mut label_parts = lock!(label_parts);
label_parts
// .lock()
// .expect("Failed to get lock on label parts")
.insert(i, out);
label_parts.insert(i, out);
let string = label_parts
.iter()
.map(|(_, part)| part.as_str())
.collect::<String>();
tx.send(string).expect("Failed to send update");
send!(tx, string);
}
})
.await;
@ -105,20 +96,17 @@ impl DynamicString {
// initialize
{
let label_parts = label_parts
.lock()
.expect("Failed to get lock on label parts")
let label_parts = lock!(label_parts)
.iter()
.map(|(_, part)| part.as_str())
.collect::<String>();
tx.send(label_parts).expect("Failed to send update");
send!(tx, label_parts);
}
rx.attach(None, f);
// Self { label }
Self {}
Self
}
}

13
src/error.rs Normal file
View file

@ -0,0 +1,13 @@
#[repr(i32)]
pub enum ExitCode {
GtkDisplay = 1,
CreateBars = 2,
Config = 3,
}
pub const ERR_OUTPUTS: &str = "GTK and Sway are reporting a different set of outputs - this is a severe bug and should never happen";
pub const ERR_MUTEX_LOCK: &str = "Failed to get lock on Mutex";
pub const ERR_READ_LOCK: &str = "Failed to get read lock";
pub const ERR_WRITE_LOCK: &str = "Failed to get write lock";
pub const ERR_CHANNEL_SEND: &str = "Failed to send message to channel";
pub const ERR_CHANNEL_RECV: &str = "Failed to receive message from channel";

View file

@ -1,7 +1,8 @@
use color_eyre::Result;
use dirs::data_dir;
use std::env;
use std::{env, panic};
use strip_ansi_escapes::Writer;
use tracing::error;
use tracing_appender::non_blocking::{NonBlocking, WorkerGuard};
use tracing_error::ErrorLayer;
use tracing_subscriber::fmt::{Layer, MakeWriter};
@ -26,11 +27,34 @@ impl<'a> MakeWriter<'a> for MakeFileWriter {
}
}
pub fn install_logging() -> Result<WorkerGuard> {
// Disable backtraces by default
if env::var("RUST_LIB_BACKTRACE").is_err() {
env::set_var("RUST_LIB_BACKTRACE", "0");
}
// keep guard in scope
// otherwise file logging drops
let guard = install_tracing()?;
let hook_builder = color_eyre::config::HookBuilder::default();
let (panic_hook, eyre_hook) = hook_builder.into_hooks();
eyre_hook.install()?;
// custom hook allows tracing_appender to capture panics
panic::set_hook(Box::new(move |panic_info| {
error!("{}", panic_hook.panic_report(panic_info));
}));
Ok(guard)
}
/// Installs tracing into the current application.
///
/// The returned `WorkerGuard` must remain in scope
/// for the lifetime of the application for logging to file to work.
pub fn install_tracing() -> Result<WorkerGuard> {
fn install_tracing() -> Result<WorkerGuard> {
const DEFAULT_LOG: &str = "info";
const DEFAULT_FILE_LOG: &str = "warn";

89
src/macros.rs Normal file
View file

@ -0,0 +1,89 @@
/// Sends a message on an asynchronous `Sender` using `send()`
/// Panics if the message cannot be sent.
///
/// Usage:
///
/// ```rs
/// send_async!(tx, "my message");
/// ```
#[macro_export]
macro_rules! send_async {
($tx:expr, $msg:expr) => {
$tx.send($msg).await.expect($crate::error::ERR_CHANNEL_SEND)
};
}
/// Sends a message on an synchronous `Sender` using `send()`
/// Panics if the message cannot be sent.
///
/// Usage:
///
/// ```rs
/// send!(tx, "my message");
/// ```
#[macro_export]
macro_rules! send {
($tx:expr, $msg:expr) => {
$tx.send($msg).expect($crate::error::ERR_CHANNEL_SEND)
};
}
/// Sends a message on an synchronous `Sender` using `try_send()`
/// Panics if the message cannot be sent.
///
/// Usage:
///
/// ```rs
/// try_send!(tx, "my message");
/// ```
#[macro_export]
macro_rules! try_send {
($tx:expr, $msg:expr) => {
$tx.try_send($msg).expect($crate::error::ERR_CHANNEL_SEND)
};
}
/// Locks a `Mutex`.
/// Panics if the `Mutex` cannot be locked.
///
/// Usage:
///
/// ```rs
/// let mut val = lock!(my_mutex);
/// ```
#[macro_export]
macro_rules! lock {
($mutex:expr) => {
$mutex.lock().expect($crate::error::ERR_MUTEX_LOCK)
};
}
/// Gets a read lock on a `RwLock`.
/// Panics if the `RwLock` cannot be locked.
///
/// Usage:
///
/// ```rs
/// let val = read_lock!(my_rwlock);
/// ```
#[macro_export]
macro_rules! read_lock {
($rwlock:expr) => {
$rwlock.read().expect($crate::error::ERR_READ_LOCK)
};
}
/// Gets a write lock on a `RwLock`.
/// Panics if the `RwLock` cannot be locked.
///
/// Usage:
///
/// ```rs
/// let mut val = write_lock!(my_rwlock);
/// ```
#[macro_export]
macro_rules! write_lock {
($rwlock:expr) => {
$rwlock.write().expect($crate::error::ERR_WRITE_LOCK)
};
}

View file

@ -3,8 +3,10 @@ mod bridge_channel;
mod clients;
mod config;
mod dynamic_string;
mod error;
mod icon;
mod logging;
mod macros;
mod modules;
mod popup;
mod script;
@ -19,62 +21,37 @@ use dirs::config_dir;
use gtk::gdk::Display;
use gtk::prelude::*;
use gtk::Application;
use std::env;
use std::future::Future;
use std::path::PathBuf;
use std::process::exit;
use std::{env, panic};
use tokio::runtime::Handle;
use tokio::task::block_in_place;
use crate::logging::install_tracing;
use crate::error::ExitCode;
use clients::wayland::{self, WaylandClient};
use tracing::{debug, error, info};
const GTK_APP_ID: &str = "dev.jstanger.ironbar";
const VERSION: &str = env!("CARGO_PKG_VERSION");
#[repr(i32)]
enum ErrorCode {
GtkDisplay = 1,
CreateBars = 2,
Config = 3,
}
#[tokio::main]
async fn main() -> Result<()> {
// Disable backtraces by default
if env::var("RUST_LIB_BACKTRACE").is_err() {
env::set_var("RUST_LIB_BACKTRACE", "0");
}
// keep guard in scope
// otherwise file logging drops
let _guard = install_tracing()?;
let hook_builder = color_eyre::config::HookBuilder::default();
let (panic_hook, eyre_hook) = hook_builder.into_hooks();
eyre_hook.install()?;
// custom hook allows tracing_appender to capture panics
panic::set_hook(Box::new(move |panic_info| {
error!("{}", panic_hook.panic_report(panic_info));
}));
let _guard = logging::install_logging();
info!("Ironbar version {}", VERSION);
info!("Starting application");
let wayland_client = wayland::get_client().await;
let app = Application::builder()
.application_id("dev.jstanger.ironbar")
.build();
let app = Application::builder().application_id(GTK_APP_ID).build();
app.connect_activate(move |app| {
let display = Display::default().map_or_else(
|| {
let report = Report::msg("Failed to get default GTK display");
error!("{:?}", report);
exit(ErrorCode::GtkDisplay as i32)
exit(ExitCode::GtkDisplay as i32)
},
|display| display,
);
@ -83,14 +60,14 @@ async fn main() -> Result<()> {
Ok(config) => config,
Err(err) => {
error!("{:?}", err);
exit(ErrorCode::Config as i32)
exit(ExitCode::Config as i32)
}
};
debug!("Loaded config file");
if let Err(err) = create_bars(app, &display, wayland_client, &config) {
error!("{:?}", err);
exit(ErrorCode::CreateBars as i32);
exit(ExitCode::CreateBars as i32);
}
debug!("Created bars");
@ -101,7 +78,7 @@ async fn main() -> Result<()> {
|| {
let report = Report::msg("Failed to locate user config dir");
error!("{:?}", report);
exit(ErrorCode::CreateBars as i32);
exit(ExitCode::CreateBars as i32);
},
|dir| dir.join("ironbar").join("style.css"),
)
@ -136,11 +113,14 @@ fn create_bars(
let num_monitors = display.n_monitors();
for i in 0..num_monitors {
let monitor = display.monitor(i).ok_or_else(|| Report::msg("GTK and Sway are reporting a different set of outputs - this is a severe bug and should never happen"))?;
let output = outputs.get(i as usize).ok_or_else(|| Report::msg("GTK and Sway are reporting a different set of outputs - this is a severe bug and should never happen"))?;
let monitor = display
.monitor(i)
.ok_or_else(|| Report::msg(error::ERR_OUTPUTS))?;
let output = outputs
.get(i as usize)
.ok_or_else(|| Report::msg(error::ERR_OUTPUTS))?;
let monitor_name = &output.name;
// TODO: Could we use an Arc<Config> or `Cow<Config>` here to avoid cloning?
config.monitors.as_ref().map_or_else(
|| {
info!("Creating bar on '{}'", monitor_name);
@ -178,6 +158,8 @@ fn create_bars(
/// Do note it must be called from within a Tokio runtime still.
///
/// Use sparingly! Prefer async functions wherever possible.
///
/// TODO: remove all instances of this once async trait funcs are stable
pub fn await_sync<F: Future>(f: F) -> F::Output {
block_in_place(|| Handle::current().block_on(f))
}

View file

@ -1,6 +1,7 @@
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::popup::Popup;
use crate::{send_async, try_send};
use chrono::{DateTime, Local};
use color_eyre::Result;
use glib::Continue;
@ -22,7 +23,7 @@ pub struct ClockModule {
format: String,
#[serde(flatten)]
pub common: CommonConfig,
pub common: Option<CommonConfig>,
}
fn default_format() -> String {
@ -33,6 +34,10 @@ impl Module<Button> for ClockModule {
type SendMessage = DateTime<Local>;
type ReceiveMessage = ();
fn name() -> &'static str {
"clock"
}
fn spawn_controller(
&self,
_info: &ModuleInfo,
@ -42,9 +47,7 @@ impl Module<Button> for ClockModule {
spawn(async move {
loop {
let date = Local::now();
tx.send(ModuleUpdateEvent::Update(date))
.await
.expect("Failed to send date");
send_async!(tx, ModuleUpdateEvent::Update(date));
sleep(tokio::time::Duration::from_millis(500)).await;
}
});
@ -64,13 +67,10 @@ impl Module<Button> for ClockModule {
let orientation = info.bar_position.get_orientation();
button.connect_clicked(move |button| {
context
.tx
.try_send(ModuleUpdateEvent::TogglePopup(Popup::button_pos(
button,
orientation,
)))
.expect("Failed to toggle popup");
try_send!(
context.tx,
ModuleUpdateEvent::TogglePopup(Popup::button_pos(button, orientation))
);
});
let format = self.format.clone();

View file

@ -3,6 +3,7 @@ use crate::dynamic_string::DynamicString;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::popup::{ButtonGeometry, Popup};
use crate::script::Script;
use crate::{send_async, try_send};
use color_eyre::{Report, Result};
use gtk::prelude::*;
use gtk::{Button, Label, Orientation};
@ -21,7 +22,7 @@ pub struct CustomModule {
popup: Option<Vec<Widget>>,
#[serde(flatten)]
pub common: CommonConfig,
pub common: Option<CommonConfig>,
}
/// Attempts to parse an `Orientation` from `String`
@ -119,8 +120,6 @@ impl Widget {
}
label
// DynamicString::new(label, &text)
}
/// Creates a `gtk::Button` from this widget
@ -146,11 +145,13 @@ impl Widget {
if let Some(exec) = self.on_click {
button.connect_clicked(move |button| {
tx.try_send(ExecEvent {
cmd: exec.clone(),
geometry: Popup::button_pos(button, bar_orientation),
})
.expect("Failed to send exec message");
try_send!(
tx,
ExecEvent {
cmd: exec.clone(),
geometry: Popup::button_pos(button, bar_orientation),
}
);
});
}
@ -168,6 +169,10 @@ impl Module<gtk::Box> for CustomModule {
type SendMessage = ();
type ReceiveMessage = ExecEvent;
fn name() -> &'static str {
"custom"
}
fn spawn_controller(
&self,
_info: &ModuleInfo,
@ -185,17 +190,11 @@ impl Module<gtk::Box> for CustomModule {
error!("{err:?}");
}
} else if event.cmd == "popup:toggle" {
tx.send(ModuleUpdateEvent::TogglePopup(event.geometry))
.await
.expect("Failed to send open popup event");
send_async!(tx, ModuleUpdateEvent::TogglePopup(event.geometry));
} else if event.cmd == "popup:open" {
tx.send(ModuleUpdateEvent::OpenPopup(event.geometry))
.await
.expect("Failed to send open popup event");
send_async!(tx, ModuleUpdateEvent::OpenPopup(event.geometry));
} else if event.cmd == "popup:close" {
tx.send(ModuleUpdateEvent::ClosePopup)
.await
.expect("Failed to send open popup event");
send_async!(tx, ModuleUpdateEvent::ClosePopup);
} else {
error!("Received invalid command: '{}'", event.cmd);
}

View file

@ -1,7 +1,7 @@
use crate::clients::wayland::{self, ToplevelChange};
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::{await_sync, icon};
use crate::{await_sync, icon, read_lock, send_async};
use color_eyre::Result;
use glib::Continue;
use gtk::prelude::*;
@ -26,7 +26,7 @@ pub struct FocusedModule {
icon_theme: Option<String>,
#[serde(flatten)]
pub common: CommonConfig,
pub common: Option<CommonConfig>,
}
const fn default_icon_size() -> i32 {
@ -37,6 +37,10 @@ impl Module<gtk::Box> for FocusedModule {
type SendMessage = (String, String);
type ReceiveMessage = ();
fn name() -> &'static str {
"focused"
}
fn spawn_controller(
&self,
_info: &ModuleInfo,
@ -45,16 +49,15 @@ impl Module<gtk::Box> for FocusedModule {
) -> Result<()> {
let focused = await_sync(async {
let wl = wayland::get_client().await;
let toplevels = wl
.toplevels
.read()
.expect("Failed to get read lock on toplevels")
.clone();
let toplevels = read_lock!(wl.toplevels);
toplevels.into_iter().find(|(_, (top, _))| top.active)
toplevels
.iter()
.find(|(_, (top, _))| top.active)
.map(|(_, (top, _))| top.clone())
});
if let Some((_, (top, _))) = focused {
if let Some(top) = focused {
tx.try_send(ModuleUpdateEvent::Update((top.title.clone(), top.app_id)))?;
}
@ -72,12 +75,10 @@ impl Module<gtk::Box> for FocusedModule {
};
if update {
tx.send(ModuleUpdateEvent::Update((
event.toplevel.title,
event.toplevel.app_id,
)))
.await
.expect("Failed to send focus update");
send_async!(
tx,
ModuleUpdateEvent::Update((event.toplevel.title, event.toplevel.app_id))
);
}
}
});

View file

@ -4,6 +4,7 @@ use crate::icon::get_icon;
use crate::modules::launcher::{ItemEvent, LauncherUpdate};
use crate::modules::ModuleUpdateEvent;
use crate::popup::Popup;
use crate::{read_lock, try_send};
use gtk::prelude::*;
use gtk::{Button, IconTheme, Image, Orientation};
use indexmap::IndexMap;
@ -177,14 +178,12 @@ impl ItemButton {
let app_id = item.app_id.clone();
let tx = controller_tx.clone();
button.connect_clicked(move |button| {
// lazy check :|
// lazy check :| TODO: Improve this
let style_context = button.style_context();
if style_context.has_class("open") {
tx.try_send(ItemEvent::FocusItem(app_id.clone()))
.expect("Failed to send item focus event");
try_send!(tx, ItemEvent::FocusItem(app_id.clone()));
} else {
tx.try_send(ItemEvent::OpenItem(app_id.clone()))
.expect("Failed to send item open event");
try_send!(tx, ItemEvent::OpenItem(app_id.clone()));
}
});
}
@ -199,24 +198,20 @@ impl ItemButton {
let menu_state = menu_state.clone();
button.connect_enter_notify_event(move |button, _| {
let menu_state = menu_state
.read()
.expect("Failed to get read lock on item menu state");
let menu_state = read_lock!(menu_state);
if menu_state.num_windows > 1 {
tx.try_send(ModuleUpdateEvent::Update(LauncherUpdate::Hover(
app_id.clone(),
)))
.expect("Failed to send item open popup event");
try_send!(
tx,
ModuleUpdateEvent::Update(LauncherUpdate::Hover(app_id.clone(),))
);
tx.try_send(ModuleUpdateEvent::OpenPopup(Popup::button_pos(
button,
orientation,
)))
.expect("Failed to send item open popup event");
try_send!(
tx,
ModuleUpdateEvent::OpenPopup(Popup::button_pos(button, orientation,))
);
} else {
tx.try_send(ModuleUpdateEvent::ClosePopup)
.expect("Failed to send item close popup event");
try_send!(tx, ModuleUpdateEvent::ClosePopup);
}
Inhibit(false)

View file

@ -7,6 +7,7 @@ use crate::clients::wayland::{self, ToplevelChange};
use crate::config::CommonConfig;
use crate::icon::find_desktop_file;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::{lock, read_lock, try_send, write_lock};
use color_eyre::{Help, Report};
use glib::Continue;
use gtk::prelude::*;
@ -36,7 +37,7 @@ pub struct LauncherModule {
icon_theme: Option<String>,
#[serde(flatten)]
pub common: CommonConfig,
pub common: Option<CommonConfig>,
}
#[derive(Debug, Clone)]
@ -78,6 +79,10 @@ impl Module<gtk::Box> for LauncherModule {
type SendMessage = LauncherUpdate;
type ReceiveMessage = ItemEvent;
fn name() -> &'static str {
"launcher"
}
fn spawn_controller(
&self,
_info: &ModuleInfo,
@ -106,12 +111,9 @@ impl Module<gtk::Box> for LauncherModule {
let tx = tx.clone();
spawn(async move {
let wl = wayland::get_client().await;
let open_windows = wl
.toplevels
.read()
.expect("Failed to get read lock on toplevels");
let open_windows = read_lock!(wl.toplevels);
let mut items = items.lock().expect("Failed to get lock on items");
let mut items = lock!(items);
for (_, (window, _)) in open_windows.clone() {
let item = items.get_mut(&window.app_id);
@ -153,12 +155,10 @@ impl Module<gtk::Box> for LauncherModule {
let window = event.toplevel;
let app_id = window.app_id.clone();
let items = || items.lock().expect("Failed to get lock on items");
match event.change {
ToplevelChange::New => {
let new_item = {
let mut items = items();
let mut items = lock!(items);
let item = items.get_mut(&app_id);
match item {
None => {
@ -185,7 +185,7 @@ impl Module<gtk::Box> for LauncherModule {
}
ToplevelChange::Close => {
let remove_item = {
let mut items = items();
let mut items = lock!(items);
let item = items.get_mut(&app_id);
match item {
Some(item) => {
@ -214,23 +214,19 @@ impl Module<gtk::Box> for LauncherModule {
};
}
ToplevelChange::Focus(focused) => {
let update_title = if focused {
if let Some(item) = items().get_mut(&app_id) {
let mut update_title = false;
if focused {
if let Some(item) = lock!(items).get_mut(&app_id) {
item.set_window_focused(window.id, true);
// might be switching focus between windows of same app
if item.windows.len() > 1 {
item.set_window_name(window.id, window.title.clone());
true
} else {
false
update_title = true;
}
} else {
false
}
} else {
false
};
}
send_update(LauncherUpdate::Focus(app_id.clone(), focused)).await?;
@ -240,7 +236,7 @@ impl Module<gtk::Box> for LauncherModule {
}
}
ToplevelChange::Title(title) => {
if let Some(item) = items().get_mut(&app_id) {
if let Some(item) = lock!(items).get_mut(&app_id) {
item.set_window_name(window.id, title.clone());
}
@ -282,7 +278,7 @@ impl Module<gtk::Box> for LauncherModule {
);
} else {
let wl = wayland::get_client().await;
let items = items.lock().expect("Failed to get lock on items");
let items = lock!(items);
let id = match event {
ItemEvent::FocusItem(app_id) => items
@ -293,10 +289,7 @@ impl Module<gtk::Box> for LauncherModule {
};
if let Some(id) = id {
let toplevels = wl
.toplevels
.read()
.expect("Failed to get read lock on toplevels");
let toplevels = read_lock!(wl.toplevels);
let seat = wl.seats.first().expect("Failed to get Wayland seat");
if let Some((_top, handle)) = toplevels.get(&id) {
handle.activate(seat);
@ -359,10 +352,7 @@ impl Module<gtk::Box> for LauncherModule {
if let Some(button) = buttons.get(&app_id) {
button.set_open(true);
let mut menu_state = button
.menu_state
.write()
.expect("Failed to get write lock on item menu state");
let mut menu_state = write_lock!(button.menu_state);
menu_state.num_windows += 1;
}
}
@ -383,10 +373,7 @@ impl Module<gtk::Box> for LauncherModule {
}
LauncherUpdate::RemoveWindow(app_id, _) => {
if let Some(button) = buttons.get(&app_id) {
let mut menu_state = button
.menu_state
.write()
.expect("Failed to get write lock on item menu state");
let mut menu_state = write_lock!(button.menu_state);
menu_state.num_windows -= 1;
}
}
@ -459,8 +446,7 @@ impl Module<gtk::Box> for LauncherModule {
{
let tx = controller_tx.clone();
button.connect_clicked(move |button| {
tx.try_send(ItemEvent::FocusWindow(win.id))
.expect("Failed to send window click event");
try_send!(tx, ItemEvent::FocusWindow(win.id));
if let Some(win) = button.window() {
win.hide();
@ -489,8 +475,7 @@ impl Module<gtk::Box> for LauncherModule {
{
let tx = controller_tx.clone();
button.connect_clicked(move |button| {
tx.try_send(ItemEvent::FocusWindow(win.id))
.expect("Failed to send window click event");
try_send!(tx, ItemEvent::FocusWindow(win.id));
if let Some(win) = button.window() {
win.hide();

View file

@ -17,7 +17,6 @@ pub mod workspaces;
use crate::config::BarPosition;
use crate::popup::ButtonGeometry;
use color_eyre::Result;
use derive_builder::Builder;
use glib::IsA;
use gtk::gdk::Monitor;
use gtk::{Application, Widget};
@ -29,15 +28,12 @@ pub enum ModuleLocation {
Center,
Right,
}
#[derive(Builder)]
pub struct ModuleInfo<'a> {
pub app: &'a Application,
pub location: ModuleLocation,
pub bar_position: BarPosition,
pub monitor: &'a Monitor,
pub output_name: &'a str,
pub module_name: &'a str,
}
#[derive(Debug)]
@ -73,6 +69,8 @@ where
type SendMessage;
type ReceiveMessage;
fn name() -> &'static str;
fn spawn_controller(
&self,
info: &ModuleInfo,

View file

@ -2,6 +2,7 @@ use crate::clients::mpd::{get_client, get_duration, get_elapsed, MpdConnectionEr
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::popup::Popup;
use crate::try_send;
use color_eyre::Result;
use dirs::{audio_dir, home_dir};
use glib::Continue;
@ -68,7 +69,7 @@ pub struct MpdModule {
music_dir: PathBuf,
#[serde(flatten)]
pub common: CommonConfig,
pub common: Option<CommonConfig>,
}
fn default_socket() -> String {
@ -128,6 +129,10 @@ impl Module<Button> for MpdModule {
type SendMessage = Option<SongUpdate>;
type ReceiveMessage = PlayerCommand;
fn name() -> &'static str {
"mpd"
}
fn spawn_controller(
&self,
_info: &ModuleInfo,
@ -221,11 +226,10 @@ impl Module<Button> for MpdModule {
let tx = context.tx.clone();
button.connect_clicked(move |button| {
tx.try_send(ModuleUpdateEvent::TogglePopup(Popup::button_pos(
button,
orientation,
)))
.expect("Failed to send MPD popup open event");
try_send!(
tx,
ModuleUpdateEvent::TogglePopup(Popup::button_pos(button, orientation,))
);
});
}
@ -239,8 +243,7 @@ impl Module<Button> for MpdModule {
button.show();
} else {
button.hide();
tx.try_send(ModuleUpdateEvent::ClosePopup)
.expect("Failed to send close popup message");
try_send!(tx, ModuleUpdateEvent::ClosePopup);
}
Continue(true)
@ -318,31 +321,22 @@ impl Module<Button> for MpdModule {
let tx_prev = tx.clone();
btn_prev.connect_clicked(move |_| {
tx_prev
.try_send(PlayerCommand::Previous)
.expect("Failed to send prev track message");
try_send!(tx_prev, PlayerCommand::Previous);
});
let tx_toggle = tx.clone();
btn_play_pause.connect_clicked(move |_| {
tx_toggle
.try_send(PlayerCommand::Toggle)
.expect("Failed to send play/pause track message");
try_send!(tx_toggle, PlayerCommand::Toggle);
});
let tx_next = tx.clone();
btn_next.connect_clicked(move |_| {
tx_next
.try_send(PlayerCommand::Next)
.expect("Failed to send next track message");
try_send!(tx_next, PlayerCommand::Next);
});
let tx_vol = tx;
volume_slider.connect_change_value(move |_, _, val| {
tx_vol
.try_send(PlayerCommand::Volume(val as u8))
.expect("Failed to send volume message");
try_send!(tx_vol, PlayerCommand::Volume(val as u8));
Inhibit(false)
});

View file

@ -21,7 +21,7 @@ pub struct ScriptModule {
interval: u64,
#[serde(flatten)]
pub common: CommonConfig,
pub common: Option<CommonConfig>,
}
/// `Mode::Poll`
@ -48,6 +48,10 @@ impl Module<Label> for ScriptModule {
type SendMessage = String;
type ReceiveMessage = ();
fn name() -> &'static str {
"script"
}
fn spawn_controller(
&self,
_info: &ModuleInfo,

View file

@ -1,5 +1,6 @@
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::send_async;
use color_eyre::Result;
use gtk::prelude::*;
use gtk::Label;
@ -22,7 +23,7 @@ pub struct SysInfoModule {
interval: Interval,
#[serde(flatten)]
pub common: CommonConfig,
pub common: Option<CommonConfig>,
}
#[derive(Debug, Deserialize, Copy, Clone)]
@ -116,6 +117,10 @@ impl Module<gtk::Box> for SysInfoModule {
type SendMessage = HashMap<String, String>;
type ReceiveMessage = ();
fn name() -> &'static str {
"sysinfo"
}
fn spawn_controller(
&self,
_info: &ModuleInfo,
@ -135,83 +140,24 @@ impl Module<gtk::Box> for SysInfoModule {
let (refresh_tx, mut refresh_rx) = mpsc::channel(16);
// memory refresh
{
let tx = refresh_tx.clone();
spawn(async move {
loop {
tx.send(RefreshType::Memory)
.await
.expect("Failed to send memory refresh");
sleep(Duration::from_secs(interval.memory())).await;
}
});
macro_rules! spawn_refresh {
($refresh_type:expr, $func:ident) => {{
let tx = refresh_tx.clone();
spawn(async move {
loop {
send_async!(tx, $refresh_type);
sleep(Duration::from_secs(interval.$func())).await;
}
});
}};
}
// cpu refresh
{
let tx = refresh_tx.clone();
spawn(async move {
loop {
tx.send(RefreshType::Cpu)
.await
.expect("Failed to send cpu refresh");
sleep(Duration::from_secs(interval.cpu())).await;
}
});
}
// temp refresh
{
let tx = refresh_tx.clone();
spawn(async move {
loop {
tx.send(RefreshType::Temps)
.await
.expect("Failed to send temperature refresh");
sleep(Duration::from_secs(interval.temps())).await;
}
});
}
// disk refresh
{
let tx = refresh_tx.clone();
spawn(async move {
loop {
tx.send(RefreshType::Disks)
.await
.expect("Failed to send disk refresh");
sleep(Duration::from_secs(interval.disks())).await;
}
});
}
// network refresh
{
let tx = refresh_tx.clone();
spawn(async move {
loop {
tx.send(RefreshType::Network)
.await
.expect("Failed to send network refresh");
sleep(Duration::from_secs(interval.networks())).await;
}
});
}
// system refresh
{
let tx = refresh_tx;
spawn(async move {
loop {
tx.send(RefreshType::System)
.await
.expect("Failed to send system refresh");
sleep(Duration::from_secs(interval.system())).await;
}
});
}
spawn_refresh!(RefreshType::Memory, memory);
spawn_refresh!(RefreshType::Cpu, cpu);
spawn_refresh!(RefreshType::Temps, temps);
spawn_refresh!(RefreshType::Disks, disks);
spawn_refresh!(RefreshType::Network, networks);
spawn_refresh!(RefreshType::System, system);
spawn(async move {
let mut format_info = HashMap::new();
@ -228,9 +174,7 @@ impl Module<gtk::Box> for SysInfoModule {
RefreshType::System => refresh_system_tokens(&mut format_info, &sys),
};
tx.send(ModuleUpdateEvent::Update(format_info.clone()))
.await
.expect("Failed to send system info map");
send_async!(tx, ModuleUpdateEvent::Update(format_info.clone()));
}
});

View file

@ -1,7 +1,7 @@
use crate::await_sync;
use crate::clients::system_tray::get_tray_event_client;
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::{await_sync, try_send};
use color_eyre::Result;
use gtk::prelude::*;
use gtk::{IconLookupFlags, IconTheme, Image, Menu, MenuBar, MenuItem, SeparatorMenuItem};
@ -17,7 +17,7 @@ use tokio::sync::mpsc::{Receiver, Sender};
#[derive(Debug, Deserialize, Clone)]
pub struct TrayModule {
#[serde(flatten)]
pub common: CommonConfig,
pub common: Option<CommonConfig>,
}
/// Gets a GTK `Image` component
@ -70,12 +70,14 @@ fn get_menu_items(
{
let tx = tx.clone();
item.connect_activate(move |_item| {
tx.try_send(NotifierItemCommand::MenuItemClicked {
submenu_id: info.id,
menu_path: path.clone(),
notifier_address: id.clone(),
})
.expect("Failed to send menu item clicked event");
try_send!(
tx,
NotifierItemCommand::MenuItemClicked {
submenu_id: info.id,
menu_path: path.clone(),
notifier_address: id.clone(),
}
);
});
}
@ -92,6 +94,10 @@ impl Module<MenuBar> for TrayModule {
type SendMessage = NotifierItemMessage;
type ReceiveMessage = NotifierItemCommand;
fn name() -> &'static str {
"tray"
}
fn spawn_controller(
&self,
_info: &ModuleInfo,

View file

@ -1,7 +1,7 @@
use crate::await_sync;
use crate::clients::sway::{get_client, get_sub_client};
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::{await_sync, send_async, try_send};
use color_eyre::{Report, Result};
use gtk::prelude::*;
use gtk::Button;
@ -22,7 +22,7 @@ pub struct WorkspacesModule {
all_monitors: bool,
#[serde(flatten)]
pub common: CommonConfig,
pub common: Option<CommonConfig>,
}
#[derive(Clone, Debug)]
@ -53,8 +53,7 @@ fn create_button(
let tx = tx.clone();
let name = name.to_string();
button.connect_clicked(move |_item| {
tx.try_send(name.clone())
.expect("Failed to send workspace click event");
try_send!(tx, name.clone());
});
}
@ -65,6 +64,10 @@ impl Module<gtk::Box> for WorkspacesModule {
type SendMessage = WorkspaceUpdate;
type ReceiveMessage = String;
fn name() -> &'static str {
"workspaces"
}
fn spawn_controller(
&self,
info: &ModuleInfo,
@ -90,8 +93,10 @@ impl Module<gtk::Box> for WorkspacesModule {
}
};
tx.try_send(ModuleUpdateEvent::Update(WorkspaceUpdate::Init(workspaces)))
.expect("Failed to send initial workspace list");
try_send!(
tx,
ModuleUpdateEvent::Update(WorkspaceUpdate::Init(workspaces))
);
// Subscribe & send events
spawn(async move {
@ -103,9 +108,10 @@ impl Module<gtk::Box> for WorkspacesModule {
trace!("Set up Sway workspace subscription");
while let Ok(payload) = srx.recv().await {
tx.send(ModuleUpdateEvent::Update(WorkspaceUpdate::Update(payload)))
.await
.expect("Failed to send workspace update");
send_async!(
tx,
ModuleUpdateEvent::Update(WorkspaceUpdate::Update(payload))
);
}
});

View file

@ -1,3 +1,4 @@
use crate::send_async;
use color_eyre::eyre::WrapErr;
use color_eyre::{Report, Result};
use serde::Deserialize;
@ -129,12 +130,12 @@ impl From<&str> for Script {
.iter()
.take_while(|c| c.is_ascii_digit())
.collect::<String>();
(
ScriptInputToken::Interval(
interval_str.parse::<u64>().expect("Invalid interval"),
),
interval_str.len(),
)
let interval = interval_str.parse::<u64>().unwrap_or_else(|_| {
warn!("Received invalid interval in script string. Falling back to default `5000ms`.");
5000
});
(ScriptInputToken::Interval(interval), interval_str.len())
}
// watching or polling
'w' | 'p' => {
@ -262,10 +263,10 @@ impl Script {
select! {
_ = handle.wait() => break,
Ok(Some(line)) = stdout_lines.next_line() => {
tx.send(OutputStream::Stdout(line)).await.expect("Failed to send stdout");
send_async!(tx, OutputStream::Stdout(line));
}
Ok(Some(line)) = stderr_lines.next_line() => {
tx.send(OutputStream::Stderr(line)).await.expect("Failed to send stderr");
send_async!(tx, OutputStream::Stderr(line));
}
}
}

View file

@ -1,3 +1,4 @@
use crate::send;
use color_eyre::{Help, Report};
use glib::Continue;
use gtk::prelude::CssProviderExt;
@ -37,8 +38,7 @@ pub fn load_css(style_path: PathBuf) {
Ok(event) if event.kind == EventKind::Modify(ModifyKind::Data(DataChange::Any)) => {
debug!("{event:?}");
if let Some(path) = event.paths.first() {
tx.send(path.clone())
.expect("Failed to send style changed message");
send!(tx, path.clone());
}
}
Err(e) => error!("Error occurred when watching stylesheet: {:?}", e),