diff --git a/Cargo.lock b/Cargo.lock index f388b0a..3e5aaa6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 18ae797..d39641e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] } \ No newline at end of file diff --git a/src/bar.rs b/src/bar.rs index 48b178a..aa4e867 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -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(¢er)); @@ -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: >k::Box, - center: >k::Box, - right: >k::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: >k::Box, - modules: Vec, - info_builder: &mut ModuleInfoBuilder, -) -> Result<()> { - let base_popup_info = info_builder.module_name("").build()?; - let popup = Popup::new(&base_popup_info); - let popup = Arc::new(RwLock::new(popup)); - - macro_rules! add_module { - ($module:expr, $id:expr, $name:literal, $send_message:ty, $receive_message:ty) => { - let info = info_builder.module_name($name).build()?; - - let (w_tx, w_rx) = glib::MainContext::channel::<$send_message>(glib::PRIORITY_DEFAULT); - let (p_tx, p_rx) = glib::MainContext::channel::<$send_message>(glib::PRIORITY_DEFAULT); - - let channel = BridgeChannel::>::new(); - let (ui_tx, ui_rx) = mpsc::channel::<$receive_message>(16); - - $module.spawn_controller(&info, channel.create_sender(), ui_rx)?; - - let context = WidgetContext { - id: $id, - widget_rx: w_rx, - popup_rx: p_rx, - tx: channel.create_sender(), - controller_tx: ui_tx, - }; - - let 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, ()); - } - ModuleConfig::Script(module) => { - add_module!(module, id, "script", String, ()); - } - ModuleConfig::SysInfo(module) => { - add_module!(module, id, "sysinfo", HashMap, ()); - } - ModuleConfig::Focused(module) => { - add_module!(module, id, "focused", (String, String), ()); - } - ModuleConfig::Workspaces(module) => { - add_module!(module, id, "workspaces", WorkspaceUpdate, String); - } - ModuleConfig::Tray(module) => { - add_module!(module, id, "tray", NotifierItemMessage, NotifierItemCommand); - } - ModuleConfig::Mpd(module) => { - add_module!(module, id, "mpd", Option, PlayerCommand); - } - ModuleConfig::Launcher(module) => { - add_module!(module, id, "launcher", LauncherUpdate, ItemEvent); - } - 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: >k::Box, + center: >k::Box, + right: >k::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: >k::Box, modules: Vec, 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( + module: TModule, + id: usize, + info: &ModuleInfo, + popup: &Arc>, +) -> Result +where + TModule: Module, + TWidget: IsA, + TSend: Clone + Send + 'static, +{ + let (w_tx, w_rx) = glib::MainContext::channel::(glib::PRIORITY_DEFAULT); + let (p_tx, p_rx) = glib::MainContext::channel::(glib::PRIORITY_DEFAULT); + + let channel = BridgeChannel::>::new(); + let (ui_tx, ui_rx) = mpsc::channel::(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>, 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( + channel: BridgeChannel>, + w_tx: glib::Sender, + p_tx: glib::Sender, + popup: Arc>, + 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>(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) + }); + } +} diff --git a/src/bridge_channel.rs b/src/bridge_channel.rs index ed516e5..2208e0c 100644 --- a/src/bridge_channel.rs +++ b/src/bridge_channel.rs @@ -1,3 +1,4 @@ +use crate::send; use tokio::spawn; use tokio::sync::mpsc; @@ -21,7 +22,7 @@ impl BridgeChannel { spawn(async move { while let Some(val) = async_rx.recv().await { - sync_tx.send(val).expect("Failed to send message"); + send!(sync_tx, val); } }); diff --git a/src/clients/wayland/client.rs b/src/clients/wayland/client.rs index 149e3e8..b0eb716 100644 --- a/src/clients/wayland/client.rs +++ b/src/clients/wayland/client.rs @@ -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::>(), - ) - .expect("Failed to send seats out of task"); + send!( + seat_tx, + seats + .into_iter() + .map(|seat| seat.detach()) + .collect::>() + ); let _toplevel_manager = env.require_global::(); @@ -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, diff --git a/src/clients/wayland/toplevel.rs b/src/clients/wayland/toplevel.rs index b878726..aab2828 100644 --- a/src/clients/wayland/toplevel.rs +++ b/src/clients/wayland/toplevel.rs @@ -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); }); diff --git a/src/config.rs b/src/config.rs index 8d251b7..9e96900 100644 --- a/src/config.rs +++ b/src/config.rs @@ -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, diff --git a/src/dynamic_string.rs b/src/dynamic_string.rs index ddd9ebe..e767af4 100644 --- a/src/dynamic_string.rs +++ b/src/dynamic_string.rs @@ -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(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::(); - 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::(); - tx.send(label_parts).expect("Failed to send update"); + send!(tx, label_parts); } rx.attach(None, f); - // Self { label } - Self {} + Self } } diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..d5a19b2 --- /dev/null +++ b/src/error.rs @@ -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"; diff --git a/src/logging.rs b/src/logging.rs index b35da3f..0357955 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -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 { + // 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 { +fn install_tracing() -> Result { const DEFAULT_LOG: &str = "info"; const DEFAULT_FILE_LOG: &str = "warn"; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..2197024 --- /dev/null +++ b/src/macros.rs @@ -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) + }; +} diff --git a/src/main.rs b/src/main.rs index 3b7011c..c560ea1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 or `Cow` 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: F) -> F::Output { block_in_place(|| Handle::current().block_on(f)) } diff --git a/src/modules/clock.rs b/src/modules/clock.rs index 5b59698..2156ef9 100644 --- a/src/modules/clock.rs +++ b/src/modules/clock.rs @@ -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, } fn default_format() -> String { @@ -33,6 +34,10 @@ impl Module