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

View file

@ -6,7 +6,6 @@ license = "MIT"
description = "Customisable GTK Layer Shell wlroots/sway bar" description = "Customisable GTK Layer Shell wlroots/sway bar"
[dependencies] [dependencies]
derive_builder = "0.11.2"
gtk = "0.16.0" gtk = "0.16.0"
gtk-layer-shell = "0.5.0" gtk-layer-shell = "0.5.0"
glib = "0.16.2" glib = "0.16.2"
@ -34,7 +33,7 @@ walkdir = "2.3.2"
notify = { version = "5.0.0", default-features = false } notify = { version = "5.0.0", default-features = false }
mpd_client = "1.0.0" mpd_client = "1.0.0"
swayipc-async = { version = "2.0.1" } swayipc-async = { version = "2.0.1" }
sysinfo = "0.26.4" sysinfo = "0.27.0"
wayland-client = "0.29.5" wayland-client = "0.29.5"
wayland-protocols = { version = "0.29.5", features = ["unstable_protocols", "client"] } wayland-protocols = { version = "0.29.5", features = ["unstable_protocols", "client"] }
smithay-client-toolkit = { version = "0.16.0", default-features = false, features = ["calloop"] } 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::bridge_channel::BridgeChannel;
use crate::config::{BarPosition, ModuleConfig}; use crate::config::{BarPosition, CommonConfig, ModuleConfig};
use crate::dynamic_string::DynamicString; use crate::dynamic_string::DynamicString;
use crate::modules::custom::ExecEvent; use crate::modules::{Module, ModuleInfo, ModuleLocation, ModuleUpdateEvent, WidgetContext};
use crate::modules::launcher::{ItemEvent, LauncherUpdate};
use crate::modules::mpd::{PlayerCommand, SongUpdate};
use crate::modules::workspaces::WorkspaceUpdate;
use crate::modules::{Module, ModuleInfoBuilder, ModuleLocation, ModuleUpdateEvent, WidgetContext};
use crate::popup::Popup; use crate::popup::Popup;
use crate::script::{OutputStream, Script}; use crate::script::{OutputStream, Script};
use crate::{await_sync, Config}; use crate::{await_sync, read_lock, send, write_lock, Config};
use chrono::{DateTime, Local};
use color_eyre::Result; use color_eyre::Result;
use gtk::gdk::Monitor; use gtk::gdk::Monitor;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{Application, ApplicationWindow, Orientation}; use gtk::{Application, ApplicationWindow, EventBox, Orientation, Widget};
use std::collections::HashMap;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use stray::message::NotifierItemCommand;
use stray::NotifierItemMessage;
use tokio::spawn; use tokio::spawn;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tracing::{debug, error, info, trace}; use tracing::{debug, error, info, trace};
@ -49,26 +41,11 @@ pub fn create_bar(
} }
.build(); .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"); content.style_context().add_class("container");
start.style_context().add_class("container");
center.style_context().add_class("container"); let start = create_container("start", orientation);
end.style_context().add_class("container"); let center = create_container("center", orientation);
let end = create_container("end", orientation);
content.add(&start); content.add(&start);
content.set_center_widget(Some(&center)); content.set_center_widget(Some(&center));
@ -84,6 +61,9 @@ pub fn create_bar(
}); });
debug!("Showing bar"); debug!("Showing bar");
// show each box but do not use `show_all`.
// this ensures `show_if` option works as intended.
start.show(); start.show();
center.show(); center.show();
end.show(); end.show();
@ -93,218 +73,6 @@ pub fn create_bar(
Ok(()) 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. /// Sets up GTK layer shell for a provided application window.
fn setup_layer_shell( fn setup_layer_shell(
win: &ApplicationWindow, win: &ApplicationWindow,
@ -349,3 +117,251 @@ fn setup_layer_shell(
|| (bar_orientation == Orientation::Horizontal && anchor_to_edges), || (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::spawn;
use tokio::sync::mpsc; use tokio::sync::mpsc;
@ -21,7 +22,7 @@ impl<T: Send + 'static> BridgeChannel<T> {
spawn(async move { spawn(async move {
while let Some(val) = async_rx.recv().await { 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::toplevel_manager::listen_for_toplevels;
use super::ToplevelChange; use super::ToplevelChange;
use super::{Env, ToplevelHandler}; use super::{Env, ToplevelHandler};
use crate::{error as err, send, write_lock};
use color_eyre::Report; use color_eyre::Report;
use indexmap::IndexMap; use indexmap::IndexMap;
use smithay_client_toolkit::environment::Environment; use smithay_client_toolkit::environment::Environment;
@ -46,19 +47,16 @@ impl WaylandClient {
.expect("Failed to connect to Wayland compositor"); .expect("Failed to connect to Wayland compositor");
let outputs = Self::get_outputs(&env); let outputs = Self::get_outputs(&env);
output_tx send!(output_tx, outputs);
.send(outputs)
.expect("Failed to send outputs out of task");
let seats = env.get_all_seats(); let seats = env.get_all_seats();
seat_tx send!(
.send( seat_tx,
seats seats
.into_iter() .into_iter()
.map(|seat| seat.detach()) .map(|seat| seat.detach())
.collect::<Vec<WlSeat>>(), .collect::<Vec<WlSeat>>()
) );
.expect("Failed to send seats out of task");
let _toplevel_manager = env.require_global::<ZwlrForeignToplevelManagerV1>(); let _toplevel_manager = env.require_global::<ZwlrForeignToplevelManagerV1>();
@ -66,20 +64,13 @@ impl WaylandClient {
trace!("Received toplevel event: {:?}", event); trace!("Received toplevel event: {:?}", event);
if event.change == ToplevelChange::Close { if event.change == ToplevelChange::Close {
toplevels2 write_lock!(toplevels2).remove(&event.toplevel.id);
.write()
.expect("Failed to get write lock on toplevels")
.remove(&event.toplevel.id);
} else { } else {
toplevels2 write_lock!(toplevels2)
.write()
.expect("Failed to get write lock on toplevels")
.insert(event.toplevel.id, (event.toplevel.clone(), handle)); .insert(event.toplevel.id, (event.toplevel.clone(), handle));
} }
toplevel_tx2 send!(toplevel_tx2, event);
.send(event)
.expect("Failed to send toplevel event");
}); });
let mut event_loop = let mut event_loop =
@ -99,11 +90,9 @@ impl WaylandClient {
} }
}); });
let outputs = output_rx let outputs = output_rx.await.expect(err::ERR_CHANNEL_RECV);
.await
.expect("Failed to receive outputs from task");
let seats = seat_rx.await.expect("Failed to receive seats from task"); let seats = seat_rx.await.expect(err::ERR_CHANNEL_RECV);
Self { Self {
outputs, outputs,

View file

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

View file

@ -63,6 +63,8 @@ impl Default for BarPosition {
} }
impl BarPosition { impl BarPosition {
/// Gets the orientation the bar and widgets should use
/// based on this position.
pub fn get_orientation(self) -> Orientation { pub fn get_orientation(self) -> Orientation {
if self == Self::Top || self == Self::Bottom { if self == Self::Top || self == Self::Bottom {
Orientation::Horizontal 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 { pub const fn get_angle(self) -> f64 {
match self { match self {
Self::Top | Self::Bottom => 0.0, Self::Top | Self::Bottom => 0.0,

View file

@ -1,4 +1,5 @@
use crate::script::{OutputStream, Script}; use crate::script::{OutputStream, Script};
use crate::{lock, send};
use gtk::prelude::*; use gtk::prelude::*;
use indexmap::IndexMap; use indexmap::IndexMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -10,9 +11,7 @@ enum DynamicStringSegment {
Dynamic(Script), Dynamic(Script),
} }
pub struct DynamicString { pub struct DynamicString;
// pub label: gtk::Label,
}
impl DynamicString { impl DynamicString {
pub fn new<F>(input: &str, f: F) -> Self pub fn new<F>(input: &str, f: F) -> Self
@ -67,10 +66,7 @@ impl DynamicString {
for (i, segment) in segments.into_iter().enumerate() { for (i, segment) in segments.into_iter().enumerate() {
match segment { match segment {
DynamicStringSegment::Static(str) => { DynamicStringSegment::Static(str) => {
label_parts lock!(label_parts).insert(i, str);
.lock()
.expect("Failed to get lock on label parts")
.insert(i, str);
} }
DynamicStringSegment::Dynamic(script) => { DynamicStringSegment::Dynamic(script) => {
let tx = tx.clone(); let tx = tx.clone();
@ -80,21 +76,16 @@ impl DynamicString {
script script
.run(|(out, _)| { .run(|(out, _)| {
if let OutputStream::Stdout(out) = out { if let OutputStream::Stdout(out) = out {
let mut label_parts = label_parts let mut label_parts = lock!(label_parts);
.lock()
.expect("Failed to get lock on label parts");
label_parts label_parts.insert(i, out);
// .lock()
// .expect("Failed to get lock on label parts")
.insert(i, out);
let string = label_parts let string = label_parts
.iter() .iter()
.map(|(_, part)| part.as_str()) .map(|(_, part)| part.as_str())
.collect::<String>(); .collect::<String>();
tx.send(string).expect("Failed to send update"); send!(tx, string);
} }
}) })
.await; .await;
@ -105,20 +96,17 @@ impl DynamicString {
// initialize // initialize
{ {
let label_parts = label_parts let label_parts = lock!(label_parts)
.lock()
.expect("Failed to get lock on label parts")
.iter() .iter()
.map(|(_, part)| part.as_str()) .map(|(_, part)| part.as_str())
.collect::<String>(); .collect::<String>();
tx.send(label_parts).expect("Failed to send update"); send!(tx, label_parts);
} }
rx.attach(None, f); 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 color_eyre::Result;
use dirs::data_dir; use dirs::data_dir;
use std::env; use std::{env, panic};
use strip_ansi_escapes::Writer; use strip_ansi_escapes::Writer;
use tracing::error;
use tracing_appender::non_blocking::{NonBlocking, WorkerGuard}; use tracing_appender::non_blocking::{NonBlocking, WorkerGuard};
use tracing_error::ErrorLayer; use tracing_error::ErrorLayer;
use tracing_subscriber::fmt::{Layer, MakeWriter}; 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. /// Installs tracing into the current application.
/// ///
/// The returned `WorkerGuard` must remain in scope /// The returned `WorkerGuard` must remain in scope
/// for the lifetime of the application for logging to file to work. /// 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_LOG: &str = "info";
const DEFAULT_FILE_LOG: &str = "warn"; 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 clients;
mod config; mod config;
mod dynamic_string; mod dynamic_string;
mod error;
mod icon; mod icon;
mod logging; mod logging;
mod macros;
mod modules; mod modules;
mod popup; mod popup;
mod script; mod script;
@ -19,62 +21,37 @@ use dirs::config_dir;
use gtk::gdk::Display; use gtk::gdk::Display;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::Application; use gtk::Application;
use std::env;
use std::future::Future; use std::future::Future;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::exit; use std::process::exit;
use std::{env, panic};
use tokio::runtime::Handle; use tokio::runtime::Handle;
use tokio::task::block_in_place; use tokio::task::block_in_place;
use crate::logging::install_tracing; use crate::error::ExitCode;
use clients::wayland::{self, WaylandClient}; use clients::wayland::{self, WaylandClient};
use tracing::{debug, error, info}; use tracing::{debug, error, info};
const GTK_APP_ID: &str = "dev.jstanger.ironbar";
const VERSION: &str = env!("CARGO_PKG_VERSION"); const VERSION: &str = env!("CARGO_PKG_VERSION");
#[repr(i32)]
enum ErrorCode {
GtkDisplay = 1,
CreateBars = 2,
Config = 3,
}
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
// Disable backtraces by default let _guard = logging::install_logging();
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));
}));
info!("Ironbar version {}", VERSION); info!("Ironbar version {}", VERSION);
info!("Starting application"); info!("Starting application");
let wayland_client = wayland::get_client().await; let wayland_client = wayland::get_client().await;
let app = Application::builder() let app = Application::builder().application_id(GTK_APP_ID).build();
.application_id("dev.jstanger.ironbar")
.build();
app.connect_activate(move |app| { app.connect_activate(move |app| {
let display = Display::default().map_or_else( let display = Display::default().map_or_else(
|| { || {
let report = Report::msg("Failed to get default GTK display"); let report = Report::msg("Failed to get default GTK display");
error!("{:?}", report); error!("{:?}", report);
exit(ErrorCode::GtkDisplay as i32) exit(ExitCode::GtkDisplay as i32)
}, },
|display| display, |display| display,
); );
@ -83,14 +60,14 @@ async fn main() -> Result<()> {
Ok(config) => config, Ok(config) => config,
Err(err) => { Err(err) => {
error!("{:?}", err); error!("{:?}", err);
exit(ErrorCode::Config as i32) exit(ExitCode::Config as i32)
} }
}; };
debug!("Loaded config file"); debug!("Loaded config file");
if let Err(err) = create_bars(app, &display, wayland_client, &config) { if let Err(err) = create_bars(app, &display, wayland_client, &config) {
error!("{:?}", err); error!("{:?}", err);
exit(ErrorCode::CreateBars as i32); exit(ExitCode::CreateBars as i32);
} }
debug!("Created bars"); debug!("Created bars");
@ -101,7 +78,7 @@ async fn main() -> Result<()> {
|| { || {
let report = Report::msg("Failed to locate user config dir"); let report = Report::msg("Failed to locate user config dir");
error!("{:?}", report); error!("{:?}", report);
exit(ErrorCode::CreateBars as i32); exit(ExitCode::CreateBars as i32);
}, },
|dir| dir.join("ironbar").join("style.css"), |dir| dir.join("ironbar").join("style.css"),
) )
@ -136,11 +113,14 @@ fn create_bars(
let num_monitors = display.n_monitors(); let num_monitors = display.n_monitors();
for i in 0..num_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 monitor = display
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"))?; .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; 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( config.monitors.as_ref().map_or_else(
|| { || {
info!("Creating bar on '{}'", monitor_name); 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. /// Do note it must be called from within a Tokio runtime still.
/// ///
/// Use sparingly! Prefer async functions wherever possible. /// 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 { pub fn await_sync<F: Future>(f: F) -> F::Output {
block_in_place(|| Handle::current().block_on(f)) block_in_place(|| Handle::current().block_on(f))
} }

View file

@ -1,6 +1,7 @@
use crate::config::CommonConfig; use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext}; use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::popup::Popup; use crate::popup::Popup;
use crate::{send_async, try_send};
use chrono::{DateTime, Local}; use chrono::{DateTime, Local};
use color_eyre::Result; use color_eyre::Result;
use glib::Continue; use glib::Continue;
@ -22,7 +23,7 @@ pub struct ClockModule {
format: String, format: String,
#[serde(flatten)] #[serde(flatten)]
pub common: CommonConfig, pub common: Option<CommonConfig>,
} }
fn default_format() -> String { fn default_format() -> String {
@ -33,6 +34,10 @@ impl Module<Button> for ClockModule {
type SendMessage = DateTime<Local>; type SendMessage = DateTime<Local>;
type ReceiveMessage = (); type ReceiveMessage = ();
fn name() -> &'static str {
"clock"
}
fn spawn_controller( fn spawn_controller(
&self, &self,
_info: &ModuleInfo, _info: &ModuleInfo,
@ -42,9 +47,7 @@ impl Module<Button> for ClockModule {
spawn(async move { spawn(async move {
loop { loop {
let date = Local::now(); let date = Local::now();
tx.send(ModuleUpdateEvent::Update(date)) send_async!(tx, ModuleUpdateEvent::Update(date));
.await
.expect("Failed to send date");
sleep(tokio::time::Duration::from_millis(500)).await; sleep(tokio::time::Duration::from_millis(500)).await;
} }
}); });
@ -64,13 +67,10 @@ impl Module<Button> for ClockModule {
let orientation = info.bar_position.get_orientation(); let orientation = info.bar_position.get_orientation();
button.connect_clicked(move |button| { button.connect_clicked(move |button| {
context try_send!(
.tx context.tx,
.try_send(ModuleUpdateEvent::TogglePopup(Popup::button_pos( ModuleUpdateEvent::TogglePopup(Popup::button_pos(button, orientation))
button, );
orientation,
)))
.expect("Failed to toggle popup");
}); });
let format = self.format.clone(); 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::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::popup::{ButtonGeometry, Popup}; use crate::popup::{ButtonGeometry, Popup};
use crate::script::Script; use crate::script::Script;
use crate::{send_async, try_send};
use color_eyre::{Report, Result}; use color_eyre::{Report, Result};
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{Button, Label, Orientation}; use gtk::{Button, Label, Orientation};
@ -21,7 +22,7 @@ pub struct CustomModule {
popup: Option<Vec<Widget>>, popup: Option<Vec<Widget>>,
#[serde(flatten)] #[serde(flatten)]
pub common: CommonConfig, pub common: Option<CommonConfig>,
} }
/// Attempts to parse an `Orientation` from `String` /// Attempts to parse an `Orientation` from `String`
@ -119,8 +120,6 @@ impl Widget {
} }
label label
// DynamicString::new(label, &text)
} }
/// Creates a `gtk::Button` from this widget /// Creates a `gtk::Button` from this widget
@ -146,11 +145,13 @@ impl Widget {
if let Some(exec) = self.on_click { if let Some(exec) = self.on_click {
button.connect_clicked(move |button| { button.connect_clicked(move |button| {
tx.try_send(ExecEvent { try_send!(
cmd: exec.clone(), tx,
geometry: Popup::button_pos(button, bar_orientation), ExecEvent {
}) cmd: exec.clone(),
.expect("Failed to send exec message"); geometry: Popup::button_pos(button, bar_orientation),
}
);
}); });
} }
@ -168,6 +169,10 @@ impl Module<gtk::Box> for CustomModule {
type SendMessage = (); type SendMessage = ();
type ReceiveMessage = ExecEvent; type ReceiveMessage = ExecEvent;
fn name() -> &'static str {
"custom"
}
fn spawn_controller( fn spawn_controller(
&self, &self,
_info: &ModuleInfo, _info: &ModuleInfo,
@ -185,17 +190,11 @@ impl Module<gtk::Box> for CustomModule {
error!("{err:?}"); error!("{err:?}");
} }
} else if event.cmd == "popup:toggle" { } else if event.cmd == "popup:toggle" {
tx.send(ModuleUpdateEvent::TogglePopup(event.geometry)) send_async!(tx, ModuleUpdateEvent::TogglePopup(event.geometry));
.await
.expect("Failed to send open popup event");
} else if event.cmd == "popup:open" { } else if event.cmd == "popup:open" {
tx.send(ModuleUpdateEvent::OpenPopup(event.geometry)) send_async!(tx, ModuleUpdateEvent::OpenPopup(event.geometry));
.await
.expect("Failed to send open popup event");
} else if event.cmd == "popup:close" { } else if event.cmd == "popup:close" {
tx.send(ModuleUpdateEvent::ClosePopup) send_async!(tx, ModuleUpdateEvent::ClosePopup);
.await
.expect("Failed to send open popup event");
} else { } else {
error!("Received invalid command: '{}'", event.cmd); error!("Received invalid command: '{}'", event.cmd);
} }

View file

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

View file

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

View file

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

View file

@ -17,7 +17,6 @@ pub mod workspaces;
use crate::config::BarPosition; use crate::config::BarPosition;
use crate::popup::ButtonGeometry; use crate::popup::ButtonGeometry;
use color_eyre::Result; use color_eyre::Result;
use derive_builder::Builder;
use glib::IsA; use glib::IsA;
use gtk::gdk::Monitor; use gtk::gdk::Monitor;
use gtk::{Application, Widget}; use gtk::{Application, Widget};
@ -29,15 +28,12 @@ pub enum ModuleLocation {
Center, Center,
Right, Right,
} }
#[derive(Builder)]
pub struct ModuleInfo<'a> { pub struct ModuleInfo<'a> {
pub app: &'a Application, pub app: &'a Application,
pub location: ModuleLocation, pub location: ModuleLocation,
pub bar_position: BarPosition, pub bar_position: BarPosition,
pub monitor: &'a Monitor, pub monitor: &'a Monitor,
pub output_name: &'a str, pub output_name: &'a str,
pub module_name: &'a str,
} }
#[derive(Debug)] #[derive(Debug)]
@ -73,6 +69,8 @@ where
type SendMessage; type SendMessage;
type ReceiveMessage; type ReceiveMessage;
fn name() -> &'static str;
fn spawn_controller( fn spawn_controller(
&self, &self,
info: &ModuleInfo, 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::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext}; use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::popup::Popup; use crate::popup::Popup;
use crate::try_send;
use color_eyre::Result; use color_eyre::Result;
use dirs::{audio_dir, home_dir}; use dirs::{audio_dir, home_dir};
use glib::Continue; use glib::Continue;
@ -68,7 +69,7 @@ pub struct MpdModule {
music_dir: PathBuf, music_dir: PathBuf,
#[serde(flatten)] #[serde(flatten)]
pub common: CommonConfig, pub common: Option<CommonConfig>,
} }
fn default_socket() -> String { fn default_socket() -> String {
@ -128,6 +129,10 @@ impl Module<Button> for MpdModule {
type SendMessage = Option<SongUpdate>; type SendMessage = Option<SongUpdate>;
type ReceiveMessage = PlayerCommand; type ReceiveMessage = PlayerCommand;
fn name() -> &'static str {
"mpd"
}
fn spawn_controller( fn spawn_controller(
&self, &self,
_info: &ModuleInfo, _info: &ModuleInfo,
@ -221,11 +226,10 @@ impl Module<Button> for MpdModule {
let tx = context.tx.clone(); let tx = context.tx.clone();
button.connect_clicked(move |button| { button.connect_clicked(move |button| {
tx.try_send(ModuleUpdateEvent::TogglePopup(Popup::button_pos( try_send!(
button, tx,
orientation, ModuleUpdateEvent::TogglePopup(Popup::button_pos(button, orientation,))
))) );
.expect("Failed to send MPD popup open event");
}); });
} }
@ -239,8 +243,7 @@ impl Module<Button> for MpdModule {
button.show(); button.show();
} else { } else {
button.hide(); button.hide();
tx.try_send(ModuleUpdateEvent::ClosePopup) try_send!(tx, ModuleUpdateEvent::ClosePopup);
.expect("Failed to send close popup message");
} }
Continue(true) Continue(true)
@ -318,31 +321,22 @@ impl Module<Button> for MpdModule {
let tx_prev = tx.clone(); let tx_prev = tx.clone();
btn_prev.connect_clicked(move |_| { btn_prev.connect_clicked(move |_| {
tx_prev try_send!(tx_prev, PlayerCommand::Previous);
.try_send(PlayerCommand::Previous)
.expect("Failed to send prev track message");
}); });
let tx_toggle = tx.clone(); let tx_toggle = tx.clone();
btn_play_pause.connect_clicked(move |_| { btn_play_pause.connect_clicked(move |_| {
tx_toggle try_send!(tx_toggle, PlayerCommand::Toggle);
.try_send(PlayerCommand::Toggle)
.expect("Failed to send play/pause track message");
}); });
let tx_next = tx.clone(); let tx_next = tx.clone();
btn_next.connect_clicked(move |_| { btn_next.connect_clicked(move |_| {
tx_next try_send!(tx_next, PlayerCommand::Next);
.try_send(PlayerCommand::Next)
.expect("Failed to send next track message");
}); });
let tx_vol = tx; let tx_vol = tx;
volume_slider.connect_change_value(move |_, _, val| { volume_slider.connect_change_value(move |_, _, val| {
tx_vol try_send!(tx_vol, PlayerCommand::Volume(val as u8));
.try_send(PlayerCommand::Volume(val as u8))
.expect("Failed to send volume message");
Inhibit(false) Inhibit(false)
}); });

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +1,4 @@
use crate::send_async;
use color_eyre::eyre::WrapErr; use color_eyre::eyre::WrapErr;
use color_eyre::{Report, Result}; use color_eyre::{Report, Result};
use serde::Deserialize; use serde::Deserialize;
@ -129,12 +130,12 @@ impl From<&str> for Script {
.iter() .iter()
.take_while(|c| c.is_ascii_digit()) .take_while(|c| c.is_ascii_digit())
.collect::<String>(); .collect::<String>();
(
ScriptInputToken::Interval( let interval = interval_str.parse::<u64>().unwrap_or_else(|_| {
interval_str.parse::<u64>().expect("Invalid interval"), warn!("Received invalid interval in script string. Falling back to default `5000ms`.");
), 5000
interval_str.len(), });
) (ScriptInputToken::Interval(interval), interval_str.len())
} }
// watching or polling // watching or polling
'w' | 'p' => { 'w' | 'p' => {
@ -262,10 +263,10 @@ impl Script {
select! { select! {
_ = handle.wait() => break, _ = handle.wait() => break,
Ok(Some(line)) = stdout_lines.next_line() => { 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() => { 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 color_eyre::{Help, Report};
use glib::Continue; use glib::Continue;
use gtk::prelude::CssProviderExt; 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)) => { Ok(event) if event.kind == EventKind::Modify(ModifyKind::Data(DataChange::Any)) => {
debug!("{event:?}"); debug!("{event:?}");
if let Some(path) = event.paths.first() { if let Some(path) = event.paths.first() {
tx.send(path.clone()) send!(tx, path.clone());
.expect("Failed to send style changed message");
} }
} }
Err(e) => error!("Error occurred when watching stylesheet: {:?}", e), Err(e) => error!("Error occurred when watching stylesheet: {:?}", e),