mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-04-19 19:34:24 +02:00
Merge branch 'master' into develop
This commit is contained in:
commit
b14fe5a1b8
52 changed files with 1149 additions and 280 deletions
4
.github/workflows/binary.yml
vendored
4
.github/workflows/binary.yml
vendored
|
@ -53,10 +53,10 @@ jobs:
|
|||
|
||||
- name: Compress the built binary
|
||||
if: ${{ matrix.platform.zipext == '.tar.gz' }}
|
||||
run: tar -zcvf ${{env.BINARY_NAME}}-${{github.ref_name}}-${{matrix.platform.target}}.tar.gz -C target/${{matrix.platform.target}}/release ${{env.BINARY_NAME}}
|
||||
run: tar -zcvf ${{env.BINARY_NAME}}-${{needs.get_last_release.outputs.latest_release_tag}}-${{matrix.platform.target}}.tar.gz -C target/${{matrix.platform.target}}/release ${{env.BINARY_NAME}}
|
||||
|
||||
- name: Upload to release
|
||||
run: gh release upload ${{needs.get_last_release.outputs.latest_release_tag}} ${{env.BINARY_NAME}}-${{github.ref_name}}-${{matrix.platform.target}}${{matrix.platform.zipext}}
|
||||
run: gh release upload ${{needs.get_last_release.outputs.latest_release_tag}} ${{env.BINARY_NAME}}-${{needs.get_last_release.outputs.latest_release_tag}}-${{matrix.platform.target}}${{matrix.platform.zipext}}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/target
|
||||
.direnv/
|
||||
|
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [v0.15.1] - 2024-05-05
|
||||
|
||||
Release to bump hyprland-rs version due to Hyprland v0.40 socket path breaking change.
|
||||
|
||||
### :memo: Documentation Changes
|
||||
- [`47b6c47`](https://github.com/JakeStanger/ironbar/commit/47b6c477242ad52aae77a6820740d9c5f4bfc263) - **compiling**: add lua deps *(commit by [@JakeStanger](https://github.com/JakeStanger))*
|
||||
- [`1971f3b`](https://github.com/JakeStanger/ironbar/commit/1971f3bb1ef3d059b29b99527e77ffaaf92240aa) - **volume**: update deprecated volume token *(PR [#567](https://github.com/JakeStanger/ironbar/pull/567) by [@drendog](https://github.com/drendog))*
|
||||
|
||||
|
||||
## [v0.15.0] - 2024-04-28
|
||||
### :sparkles: New Features
|
||||
- [`f4384b6`](https://github.com/JakeStanger/ironbar/commit/f4384b6252e86d4e2558e1c36810d4ef903bd58c) - enable use of markup in clock module format and format_popup, and update documentation to reflect supporting Pango markup in both *commit by [@Dridus](https://github.com/Dridus))*
|
||||
|
@ -565,3 +574,4 @@ It also requires `lua-lgi` as a runtime dependency.
|
|||
[v0.14.0]: https://github.com/JakeStanger/ironbar/compare/v0.13.0...v0.14.0
|
||||
[v0.14.1]: https://github.com/JakeStanger/ironbar/compare/v0.14.0...v0.14.1
|
||||
[v0.15.0]: https://github.com/JakeStanger/ironbar/compare/v0.14.3...v0.15.0
|
||||
[v0.15.1]: https://github.com/JakeStanger/ironbar/compare/v0.15.0...v0.15.1
|
||||
|
|
157
Cargo.lock
generated
157
Cargo.lock
generated
|
@ -26,6 +26,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
@ -434,6 +435,12 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.38"
|
||||
|
@ -529,12 +536,6 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
|
@ -703,10 +704,8 @@ version = "0.99.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote 1.0.35",
|
||||
"rustc_version",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
|
@ -756,12 +755,6 @@ dependencies = [
|
|||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.0"
|
||||
|
@ -1491,32 +1484,28 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hyprland"
|
||||
version = "0.3.13"
|
||||
version = "0.4.0-alpha.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f87a8f1cc065d451894dd3916c0bc3fcf9b67b276126c05f27b1db912688dde8"
|
||||
checksum = "d627cd06fb3389f2554b7a4bb21db8c0bfca8863e6e653702cc4c6dbf20d8276"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"ahash",
|
||||
"derive_more",
|
||||
"doc-comment",
|
||||
"futures",
|
||||
"hex",
|
||||
"hyprland-macros",
|
||||
"lazy_static",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"strum",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyprland-macros"
|
||||
version = "0.3.4"
|
||||
version = "0.4.0-alpha.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c941d3d52e979612af8cb94e8de49000c7fada2014a7791d173ab41339f4e4eb"
|
||||
checksum = "5dd8ce4c182ce77e485918f49262425ee51a2746fe97f14084869aeff2fbc38e"
|
||||
dependencies = [
|
||||
"quote 1.0.35",
|
||||
"syn 2.0.48",
|
||||
|
@ -1626,7 +1615,7 @@ checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
|
|||
|
||||
[[package]]
|
||||
name = "ironbar"
|
||||
version = "0.15.0"
|
||||
version = "0.16.0-pre"
|
||||
dependencies = [
|
||||
"cairo-rs",
|
||||
"cfg-if",
|
||||
|
@ -1637,6 +1626,7 @@ dependencies = [
|
|||
"dirs",
|
||||
"futures-lite 2.3.0",
|
||||
"futures-signals",
|
||||
"futures-util",
|
||||
"glib",
|
||||
"gtk",
|
||||
"gtk-layer-shell",
|
||||
|
@ -1647,7 +1637,7 @@ dependencies = [
|
|||
"mlua",
|
||||
"mpd-utils",
|
||||
"mpris",
|
||||
"nix 0.27.1",
|
||||
"nix 0.28.0",
|
||||
"notify",
|
||||
"regex",
|
||||
"reqwest",
|
||||
|
@ -1714,9 +1704,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.155"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
|
||||
[[package]]
|
||||
name = "libcorn"
|
||||
|
@ -1790,16 +1780,6 @@ version = "0.4.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
|
@ -1895,9 +1875,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mlua"
|
||||
version = "0.9.7"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d9bed6bce296397a9d6a86f995dd10a547a4e6949825d45225906bdcbfe7367"
|
||||
checksum = "e340c022072f3208a4105458286f4985ba5355bfe243c3073afe45cbe9ecf491"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"mlua-sys",
|
||||
|
@ -1908,9 +1888,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mlua-sys"
|
||||
version = "0.5.1"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2847b42764435201d8cbee1f517edb79c4cca4181877b90047587c89e1b7bce4"
|
||||
checksum = "5552e7e4e22ada0463dfdeee6caf6dc057a189fdc83136408a8f950a5e5c5540"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
|
@ -2009,6 +1989,18 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
|
@ -2068,9 +2060,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
@ -2203,34 +2195,11 @@ version = "2.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.4.1",
|
||||
"smallvec",
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.12"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
|
||||
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
|
@ -2508,15 +2477,6 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.3"
|
||||
|
@ -2688,12 +2648,6 @@ version = "1.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.13"
|
||||
|
@ -2761,18 +2715,18 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.198"
|
||||
version = "1.0.202"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
|
||||
checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.198"
|
||||
version = "1.0.202"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
|
||||
checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.35",
|
||||
|
@ -2781,9 +2735,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.116"
|
||||
version = "1.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
|
||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -2972,28 +2926,6 @@ version = "0.11.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote 1.0.35",
|
||||
"rustversion",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "swayipc-async"
|
||||
version = "2.0.1"
|
||||
|
@ -3204,7 +3136,6 @@ dependencies = [
|
|||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2 0.5.5",
|
||||
|
|
13
Cargo.toml
13
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ironbar"
|
||||
version = "0.15.0"
|
||||
version = "0.16.0-pre"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
description = "Customisable GTK Layer Shell wlroots/sway bar"
|
||||
|
@ -99,7 +99,7 @@ tracing-error = { version = "0.2.0" , default-features = false }
|
|||
tracing-appender = "0.2.3"
|
||||
strip-ansi-escapes = "0.2.0"
|
||||
color-eyre = "0.6.3"
|
||||
serde = { version = "1.0.198", features = ["derive"] }
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
indexmap = "2.2.6"
|
||||
dirs = "5.0.1"
|
||||
walkdir = "2.5.0"
|
||||
|
@ -117,18 +117,18 @@ cfg-if = "1.0.0"
|
|||
clap = { version = "4.5.4", optional = true, features = ["derive"] }
|
||||
|
||||
# ipc
|
||||
serde_json = { version = "1.0.116", optional = true }
|
||||
serde_json = { version = "1.0.117", optional = true }
|
||||
|
||||
# http
|
||||
reqwest = { version = "0.12.4", default_features = false, features = ["default-tls", "http2"], optional = true }
|
||||
|
||||
# cairo
|
||||
lua-src = { version = "546.0.2", optional = true }
|
||||
mlua = { version = "0.9.7", optional = true, features = ["luajit"] }
|
||||
mlua = { version = "0.9.8", optional = true, features = ["luajit"] }
|
||||
cairo-rs = { version = "0.18.5", optional = true, features = ["png"] }
|
||||
|
||||
# clipboard
|
||||
nix = { version = "0.27.1", optional = true, features = ["event"] }
|
||||
nix = { version = "0.28.0", optional = true, features = ["event", "fs"] }
|
||||
|
||||
# clock
|
||||
chrono = { version = "0.4.38", optional = true, default_features = false, features = ["clock", "unstable-locales"] }
|
||||
|
@ -154,7 +154,8 @@ libpulse-binding = { version = "2.28.1", optional = true }
|
|||
|
||||
# workspaces
|
||||
swayipc-async = { version = "2.0.1", optional = true }
|
||||
hyprland = { version = "0.3.13", default_features = false, features = ["listener", "tokio", "silent"], optional = true }
|
||||
hyprland = { version = "0.4.0-alpha.2", features = ["silent"], optional = true }
|
||||
futures-util = { version = "0.3.30", optional = true }
|
||||
|
||||
# shared
|
||||
futures-lite = { version = "2.3.0", optional = true } # networkmanager, upower, workspaces
|
||||
|
|
|
@ -59,6 +59,10 @@ Ironbar is designed to support anything from a lightweight bar to a full desktop
|
|||
|
||||
[](https://repology.org/project/ironbar/versions)
|
||||
|
||||
Ironbar can be installed from source or using your preferred package manager.
|
||||
|
||||
It is also recommended to install a [Nerd Font](https://www.nerdfonts.com/#home) for displaying symbols.
|
||||
|
||||
### Cargo
|
||||
|
||||
[crate](https://crates.io/crates/ironbar)
|
||||
|
|
|
@ -9,6 +9,8 @@ cargo build --release
|
|||
install target/release/ironbar ~/.local/bin/ironbar
|
||||
```
|
||||
|
||||
It is also recommended to install a [Nerd Font](https://www.nerdfonts.com/#home) for displaying symbols.
|
||||
|
||||
## Build requirements
|
||||
|
||||
To build from source, you must have GTK (>= 3.22) and GTK Layer Shell installed.
|
||||
|
@ -45,7 +47,7 @@ dnf install gtk3-devel gtk-layer-shell-devel
|
|||
# for http support
|
||||
dnf install openssl-devel
|
||||
# for volume support
|
||||
dnf install libpulseaudio-devel
|
||||
dnf install pulseaudio-libs-devel
|
||||
# for lua/cairo support
|
||||
dnf install luajit-devel lua-lgi
|
||||
```
|
||||
|
|
|
@ -9,6 +9,8 @@ If you want to see some ready-to-go config files check
|
|||
the [examples folder](https://github.com/JakeStanger/ironbar/tree/master/examples)
|
||||
and the example pages in the sidebar.
|
||||
|
||||
The examples make use of [Nerd Fonts](https://www.nerdfonts.com/#home) for displaying symbols.
|
||||
|
||||
## 1. Create config file
|
||||
|
||||
The config file lives inside the `ironbar` directory in your XDG_CONFIG_DIR, which is usually `~/.config/ironbar`.
|
||||
|
|
|
@ -84,11 +84,10 @@ and will be replaced with values from the current battery state:
|
|||
|
||||
| Selector | Description |
|
||||
|---------------------------------|--------------------------------|
|
||||
| `.upower` | Upower widget container. |
|
||||
| `.upower .button` | Upower widget button. |
|
||||
| `.upower .button .contents` | Upower widget button contents. |
|
||||
| `.upower .button .icon` | Upower widget battery icon. |
|
||||
| `.upower .button .label` | Upower widget button label. |
|
||||
| `.upower` | Upower widget button. |
|
||||
| `.upower .contents` | Upower widget button contents. |
|
||||
| `.upower .icon` | Upower widget battery icon. |
|
||||
| `.upower .label` | Upower widget button label. |
|
||||
| `.popup-upower` | Upower popup box. |
|
||||
| `.popup-upower .upower-details` | Label inside the popup. |
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ let {
|
|||
interval.networks = 3
|
||||
|
||||
format = [
|
||||
" {cpu_percent}% | {temp_c:k10temp_Tccd1}°C"
|
||||
" {cpu_percent}% | {temp_c:k10temp-Tccd1}°C"
|
||||
" {memory_used} / {memory_total} GB ({memory_percent}%)"
|
||||
"| {swap_used} / {swap_total} GB ({swap_percent}%)"
|
||||
" {disk_used:/} / {disk_total:/} GB ({disk_percent:/}%)"
|
||||
|
@ -81,7 +81,7 @@ let {
|
|||
|
||||
$volume = {
|
||||
type = "volume"
|
||||
format = "{icon} {volume}%"
|
||||
format = "{icon} {percentage}%"
|
||||
max_volume = 100
|
||||
icons.volume_high = ""
|
||||
icons.volume_medium = ""
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
"networks": 3
|
||||
},
|
||||
"format": [
|
||||
" {cpu_percent}% | {temp_c:k10temp_Tccd1}°C",
|
||||
" {cpu_percent}% | {temp_c:k10temp-Tccd1}°C",
|
||||
" {memory_used} / {memory_total} GB ({memory_percent}%)",
|
||||
"| {swap_used} / {swap_total} GB ({swap_percent}%)",
|
||||
" {disk_used:/} / {disk_total:/} GB ({disk_percent:/}%)",
|
||||
|
@ -74,7 +74,7 @@
|
|||
},
|
||||
{
|
||||
"type": "volume",
|
||||
"format": "{icon} {volume}%",
|
||||
"format": "{icon} {percentage}%",
|
||||
"max_volume": 100,
|
||||
"icons": {
|
||||
"volume_high": "",
|
||||
|
|
|
@ -53,7 +53,7 @@ interval = 500
|
|||
[[end]]
|
||||
type = "sys_info"
|
||||
format = [
|
||||
" {cpu_percent}% | {temp_c:k10temp_Tccd1}°C",
|
||||
" {cpu_percent}% | {temp_c:k10temp-Tccd1}°C",
|
||||
" {memory_used} / {memory_total} GB ({memory_percent}%)",
|
||||
"| {swap_used} / {swap_total} GB ({swap_percent}%)",
|
||||
" {disk_used:/} / {disk_total:/} GB ({disk_percent:/}%)",
|
||||
|
@ -71,7 +71,7 @@ networks = 3
|
|||
|
||||
[[end]]
|
||||
type = "volume"
|
||||
format = "{icon} {volume}%"
|
||||
format = "{icon} {percentage}%"
|
||||
max_volume = 100
|
||||
|
||||
[end.icons]
|
||||
|
|
|
@ -43,7 +43,7 @@ end:
|
|||
disks: 300
|
||||
networks: 3
|
||||
format:
|
||||
- {cpu_percent}% | {temp_c:k10temp_Tccd1}°C
|
||||
- {cpu_percent}% | {temp_c:k10temp-Tccd1}°C
|
||||
- {memory_used} / {memory_total} GB ({memory_percent}%)
|
||||
- '| {swap_used} / {swap_total} GB ({swap_percent}%)'
|
||||
- {disk_used:/} / {disk_total:/} GB ({disk_percent:/}%)
|
||||
|
@ -51,7 +51,7 @@ end:
|
|||
- {load_average:1} | {load_average:5} | {load_average:15}
|
||||
- {uptime}
|
||||
- type: volume
|
||||
format: '{icon} {volume}%'
|
||||
format: '{icon} {percentage}%'
|
||||
max_volume: 100
|
||||
icons:
|
||||
volume_high:
|
||||
|
|
60
examples/test.corn
Normal file
60
examples/test.corn
Normal file
|
@ -0,0 +1,60 @@
|
|||
let {
|
||||
$config_dir = "/home/jake/.config/ironbar"
|
||||
|
||||
$workspaces = { type = "workspaces" }
|
||||
$launcher = { type = "launcher" }
|
||||
$volume = {
|
||||
type = "volume"
|
||||
format = "{icon} {percentage}%"
|
||||
max_volume = 100
|
||||
icons.volume_high = ""
|
||||
icons.volume_medium = ""
|
||||
icons.volume_low = ""
|
||||
icons.muted = ""
|
||||
}
|
||||
$network_manager = { type = "networkmanager" }
|
||||
$clock = {
|
||||
type = "clock"
|
||||
// disable_popup = true
|
||||
// format = "<span color='#f2777a'>%d/%m/%Y</span> <span color='#69c'>%H:%M:%S</span>"
|
||||
}
|
||||
$tray = { type = "tray" prefer_theme_icons = false }
|
||||
|
||||
// $label = { type = "label" label = "<span color='#color'>hello</span>" }
|
||||
$label = { type = "label" label = "#random" }
|
||||
$clipboard = { type = "clipboard" }
|
||||
|
||||
$notifications = {
|
||||
type = "notifications"
|
||||
show_count = true
|
||||
|
||||
icons.closed_none = ""
|
||||
icons.closed_some = ""
|
||||
icons.closed_dnd = ""
|
||||
icons.open_none = ""
|
||||
icons.open_some = ""
|
||||
icons.open_dnd = ""
|
||||
}
|
||||
|
||||
$focused = { type = "focused" }
|
||||
|
||||
$cairo = { type = "cairo" path = "$config_dir/clock.lua" frequency = 50 width = 300 height = 300 }
|
||||
|
||||
$custom = {
|
||||
type = "custom"
|
||||
bar = [ { type = "button" on_click = "popup:toggle" widgets = [ $focused ] } ]
|
||||
popup = [ { type = "box" orientation = "v" widgets = [ $clock $cairo ] } ]
|
||||
}
|
||||
|
||||
$mpris = { type = "music" }
|
||||
} in {
|
||||
// ironvar_defaults.color = "red"
|
||||
|
||||
position = "bottom"
|
||||
|
||||
icon_theme = "Paper"
|
||||
|
||||
start = [ $workspaces $label ]
|
||||
center = [ $custom ]
|
||||
end = [ $notifications $clock ]
|
||||
}
|
30
flake.lock
generated
30
flake.lock
generated
|
@ -7,11 +7,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711681752,
|
||||
"narHash": "sha256-LEg6/dmEFxx6Ygti5DO9MOhGNpyB7zdxdWtzv/FCTXk=",
|
||||
"lastModified": 1713979152,
|
||||
"narHash": "sha256-apdecPuh8SOQnkEET/kW/UcfjCRb8JbV5BKjoH+DcP4=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "ada0fb4dcce4561acb1eb17c59b7306d9d4a95f3",
|
||||
"rev": "a5eca68a2cf11adb32787fc141cddd29ac8eb79c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -43,11 +43,11 @@
|
|||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1698420672,
|
||||
"narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=",
|
||||
"lastModified": 1713520724,
|
||||
"narHash": "sha256-CO8MmVDmqZX2FovL75pu5BvwhW+Vugc7Q6ze7Hj8heI=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "aeb58d5e8faead8980a807c840232697982d47b9",
|
||||
"rev": "c5037590290c6c7dae2e42e7da1e247e54ed2d49",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -58,11 +58,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1711715736,
|
||||
"narHash": "sha256-9slQ609YqT9bT/MNX9+5k5jltL9zgpn36DpFB7TkttM=",
|
||||
"lastModified": 1714314149,
|
||||
"narHash": "sha256-yNAevSKF4krRWacmLUsLK7D7PlfuY3zF0lYnGYNi9vQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "807c549feabce7eddbf259dbdcec9e0600a0660d",
|
||||
"rev": "cf8cc1201be8bc71b7cbbbdaf349b22f4f99c7ae",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -72,11 +72,11 @@
|
|||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1711703276,
|
||||
"narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=",
|
||||
"lastModified": 1714253743,
|
||||
"narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
|
||||
"rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -102,11 +102,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711851236,
|
||||
"narHash": "sha256-EJ03x3N9ihhonAttkaCrqxb0djDq3URCuDpmVPbNZhA=",
|
||||
"lastModified": 1714443211,
|
||||
"narHash": "sha256-lKTA3XqRo4aVgkyTSCtpcALpGXdmkilHTtN00eRg0QU=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "f258266af947599e8069df1c2e933189270f143a",
|
||||
"rev": "ce35c36f58f82cee6ec959e0d44c587d64281b6f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -149,12 +149,27 @@ impl Client {
|
|||
}
|
||||
|
||||
{
|
||||
event_listener.add_workspace_destroy_handler(move |workspace_type| {
|
||||
let _lock = lock!(lock);
|
||||
debug!("Received workspace destroy: {workspace_type:?}");
|
||||
let tx = tx.clone();
|
||||
let lock = lock.clone();
|
||||
|
||||
let name = get_workspace_name(workspace_type);
|
||||
send!(tx, WorkspaceUpdate::Remove(name));
|
||||
event_listener.add_workspace_rename_handler(move |data| {
|
||||
let _lock = lock!(lock);
|
||||
|
||||
send!(
|
||||
tx,
|
||||
WorkspaceUpdate::Rename {
|
||||
id: data.workspace_id as i64,
|
||||
name: data.workspace_name
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
event_listener.add_workspace_destroy_handler(move |data| {
|
||||
let _lock = lock!(lock);
|
||||
debug!("Received workspace destroy: {data:?}");
|
||||
send!(tx, WorkspaceUpdate::Remove(data.workspace_id as i64));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -186,6 +201,7 @@ impl Client {
|
|||
fn get_workspace(name: &str, active: Option<&Workspace>) -> Option<Workspace> {
|
||||
Workspaces::get()
|
||||
.expect("Failed to get workspaces")
|
||||
.into_iter()
|
||||
.find_map(|w| {
|
||||
if w.name == name {
|
||||
let vis = Visibility::from((&w, active.map(|w| w.name.as_ref()), &|w| {
|
||||
|
@ -228,6 +244,7 @@ impl WorkspaceClient for Client {
|
|||
|
||||
let workspaces = Workspaces::get()
|
||||
.expect("Failed to get workspaces")
|
||||
.into_iter()
|
||||
.map(|w| {
|
||||
let vis = Visibility::from((&w, active_id.as_deref(), &is_visible));
|
||||
|
||||
|
@ -262,7 +279,7 @@ fn create_is_visible() -> impl Fn(&HWorkspace) -> bool {
|
|||
impl From<(Visibility, HWorkspace)> for Workspace {
|
||||
fn from((visibility, workspace): (Visibility, HWorkspace)) -> Self {
|
||||
Self {
|
||||
id: workspace.id.to_string(),
|
||||
id: workspace.id as i64,
|
||||
name: workspace.name,
|
||||
monitor: workspace.monitor,
|
||||
visibility,
|
||||
|
|
|
@ -74,7 +74,7 @@ impl Compositor {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Workspace {
|
||||
/// Unique identifier
|
||||
pub id: String,
|
||||
pub id: i64,
|
||||
/// Workspace friendly name
|
||||
pub name: String,
|
||||
/// Name of the monitor (output) the workspace is located on
|
||||
|
@ -119,13 +119,19 @@ pub enum WorkspaceUpdate {
|
|||
/// This is re-sent to all subscribers when a new subscription is created.
|
||||
Init(Vec<Workspace>),
|
||||
Add(Workspace),
|
||||
Remove(String),
|
||||
Remove(i64),
|
||||
Move(Workspace),
|
||||
/// Declares focus moved from the old workspace to the new.
|
||||
Focus {
|
||||
old: Option<Workspace>,
|
||||
new: Workspace,
|
||||
},
|
||||
|
||||
Rename {
|
||||
id: i64,
|
||||
name: String,
|
||||
},
|
||||
|
||||
/// An update was triggered by the compositor but this was not mapped by Ironbar.
|
||||
///
|
||||
/// This is purely used for ergonomics within the compositor clients
|
||||
|
|
|
@ -90,7 +90,7 @@ impl From<Node> for Workspace {
|
|||
let visibility = Visibility::from(&node);
|
||||
|
||||
Self {
|
||||
id: node.id.to_string(),
|
||||
id: node.id,
|
||||
name: node.name.unwrap_or_default(),
|
||||
monitor: node.output.unwrap_or_default(),
|
||||
visibility,
|
||||
|
@ -103,7 +103,7 @@ impl From<swayipc_async::Workspace> for Workspace {
|
|||
let visibility = Visibility::from(&workspace);
|
||||
|
||||
Self {
|
||||
id: workspace.id.to_string(),
|
||||
id: workspace.id,
|
||||
name: workspace.name,
|
||||
monitor: workspace.output,
|
||||
visibility,
|
||||
|
@ -141,13 +141,9 @@ impl From<WorkspaceEvent> for WorkspaceUpdate {
|
|||
WorkspaceChange::Init => {
|
||||
Self::Add(event.current.expect("Missing current workspace").into())
|
||||
}
|
||||
WorkspaceChange::Empty => Self::Remove(
|
||||
event
|
||||
.current
|
||||
.expect("Missing current workspace")
|
||||
.name
|
||||
.unwrap_or_default(),
|
||||
),
|
||||
WorkspaceChange::Empty => {
|
||||
Self::Remove(event.current.expect("Missing current workspace").id)
|
||||
}
|
||||
WorkspaceChange::Focus => Self::Focus {
|
||||
old: event.old.map(Workspace::from),
|
||||
new: Workspace::from(event.current.expect("Missing current workspace")),
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::{lock, try_send, Ironbar};
|
|||
use device::DataControlDevice;
|
||||
use glib::Bytes;
|
||||
use nix::fcntl::{fcntl, F_GETPIPE_SZ, F_SETPIPE_SZ};
|
||||
use nix::sys::epoll::{Epoll, EpollCreateFlags, EpollEvent, EpollFlags};
|
||||
use nix::sys::epoll::{Epoll, EpollCreateFlags, EpollEvent, EpollFlags, EpollTimeout};
|
||||
use smithay_client_toolkit::data_device_manager::WritePipe;
|
||||
use smithay_client_toolkit::reexports::calloop::{PostAction, RegistrationToken};
|
||||
use std::cmp::min;
|
||||
|
@ -274,7 +274,7 @@ impl DataControlDeviceHandler for Environment {
|
|||
Ok(token) => {
|
||||
cur_offer.token.replace(token);
|
||||
}
|
||||
Err(err) => error!("{err:?}"),
|
||||
Err(err) => error!("Failed to insert read pipe event: {err:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -294,15 +294,15 @@ impl DataControlOfferHandler for Environment {
|
|||
}
|
||||
|
||||
impl DataControlSourceHandler for Environment {
|
||||
fn accept_mime(
|
||||
&mut self,
|
||||
_conn: &Connection,
|
||||
_qh: &QueueHandle<Self>,
|
||||
_source: &ZwlrDataControlSourceV1,
|
||||
mime: Option<String>,
|
||||
) {
|
||||
debug!("Accepted mime type: {mime:?}");
|
||||
}
|
||||
// fn accept_mime(
|
||||
// &mut self,
|
||||
// _conn: &Connection,
|
||||
// _qh: &QueueHandle<Self>,
|
||||
// _source: &ZwlrDataControlSourceV1,
|
||||
// mime: Option<String>,
|
||||
// ) {
|
||||
// debug!("Accepted mime type: {mime:?}");
|
||||
// }
|
||||
|
||||
/// Writes the current clipboard item to 'paste' it
|
||||
/// upon request from a compositor client.
|
||||
|
@ -349,11 +349,12 @@ impl DataControlSourceHandler for Environment {
|
|||
.add(fd, epoll_event)
|
||||
.expect("to send valid epoll operation");
|
||||
|
||||
let timeout = EpollTimeout::from(100u16);
|
||||
while !bytes.is_empty() {
|
||||
let chunk = &bytes[..min(pipe_size as usize, bytes.len())];
|
||||
|
||||
epoll_fd
|
||||
.wait(&mut events, 100)
|
||||
.wait(&mut events, timeout)
|
||||
.expect("Failed to wait to epoll");
|
||||
|
||||
match file.write(chunk) {
|
||||
|
|
|
@ -5,7 +5,7 @@ use nix::unistd::{close, pipe2};
|
|||
use smithay_client_toolkit::data_device_manager::data_offer::DataOfferError;
|
||||
use smithay_client_toolkit::data_device_manager::ReadPipe;
|
||||
use std::ops::DerefMut;
|
||||
use std::os::fd::{BorrowedFd, FromRawFd};
|
||||
use std::os::fd::{AsFd, AsRawFd};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tracing::{trace, warn};
|
||||
use wayland_client::{Connection, Dispatch, Proxy, QueueHandle};
|
||||
|
@ -176,11 +176,11 @@ pub unsafe fn receive(
|
|||
// create a pipe
|
||||
let (readfd, writefd) = pipe2(OFlag::O_CLOEXEC)?;
|
||||
|
||||
offer.receive(mime_type, BorrowedFd::borrow_raw(writefd));
|
||||
offer.receive(mime_type, writefd.as_fd());
|
||||
|
||||
if let Err(err) = close(writefd) {
|
||||
if let Err(err) = close(writefd.as_raw_fd()) {
|
||||
warn!("Failed to close write pipe: {}", err);
|
||||
}
|
||||
|
||||
Ok(FromRawFd::from_raw_fd(readfd))
|
||||
Ok(ReadPipe::from(readfd))
|
||||
}
|
||||
|
|
|
@ -10,13 +10,13 @@ use wayland_protocols_wlr::data_control::v1::client::zwlr_data_control_source_v1
|
|||
pub struct DataControlSourceData {}
|
||||
|
||||
pub trait DataControlSourceDataExt: Send + Sync {
|
||||
fn data_source_data(&self) -> &DataControlSourceData;
|
||||
// fn data_source_data(&self) -> &DataControlSourceData;
|
||||
}
|
||||
|
||||
impl DataControlSourceDataExt for DataControlSourceData {
|
||||
fn data_source_data(&self) -> &DataControlSourceData {
|
||||
self
|
||||
}
|
||||
// fn data_source_data(&self) -> &DataControlSourceData {
|
||||
// self
|
||||
// }
|
||||
}
|
||||
|
||||
/// Handler trait for `DataSource` events.
|
||||
|
@ -24,13 +24,13 @@ impl DataControlSourceDataExt for DataControlSourceData {
|
|||
/// The functions defined in this trait are called as `DataSource` events are received from the compositor.
|
||||
pub trait DataControlSourceHandler: Sized {
|
||||
/// This may be called multiple times, once for each accepted mime type from the destination, if any.
|
||||
fn accept_mime(
|
||||
&mut self,
|
||||
conn: &Connection,
|
||||
qh: &QueueHandle<Self>,
|
||||
source: &ZwlrDataControlSourceV1,
|
||||
mime: Option<String>,
|
||||
);
|
||||
// fn accept_mime(
|
||||
// &mut self,
|
||||
// conn: &Connection,
|
||||
// qh: &QueueHandle<Self>,
|
||||
// source: &ZwlrDataControlSourceV1,
|
||||
// mime: Option<String>,
|
||||
// );
|
||||
|
||||
/// The client has requested the data for this source to be sent.
|
||||
/// Send the data, then close the fd.
|
||||
|
|
|
@ -77,7 +77,6 @@ impl ToplevelHandleHandler for Environment {
|
|||
match handle.info() {
|
||||
Some(info) => {
|
||||
trace!("Updating handle: {info:?}");
|
||||
self.handles.push(handle.clone());
|
||||
if let Some(info) = handle.info() {
|
||||
try_send!(self.event_tx, Event::Toplevel(ToplevelEvent::Update(info)));
|
||||
}
|
||||
|
|
|
@ -7,26 +7,153 @@ use gtk::{EventBox, Orientation, Revealer, RevealerTransitionType};
|
|||
use serde::Deserialize;
|
||||
use tracing::trace;
|
||||
|
||||
/// Common configuration options
|
||||
/// which can be set on every module.
|
||||
/// The following are module-level options which are present on **all** modules.
|
||||
///
|
||||
/// Each module also provides options specific to its type.
|
||||
/// For details on those, check the relevant module documentation.
|
||||
///
|
||||
/// For information on the Script type, and embedding scripts in strings,
|
||||
/// see [here](script).
|
||||
/// For information on styling, please see the [styling guide](styling-guide).
|
||||
#[derive(Debug, Default, Deserialize, Clone)]
|
||||
pub struct CommonConfig {
|
||||
pub class: Option<String>,
|
||||
/// Sets the unique widget name,
|
||||
/// allowing you to target it in CSS using `#name`.
|
||||
///
|
||||
/// It is best practise (although not required) to ensure that the value is
|
||||
/// globally unique throughout the Ironbar instance
|
||||
/// to avoid clashes.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
pub name: Option<String>,
|
||||
|
||||
/// Sets one or more CSS classes,
|
||||
/// allowing you to target it in CSS using `.class`.
|
||||
///
|
||||
/// Unlike [name](#name), the `class` property is not expected to be unique.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
pub class: Option<String>,
|
||||
|
||||
/// Shows this text on hover.
|
||||
/// Supports embedding scripts between `{{double braces}}`.
|
||||
///
|
||||
/// Note that full dynamic string support is not currently supported.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
pub tooltip: Option<String>,
|
||||
|
||||
/// Shows the module only if the dynamic boolean evaluates to true.
|
||||
///
|
||||
/// This allows for modules to be dynamically shown or hidden
|
||||
/// based on custom events.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
pub show_if: Option<DynamicBool>,
|
||||
|
||||
/// The transition animation to use when showing/hiding the widget.
|
||||
///
|
||||
/// Note this has no effect if `show_if` is not configured.
|
||||
///
|
||||
/// **Valid options**: `slide_start`, `slide_end`, `crossfade`, `none`
|
||||
/// <br>
|
||||
/// **Default**: `slide_start`
|
||||
pub transition_type: Option<TransitionType>,
|
||||
|
||||
/// The length in milliseconds
|
||||
/// of the transition animation to use when showing/hiding the widget.
|
||||
///
|
||||
/// Note this has no effect if `show_if` is not configured.
|
||||
///
|
||||
/// **Default**: `250`
|
||||
pub transition_duration: Option<u32>,
|
||||
|
||||
/// A [script](scripts) to run when the module is left-clicked.
|
||||
///
|
||||
/// **Supported script types**: `oneshot`.
|
||||
/// <br>
|
||||
/// **Default**: `null`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```corn
|
||||
/// { on_click_left = "echo 'event' >> log.txt" }
|
||||
/// ```
|
||||
pub on_click_left: Option<ScriptInput>,
|
||||
|
||||
/// A [script](scripts) to run when the module is right-clicked.
|
||||
///
|
||||
/// **Supported script types**: `oneshot`.
|
||||
/// <br>
|
||||
/// **Default**: `null`
|
||||
/// /// # Example
|
||||
///
|
||||
/// ```corn
|
||||
/// { on_click_right = "echo 'event' >> log.txt" }
|
||||
/// ```
|
||||
pub on_click_right: Option<ScriptInput>,
|
||||
|
||||
/// A [script](scripts) to run when the module is middle-clicked.
|
||||
///
|
||||
/// **Supported script types**: `oneshot`.
|
||||
/// <br>
|
||||
/// **Default**: `null`
|
||||
/// # Example
|
||||
///
|
||||
/// ```corn
|
||||
/// { on_click_middle = "echo 'event' >> log.txt" }
|
||||
/// ```
|
||||
pub on_click_middle: Option<ScriptInput>,
|
||||
|
||||
/// A [script](scripts) to run when the module is scrolled up on.
|
||||
///
|
||||
/// **Supported script types**: `oneshot`.
|
||||
/// <br>
|
||||
/// **Default**: `null`
|
||||
/// # Example
|
||||
///
|
||||
/// ```corn
|
||||
/// { on_scroll_up = "echo 'event' >> log.txt" }
|
||||
/// ```
|
||||
pub on_scroll_up: Option<ScriptInput>,
|
||||
|
||||
/// A [script](scripts) to run when the module is scrolled down on.
|
||||
///
|
||||
/// **Supported script types**: `oneshot`.
|
||||
/// <br>
|
||||
/// **Default**: `null`
|
||||
/// # Example
|
||||
///
|
||||
/// ```corn
|
||||
/// { on_scroll_down = "echo 'event' >> log.txt" }
|
||||
/// ```
|
||||
pub on_scroll_down: Option<ScriptInput>,
|
||||
|
||||
/// A [script](scripts) to run when the cursor begins hovering over the module.
|
||||
///
|
||||
/// **Supported script types**: `oneshot`.
|
||||
/// <br>
|
||||
/// **Default**: `null`
|
||||
/// # Example
|
||||
///
|
||||
/// ```corn
|
||||
/// { on_mouse_enter = "echo 'event' >> log.txt" }
|
||||
/// ```
|
||||
pub on_mouse_enter: Option<ScriptInput>,
|
||||
|
||||
/// A [script](scripts) to run when the cursor stops hovering over the module.
|
||||
///
|
||||
/// **Supported script types**: `oneshot`.
|
||||
/// <br>
|
||||
/// **Default**: `null`
|
||||
/// # Example
|
||||
///
|
||||
/// ```corn
|
||||
/// { on_mouse_exit = "echo 'event' >> log.txt" }
|
||||
/// ```
|
||||
pub on_mouse_exit: Option<ScriptInput>,
|
||||
|
||||
pub tooltip: Option<String>,
|
||||
/// Prevents the popup from opening on-click for this widget.
|
||||
#[serde(default)]
|
||||
pub disable_popup: bool,
|
||||
}
|
||||
|
|
|
@ -122,12 +122,6 @@ impl ModuleConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub enum BarEntryConfig {
|
||||
Single(BarConfig),
|
||||
Monitors(HashMap<String, MonitorConfig>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MonitorConfig {
|
||||
Single(BarConfig),
|
||||
|
@ -161,32 +155,107 @@ pub struct MarginConfig {
|
|||
pub top: i32,
|
||||
}
|
||||
|
||||
/// The following is a list of all top-level bar config options.
|
||||
///
|
||||
/// These options can either be written at the very top object of your config,
|
||||
/// or within an object in the [monitors](#monitors) config,
|
||||
/// depending on your [use-case](#2-pick-your-use-case).
|
||||
///
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct BarConfig {
|
||||
#[serde(default)]
|
||||
pub position: BarPosition,
|
||||
#[serde(default = "default_true")]
|
||||
pub anchor_to_edges: bool,
|
||||
#[serde(default = "default_bar_height")]
|
||||
pub height: i32,
|
||||
#[serde(default)]
|
||||
pub margin: MarginConfig,
|
||||
/// A unique identifier for the bar, used for controlling it over IPC.
|
||||
/// If not set, uses a generated integer suffix.
|
||||
///
|
||||
/// **Default**: `bar-n`
|
||||
pub name: Option<String>,
|
||||
|
||||
/// The bar's position on screen.
|
||||
///
|
||||
/// **Valid options**: `top`, `bottom`, `left`, `right`
|
||||
/// <br>
|
||||
/// **Default**: `bottom`
|
||||
#[serde(default)]
|
||||
pub position: BarPosition,
|
||||
|
||||
/// Whether to anchor the bar to the edges of the screen.
|
||||
/// Setting to false centers the bar.
|
||||
///
|
||||
/// **Default**: `true`
|
||||
#[serde(default = "default_true")]
|
||||
pub anchor_to_edges: bool,
|
||||
|
||||
/// The bar's height in pixels.
|
||||
///
|
||||
/// Note that GTK treats this as a target minimum,
|
||||
/// and if content inside the bar is over this,
|
||||
/// it will automatically expand to fit.
|
||||
///
|
||||
/// **Default**: `42`
|
||||
#[serde(default = "default_bar_height")]
|
||||
pub height: i32,
|
||||
|
||||
/// The margin to use on each side of the bar, in pixels.
|
||||
/// Object which takes `top`, `bottom`, `left` and `right` keys.
|
||||
///
|
||||
/// **Default**: `0` on all sides.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// The following would set a 10px margin around each edge.
|
||||
///
|
||||
/// ```corn
|
||||
/// {
|
||||
/// margin.top = 10
|
||||
/// margin.bottom = 10
|
||||
/// margin.left = 10
|
||||
/// margin.right = 10
|
||||
/// }
|
||||
/// ```
|
||||
#[serde(default)]
|
||||
pub margin: MarginConfig,
|
||||
|
||||
/// The size of the gap in pixels
|
||||
/// between the bar and the popup window.
|
||||
///
|
||||
/// **Default**: `5`
|
||||
#[serde(default = "default_popup_gap")]
|
||||
pub popup_gap: i32,
|
||||
|
||||
/// Whether the bar should be hidden when Ironbar starts.
|
||||
///
|
||||
/// **Default**: `false`, unless `autohide` is set.
|
||||
#[serde(default)]
|
||||
pub start_hidden: Option<bool>,
|
||||
|
||||
/// The duration in milliseconds before the bar is hidden after the cursor leaves.
|
||||
/// Leave unset to disable auto-hide behaviour.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
#[serde(default)]
|
||||
pub autohide: Option<u64>,
|
||||
|
||||
/// GTK icon theme to use.
|
||||
/// The name of the GTK icon theme to use.
|
||||
/// Leave unset to use the default Adwaita theme.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
pub icon_theme: Option<String>,
|
||||
|
||||
/// An array of modules to append to the start of the bar.
|
||||
/// Depending on the orientation, this is either the top of the left edge.
|
||||
///
|
||||
/// **Default**: `[]`
|
||||
pub start: Option<Vec<ModuleConfig>>,
|
||||
pub center: Option<Vec<ModuleConfig>>,
|
||||
pub end: Option<Vec<ModuleConfig>>,
|
||||
|
||||
#[serde(default = "default_popup_gap")]
|
||||
pub popup_gap: i32,
|
||||
/// An array of modules to append to the center of the bar.
|
||||
///
|
||||
/// **Default**: `[]`
|
||||
pub center: Option<Vec<ModuleConfig>>,
|
||||
|
||||
/// An array of modules to append to the end of the bar.
|
||||
/// Depending on the orientation, this is either the bottom or right edge.
|
||||
///
|
||||
/// **Default**: `[]`
|
||||
pub end: Option<Vec<ModuleConfig>>,
|
||||
}
|
||||
|
||||
impl Default for BarConfig {
|
||||
|
@ -230,10 +299,41 @@ impl Default for BarConfig {
|
|||
|
||||
#[derive(Debug, Deserialize, Clone, Default)]
|
||||
pub struct Config {
|
||||
/// A map of [ironvar](ironvar) keys and values
|
||||
/// to initialize Ironbar with on startup.
|
||||
///
|
||||
/// **Default**: `{}`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// The following initializes an ironvar called `foo` set to `bar` on startup:
|
||||
///
|
||||
/// ```corn
|
||||
/// { ironvar_defaults.foo = "bar" }
|
||||
/// ```
|
||||
///
|
||||
/// The variable can then be immediately fetched without needing to be manually set:
|
||||
///
|
||||
/// ```sh
|
||||
/// $ ironbar get foo
|
||||
/// ok
|
||||
/// bar
|
||||
/// ```
|
||||
pub ironvar_defaults: Option<HashMap<Box<str>, String>>,
|
||||
|
||||
/// The configuration for the bar.
|
||||
/// Setting through this will enable a single identical bar on each monitor.
|
||||
#[serde(flatten)]
|
||||
pub bar: BarConfig,
|
||||
|
||||
/// A map of monitor names to configs.
|
||||
///
|
||||
/// The config values can be either:
|
||||
///
|
||||
/// - a single object, which denotes a single bar for that monitor,
|
||||
/// - an array of multiple objects, which denotes multiple for that monitor.
|
||||
///
|
||||
/// Providing this option overrides the single, global `bar` option.
|
||||
pub monitors: Option<HashMap<String, MonitorConfig>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -20,13 +20,68 @@ impl From<EllipsizeMode> for GtkEllipsizeMode {
|
|||
}
|
||||
}
|
||||
|
||||
/// Some modules provide options for truncating text.
|
||||
/// This is controlled using a common `TruncateMode` type,
|
||||
/// which is defined below.
|
||||
///
|
||||
/// The option can be configured in one of two modes.
|
||||
///
|
||||
#[derive(Debug, Deserialize, Clone, Copy)]
|
||||
#[serde(untagged)]
|
||||
pub enum TruncateMode {
|
||||
/// Auto mode lets GTK decide when to ellipsize.
|
||||
///
|
||||
/// To use this mode, set the truncate option to a string
|
||||
/// declaring the location to truncate text from and place the ellipsis.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```corn
|
||||
/// { truncate = "start" }
|
||||
/// ```
|
||||
///
|
||||
/// **Valid options**: `start`, `middle`, `end`
|
||||
/// <br>
|
||||
/// **Default**: `null`
|
||||
Auto(EllipsizeMode),
|
||||
|
||||
/// Length mode defines a fixed point at which to ellipsize.
|
||||
///
|
||||
/// Generally you will want to set only one of `length` or `max_length`,
|
||||
/// but you can set both if required.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```corn
|
||||
/// {
|
||||
/// truncate.mode = "start"
|
||||
/// truncate.length = 50
|
||||
/// truncate.max_length = 70
|
||||
/// }
|
||||
/// ```
|
||||
Length {
|
||||
/// The location to truncate text from and place the ellipsis.
|
||||
/// **Valid options**: `start`, `middle`, `end`
|
||||
/// <br>
|
||||
/// **Default**: `null`
|
||||
mode: EllipsizeMode,
|
||||
|
||||
/// The fixed width (in characters) of the widget.
|
||||
///
|
||||
/// The widget will be expanded to this width
|
||||
/// if it would have otherwise been smaller.
|
||||
///
|
||||
/// Leave unset to let GTK automatically handle.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
length: Option<i32>,
|
||||
|
||||
/// The maximum number of characters to show
|
||||
/// before truncating.
|
||||
///
|
||||
/// Leave unset to let GTK automatically handle.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
max_length: Option<i32>,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ pub fn new_icon_label(input: &str, icon_theme: &IconTheme, size: i32) -> gtk::Bo
|
|||
ImageProvider::parse(input, icon_theme, false, size)
|
||||
.map(|provider| provider.load_into_image(image));
|
||||
} else {
|
||||
let label = Label::new(Some(input));
|
||||
let label = Label::builder().use_markup(true).label(input).build();
|
||||
label.add_class("icon");
|
||||
label.add_class("text-icon");
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ impl IronVar {
|
|||
/// Sets the current variable value.
|
||||
/// The change is broadcast to all receivers.
|
||||
fn set(&mut self, value: Option<String>) {
|
||||
self.value = value.clone();
|
||||
self.value.clone_from(&value);
|
||||
send!(self.tx, value);
|
||||
}
|
||||
|
||||
|
|
29
src/main.rs
29
src/main.rs
|
@ -9,7 +9,7 @@ use std::rc::Rc;
|
|||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
#[cfg(feature = "ipc")]
|
||||
use std::sync::RwLock;
|
||||
use std::sync::{mpsc, Arc, OnceLock};
|
||||
use std::sync::{mpsc, Arc, Mutex, OnceLock};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
#[cfg(feature = "cli")]
|
||||
|
@ -339,17 +339,36 @@ fn load_output_bars(
|
|||
app: &Application,
|
||||
output: &OutputInfo,
|
||||
) -> Result<Vec<Bar>> {
|
||||
// Hack to track monitor positions due to new GTK3/wlroots bug:
|
||||
// https://github.com/swaywm/sway/issues/8164
|
||||
// This relies on Wayland always tracking monitors in the same order as GDK.
|
||||
// We also need this static to ensure hot-reloading continues to work as best we can.
|
||||
static INDEX_MAP: OnceLock<Mutex<Vec<String>>> = OnceLock::new();
|
||||
|
||||
let Some(monitor_name) = &output.name else {
|
||||
return Err(Report::msg("Output missing monitor name"));
|
||||
};
|
||||
|
||||
let map = INDEX_MAP.get_or_init(|| Mutex::new(vec![]));
|
||||
|
||||
let index = lock!(map).iter().position(|n| n == monitor_name);
|
||||
let index = match index {
|
||||
Some(index) => index,
|
||||
None => {
|
||||
lock!(map).push(monitor_name.clone());
|
||||
lock!(map).len() - 1
|
||||
}
|
||||
};
|
||||
|
||||
let config = ironbar.config.borrow();
|
||||
let display = get_display();
|
||||
|
||||
let pos = output.logical_position.unwrap_or_default();
|
||||
let monitor = display
|
||||
.monitor_at_point(pos.0, pos.1)
|
||||
.expect("monitor to exist");
|
||||
// let pos = output.logical_position.unwrap_or_default();
|
||||
// let monitor = display
|
||||
// .monitor_at_point(pos.0, pos.1)
|
||||
// .expect("monitor to exist");
|
||||
|
||||
let monitor = display.monitor(index as i32).expect("monitor to exist");
|
||||
|
||||
let show_default_bar =
|
||||
config.bar.start.is_some() || config.bar.center.is_some() || config.bar.end.is_some();
|
||||
|
|
|
@ -19,16 +19,33 @@ use tracing::{debug, error};
|
|||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct CairoModule {
|
||||
/// The path to the Lua script to load.
|
||||
/// This can be absolute, or relative to the working directory.
|
||||
///
|
||||
/// The script must contain the entry `draw` function.
|
||||
///
|
||||
/// **Required**
|
||||
path: PathBuf,
|
||||
|
||||
/// The number of milliseconds between each draw call.
|
||||
///
|
||||
/// **Default**: `200`
|
||||
#[serde(default = "default_frequency")]
|
||||
frequency: u64,
|
||||
|
||||
/// The canvas width in pixels.
|
||||
///
|
||||
/// **Default**: `42`
|
||||
#[serde(default = "default_size")]
|
||||
width: u32,
|
||||
|
||||
/// The canvas height in pixels.
|
||||
///
|
||||
/// **Default**: `42`
|
||||
#[serde(default = "default_size")]
|
||||
height: u32,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
|
|
@ -18,18 +18,34 @@ use tracing::{debug, error};
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ClipboardModule {
|
||||
/// The icon to show on the bar widget button.
|
||||
/// Supports [image](images) icons.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon")]
|
||||
icon: String,
|
||||
|
||||
/// The size to render the icon at.
|
||||
/// Note this only applies to image-type icons.
|
||||
///
|
||||
/// **Default**: `32`
|
||||
#[serde(default = "default_icon_size")]
|
||||
icon_size: i32,
|
||||
|
||||
/// The maximum number of items to keep in the history,
|
||||
/// and to show in the popup.
|
||||
///
|
||||
/// **Default**: `10`
|
||||
#[serde(default = "default_max_items")]
|
||||
max_items: usize,
|
||||
|
||||
// -- Common --
|
||||
/// See [truncate options](module-level-options#truncate-mode).
|
||||
///
|
||||
/// **Default**: `null`
|
||||
truncate: Option<TruncateMode>,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
|
|
@ -17,23 +17,47 @@ use crate::{glib_recv, module_impl, send_async, spawn, try_send};
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ClockModule {
|
||||
/// Date/time format string.
|
||||
/// Default: `%d/%m/%Y %H:%M`
|
||||
/// The format string to use for the date/time shown on the bar.
|
||||
/// Pango markup is supported.
|
||||
///
|
||||
/// Detail on available tokens can be found here:
|
||||
/// <https://docs.rs/chrono/latest/chrono/format/strftime/index.html>
|
||||
///
|
||||
/// **Default**: `%d/%m/%Y %H:%M`
|
||||
#[serde(default = "default_format")]
|
||||
format: String,
|
||||
|
||||
/// The format string to use for the date/time shown in the popup header.
|
||||
/// Pango markup is supported.
|
||||
///
|
||||
/// Detail on available tokens can be found here:
|
||||
/// <https://docs.rs/chrono/latest/chrono/format/strftime/index.html>
|
||||
///
|
||||
/// **Default**: `%H:%M:%S`
|
||||
#[serde(default = "default_popup_format")]
|
||||
format_popup: String,
|
||||
|
||||
/// The locale to use when formatting dates.
|
||||
///
|
||||
/// Note this will not control the calendar -
|
||||
/// for that you must set `LC_TIME`.
|
||||
///
|
||||
/// **Valid options**: See [here](https://docs.rs/pure-rust-locales/0.8.1/pure_rust_locales/enum.Locale.html#variants)
|
||||
/// <br>
|
||||
/// **Default**: `$LC_TIME` or `$LANG` or `'POSIX'`
|
||||
#[serde(default = "default_locale")]
|
||||
locale: String,
|
||||
|
||||
/// The orientation to display the widget contents.
|
||||
/// Setting to vertical will rotate text 90 degrees.
|
||||
///
|
||||
/// **Valid options**: `horizontal`, `vertical`
|
||||
/// <br>
|
||||
/// **Default**: `horizontal`
|
||||
#[serde(default)]
|
||||
orientation: ModuleOrientation,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
|
|
@ -7,9 +7,26 @@ use serde::Deserialize;
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct BoxWidget {
|
||||
/// Widget name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
name: Option<String>,
|
||||
|
||||
/// Widget class name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
class: Option<String>,
|
||||
|
||||
/// Whether child widgets should be horizontally or vertically added.
|
||||
///
|
||||
/// **Valid options**: `horizontal`, `vertical`, `h`, `v`
|
||||
/// <br />
|
||||
/// **Default**: `horizontal`
|
||||
orientation: Option<ModuleOrientation>,
|
||||
|
||||
/// Modules and widgets to add to this box.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
widgets: Option<Vec<WidgetConfig>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -11,13 +11,43 @@ use super::{CustomWidget, CustomWidgetContext, ExecEvent, WidgetConfig};
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ButtonWidget {
|
||||
/// Widget name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
name: Option<String>,
|
||||
|
||||
/// Widget class name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
class: Option<String>,
|
||||
|
||||
/// Widget text label. Pango markup and embedded scripts are supported.
|
||||
///
|
||||
/// This is a shorthand for adding a label widget to the button.
|
||||
/// Ignored if `widgets` is set.
|
||||
///
|
||||
/// This is a [Dynamic String](dynamic-values#dynamic-string).
|
||||
///
|
||||
/// **Default**: `null`
|
||||
label: Option<String>,
|
||||
|
||||
/// Command to execute. More on this [below](#commands).
|
||||
///
|
||||
/// **Default**: `null`
|
||||
on_click: Option<String>,
|
||||
widgets: Option<Vec<WidgetConfig>>,
|
||||
|
||||
/// Orientation of the button.
|
||||
///
|
||||
/// **Valid options**: `horizontal`, `vertical`, `h`, `v`
|
||||
/// <br />
|
||||
/// **Default**: `horizontal`
|
||||
#[serde(default)]
|
||||
orientation: ModuleOrientation,
|
||||
|
||||
/// Modules and widgets to add to this box.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
widgets: Option<Vec<WidgetConfig>>,
|
||||
}
|
||||
|
||||
impl CustomWidget for ButtonWidget {
|
||||
|
|
|
@ -10,9 +10,27 @@ use super::{CustomWidget, CustomWidgetContext};
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ImageWidget {
|
||||
/// Widget name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
name: Option<String>,
|
||||
|
||||
/// Widget class name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
class: Option<String>,
|
||||
|
||||
/// Image source.
|
||||
///
|
||||
/// This is an [image](image) via [Dynamic String](dynamic-values#dynamic-string).
|
||||
///
|
||||
/// **Required**
|
||||
src: String,
|
||||
|
||||
/// The width/height of the image.
|
||||
/// Aspect ratio is preserved.
|
||||
///
|
||||
/// **Default**: `32`
|
||||
#[serde(default = "default_size")]
|
||||
size: i32,
|
||||
}
|
||||
|
|
|
@ -10,9 +10,29 @@ use super::{CustomWidget, CustomWidgetContext};
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct LabelWidget {
|
||||
/// Widget name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
name: Option<String>,
|
||||
|
||||
/// Widget class name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
class: Option<String>,
|
||||
|
||||
/// Widget text label. Pango markup and embedded scripts are supported.
|
||||
///
|
||||
/// This is a [Dynamic String](dynamic-values#dynamic-string).
|
||||
///
|
||||
/// **Required**
|
||||
label: String,
|
||||
|
||||
/// Orientation of the label.
|
||||
/// Setting to vertical will rotate text 90 degrees.
|
||||
///
|
||||
/// **Valid options**: `horizontal`, `vertical`, `h`, `v`
|
||||
/// <br />
|
||||
/// **Default**: `horizontal`
|
||||
#[serde(default)]
|
||||
orientation: ModuleOrientation,
|
||||
}
|
||||
|
@ -24,7 +44,6 @@ impl CustomWidget for LabelWidget {
|
|||
let label = build!(self, Self::Widget);
|
||||
|
||||
label.set_angle(self.orientation.to_angle());
|
||||
|
||||
label.set_use_markup(true);
|
||||
|
||||
{
|
||||
|
|
|
@ -29,19 +29,28 @@ use tracing::{debug, error};
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct CustomModule {
|
||||
/// Widgets to add to the bar container
|
||||
/// Modules and widgets to add to the bar container.
|
||||
///
|
||||
/// **Default**: `[]`
|
||||
bar: Vec<WidgetConfig>,
|
||||
/// Widgets to add to the popup container
|
||||
|
||||
/// Modules and widgets to add to the popup container.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
popup: Option<Vec<WidgetConfig>>,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct WidgetConfig {
|
||||
/// One of a custom module native Ironbar module.
|
||||
#[serde(flatten)]
|
||||
widget: WidgetOrModule,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
common: CommonConfig,
|
||||
}
|
||||
|
@ -49,18 +58,27 @@ pub struct WidgetConfig {
|
|||
#[derive(Debug, Deserialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum WidgetOrModule {
|
||||
/// A custom-module specific basic widget
|
||||
Widget(Widget),
|
||||
/// A native Ironbar module, such as `clock` or `focused`.
|
||||
/// All widgets are supported, including their popups.
|
||||
Module(ModuleConfig),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum Widget {
|
||||
/// A container to place nested widgets inside.
|
||||
Box(BoxWidget),
|
||||
/// A text label. Pango markup is supported.
|
||||
Label(LabelWidget),
|
||||
/// A clickable button, which can run a command when clicked.
|
||||
Button(ButtonWidget),
|
||||
/// An image or icon from disk or http.
|
||||
Image(ImageWidget),
|
||||
/// A draggable slider.
|
||||
Slider(SliderWidget),
|
||||
/// A progress bar.
|
||||
Progress(ProgressWidget),
|
||||
}
|
||||
|
||||
|
|
|
@ -14,14 +14,49 @@ use super::{CustomWidget, CustomWidgetContext};
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ProgressWidget {
|
||||
/// Widget name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
name: Option<String>,
|
||||
|
||||
/// Widget class name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
class: Option<String>,
|
||||
|
||||
/// Orientation of the progress bar.
|
||||
///
|
||||
/// **Valid options**: `horizontal`, `vertical`, `h`, `v`
|
||||
/// <br />
|
||||
/// **Default**: `horizontal`
|
||||
#[serde(default)]
|
||||
orientation: ModuleOrientation,
|
||||
|
||||
/// Text label to show for the progress bar.
|
||||
///
|
||||
/// This is a [Dynamic String](dynamic-values#dynamic-string).
|
||||
///
|
||||
/// **Default**: `null`
|
||||
label: Option<String>,
|
||||
|
||||
/// Script to run to get the progress bar value.
|
||||
/// Output must be a valid percentage.
|
||||
///
|
||||
/// Note that this expects a numeric value between `0`-`max` as output.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
value: Option<ScriptInput>,
|
||||
|
||||
/// The maximum progress bar value.
|
||||
///
|
||||
/// **Default**: `100`
|
||||
#[serde(default = "default_max")]
|
||||
max: f64,
|
||||
|
||||
/// The progress bar length, in pixels.
|
||||
/// GTK will automatically determine the size if left blank.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
length: Option<i32>,
|
||||
}
|
||||
|
||||
|
|
|
@ -17,18 +17,67 @@ use super::{CustomWidget, CustomWidgetContext, ExecEvent};
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct SliderWidget {
|
||||
/// Widget name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
name: Option<String>,
|
||||
|
||||
/// Widget class name.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
class: Option<String>,
|
||||
|
||||
/// Orientation of the slider.
|
||||
///
|
||||
/// **Valid options**: `horizontal`, `vertical`, `h`, `v`
|
||||
/// <br />
|
||||
/// **Default**: `horizontal`
|
||||
#[serde(default)]
|
||||
orientation: ModuleOrientation,
|
||||
|
||||
/// Script to run to get the slider value.
|
||||
/// Output must be a valid number.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
value: Option<ScriptInput>,
|
||||
|
||||
/// Command to execute when the slider changes.
|
||||
/// More on this [below](#slider).
|
||||
///
|
||||
/// Note that this will provide the floating point value as an argument.
|
||||
/// If your input program requires an integer, you will need to round it.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
on_change: Option<String>,
|
||||
|
||||
/// Minimum slider value.
|
||||
///
|
||||
/// **Default**: `0`
|
||||
#[serde(default = "default_min")]
|
||||
min: f64,
|
||||
|
||||
/// Maximum slider value.
|
||||
///
|
||||
/// **Default**: `100`
|
||||
#[serde(default = "default_max")]
|
||||
max: f64,
|
||||
|
||||
/// If the increment to change when scrolling with the mousewheel.
|
||||
/// If left blank, GTK will use the default value,
|
||||
/// determined by the current environment.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
step: Option<f64>,
|
||||
|
||||
/// The slider length.
|
||||
/// GTK will automatically determine the size if left blank.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
length: Option<i32>,
|
||||
|
||||
/// Whether to show the value label above the slider.
|
||||
///
|
||||
/// **Default**: `true`
|
||||
#[serde(default = "crate::config::default_true")]
|
||||
show_label: bool,
|
||||
}
|
||||
|
|
|
@ -14,18 +14,29 @@ use tracing::debug;
|
|||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct FocusedModule {
|
||||
/// Whether to show icon on the bar.
|
||||
///
|
||||
/// **Default**: `true`
|
||||
#[serde(default = "crate::config::default_true")]
|
||||
show_icon: bool,
|
||||
/// Whether to show app name on the bar.
|
||||
///
|
||||
/// **Default**: `true`
|
||||
#[serde(default = "crate::config::default_true")]
|
||||
show_title: bool,
|
||||
|
||||
/// Icon size in pixels.
|
||||
///
|
||||
/// **Default**: `32`
|
||||
#[serde(default = "default_icon_size")]
|
||||
icon_size: i32,
|
||||
|
||||
// -- common --
|
||||
/// See [truncate options](module-level-options#truncate-mode).
|
||||
///
|
||||
/// **Default**: `null`
|
||||
truncate: Option<TruncateMode>,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
@ -81,7 +92,6 @@ impl Module<gtk::Box> for FocusedModule {
|
|||
while let Ok(event) = wlrx.recv().await {
|
||||
match event {
|
||||
ToplevelEvent::Update(info) => {
|
||||
println!("{current:?} | {info:?}");
|
||||
if info.focused {
|
||||
debug!("Changing focus");
|
||||
|
||||
|
|
|
@ -10,8 +10,13 @@ use tokio::sync::mpsc;
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct LabelModule {
|
||||
/// The text to show on the label.
|
||||
/// This is a [Dynamic String](dynamic-values#dynamic-string).
|
||||
///
|
||||
/// **Required**
|
||||
label: String,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ impl Item {
|
|||
let id = info.id;
|
||||
|
||||
if self.windows.is_empty() {
|
||||
self.name = info.title.clone();
|
||||
self.name.clone_from(&info.title);
|
||||
}
|
||||
|
||||
let window = Window::from(info);
|
||||
|
@ -59,7 +59,7 @@ impl Item {
|
|||
pub fn set_window_name(&mut self, window_id: usize, name: String) {
|
||||
if let Some(window) = self.windows.get_mut(&window_id) {
|
||||
if let OpenState::Open { focused: true, .. } = window.open_state {
|
||||
self.name = name.clone();
|
||||
self.name.clone_from(&name);
|
||||
}
|
||||
|
||||
window.name = name;
|
||||
|
|
|
@ -22,20 +22,38 @@ use tracing::{debug, error, trace};
|
|||
pub struct LauncherModule {
|
||||
/// List of app IDs (or classes) to always show regardless of open state,
|
||||
/// in the order specified.
|
||||
///
|
||||
/// **Default**: `null`
|
||||
favorites: Option<Vec<String>>,
|
||||
|
||||
/// Whether to show application names on the bar.
|
||||
///
|
||||
/// **Default**: `false`
|
||||
#[serde(default = "crate::config::default_false")]
|
||||
show_names: bool,
|
||||
|
||||
/// Whether to show application icons on the bar.
|
||||
///
|
||||
/// **Default**: `true`
|
||||
#[serde(default = "crate::config::default_true")]
|
||||
show_icons: bool,
|
||||
|
||||
/// Size in pixels to render icon at (image icons only).
|
||||
///
|
||||
/// **Default**: `32`
|
||||
#[serde(default = "default_icon_size")]
|
||||
icon_size: i32,
|
||||
|
||||
/// Whether items should be added from right-to-left
|
||||
/// instead of left-to-right.
|
||||
///
|
||||
/// This includes favourites.
|
||||
///
|
||||
/// **Default**: `false`
|
||||
#[serde(default = "crate::config::default_false")]
|
||||
reversed: bool,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
@ -182,13 +200,22 @@ impl Module<gtk::Box> for LauncherModule {
|
|||
}?;
|
||||
}
|
||||
ToplevelEvent::Update(info) => {
|
||||
if let Some(item) = lock!(items).get_mut(&info.app_id) {
|
||||
// check if open, as updates can be sent as program closes
|
||||
// if it's a focused favourite closing, it otherwise incorrectly re-focuses.
|
||||
let is_open = if let Some(item) = lock!(items).get_mut(&info.app_id) {
|
||||
item.set_window_focused(info.id, info.focused);
|
||||
item.set_window_name(info.id, info.title.clone());
|
||||
}
|
||||
|
||||
send_update(LauncherUpdate::Focus(info.app_id.clone(), info.focused))
|
||||
.await?;
|
||||
item.open_state.is_open()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
send_update(LauncherUpdate::Focus(
|
||||
info.app_id.clone(),
|
||||
is_open && info.focused,
|
||||
))
|
||||
.await?;
|
||||
send_update(LauncherUpdate::Title(
|
||||
info.app_id.clone(),
|
||||
info.id,
|
||||
|
@ -355,8 +382,7 @@ impl Module<gtk::Box> for LauncherModule {
|
|||
button.set_open(true);
|
||||
button.set_focused(win.open_state.is_focused());
|
||||
|
||||
let mut menu_state = write_lock!(button.menu_state);
|
||||
menu_state.num_windows += 1;
|
||||
write_lock!(button.menu_state).num_windows += 1;
|
||||
}
|
||||
}
|
||||
LauncherUpdate::RemoveItem(app_id) => {
|
||||
|
|
|
@ -6,34 +6,50 @@ use std::path::PathBuf;
|
|||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct Icons {
|
||||
/// Icon to display when playing.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_play")]
|
||||
pub(crate) play: String,
|
||||
|
||||
/// Icon to display when paused.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_pause")]
|
||||
pub(crate) pause: String,
|
||||
|
||||
/// Icon to display for previous button.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_prev")]
|
||||
pub(crate) prev: String,
|
||||
|
||||
/// Icon to display for next button.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_next")]
|
||||
pub(crate) next: String,
|
||||
|
||||
/// Icon to display under volume slider
|
||||
/// Icon to display under volume slider.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_volume")]
|
||||
pub(crate) volume: String,
|
||||
|
||||
/// Icon to display nex to track title
|
||||
/// Icon to display nex to track title.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_track")]
|
||||
pub(crate) track: String,
|
||||
|
||||
/// Icon to display nex to album name
|
||||
/// Icon to display nex to album name.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_album")]
|
||||
pub(crate) album: String,
|
||||
|
||||
/// Icon to display nex to artist name
|
||||
/// Icon to display nex to artist name.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_artist")]
|
||||
pub(crate) artist: String,
|
||||
}
|
||||
|
@ -73,33 +89,62 @@ pub struct MusicModule {
|
|||
pub(crate) player_type: PlayerType,
|
||||
|
||||
/// Format of current song info to display on the bar.
|
||||
///
|
||||
/// Info on formatting tokens [below](#formatting-tokens).
|
||||
///
|
||||
/// **Default**: `{title} / {artist}`
|
||||
#[serde(default = "default_format")]
|
||||
pub(crate) format: String,
|
||||
|
||||
/// Player state icons
|
||||
/// Player state icons.
|
||||
///
|
||||
/// See [icons](#icons).
|
||||
#[serde(default)]
|
||||
pub(crate) icons: Icons,
|
||||
|
||||
// -- MPD --
|
||||
/// TCP or Unix socket address.
|
||||
#[serde(default = "default_socket")]
|
||||
pub(crate) host: String,
|
||||
/// Path to root of music directory.
|
||||
#[serde(default = "default_music_dir")]
|
||||
pub(crate) music_dir: PathBuf,
|
||||
|
||||
/// Whether to show the play/pause status icon
|
||||
/// on the bar.
|
||||
///
|
||||
/// **Default**: `true`
|
||||
#[serde(default = "crate::config::default_true")]
|
||||
pub(crate) show_status_icon: bool,
|
||||
|
||||
/// Size to render the icons at, in pixels (image icons only).
|
||||
///
|
||||
/// **Default** `32`
|
||||
#[serde(default = "default_icon_size")]
|
||||
pub(crate) icon_size: i32,
|
||||
|
||||
/// Size to render the album art image at inside the popup, in pixels.
|
||||
///
|
||||
/// **Default**: `128`
|
||||
#[serde(default = "default_cover_image_size")]
|
||||
pub(crate) cover_image_size: i32,
|
||||
|
||||
// -- MPD --
|
||||
/// *[MPD Only]*
|
||||
/// TCP or Unix socket address of the MPD server.
|
||||
/// For TCP, this should include the port number.
|
||||
///
|
||||
/// **Default**: `localhost:6600`
|
||||
#[serde(default = "default_socket")]
|
||||
pub(crate) host: String,
|
||||
|
||||
/// *[MPD Only]*
|
||||
/// Path to root of the MPD server's music directory.
|
||||
/// This is required for displaying album art.
|
||||
///
|
||||
/// **Default**: `$HOME/Music`
|
||||
#[serde(default = "default_music_dir")]
|
||||
pub(crate) music_dir: PathBuf,
|
||||
|
||||
// -- Common --
|
||||
/// See [truncate options](module-level-options#truncate-mode).
|
||||
///
|
||||
/// **Default**: `null`
|
||||
pub(crate) truncate: Option<TruncateMode>,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
|
|
@ -191,6 +191,7 @@ impl Module<Button> for MusicModule {
|
|||
let icon_pause = new_icon_label(&self.icons.pause, info.icon_theme, self.icon_size);
|
||||
let label = Label::new(None);
|
||||
|
||||
label.set_use_markup(true);
|
||||
label.set_angle(info.bar_position.get_angle());
|
||||
|
||||
if let Some(truncate) = self.truncate {
|
||||
|
@ -408,7 +409,7 @@ impl Module<Button> for MusicModule {
|
|||
// only update art when album changes
|
||||
let new_cover = update.song.cover_path;
|
||||
if prev_cover != new_cover {
|
||||
prev_cover = new_cover.clone();
|
||||
prev_cover.clone_from(&new_cover);
|
||||
let res = if let Some(image) = new_cover.and_then(|cover_path| {
|
||||
ImageProvider::parse(&cover_path, &icon_theme, false, image_size)
|
||||
}) {
|
||||
|
@ -544,7 +545,14 @@ impl IconLabel {
|
|||
let container = gtk::Box::new(Orientation::Horizontal, 5);
|
||||
|
||||
let icon = new_icon_label(icon_input, icon_theme, 24);
|
||||
let label = Label::new(label);
|
||||
|
||||
let mut builder = Label::builder().use_markup(true);
|
||||
|
||||
if let Some(label) = label {
|
||||
builder = builder.label(label);
|
||||
}
|
||||
|
||||
let label = builder.build();
|
||||
|
||||
icon.add_class("icon-box");
|
||||
label.add_class("label");
|
||||
|
|
|
@ -11,28 +11,60 @@ use tracing::error;
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct NotificationsModule {
|
||||
/// Whether to show the current notification count.
|
||||
///
|
||||
/// **Default**: `true`
|
||||
#[serde(default = "crate::config::default_true")]
|
||||
show_count: bool,
|
||||
|
||||
/// SwayNC state icons.
|
||||
///
|
||||
/// See [icons](#icons).
|
||||
#[serde(default)]
|
||||
icons: Icons,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
struct Icons {
|
||||
/// Icon to show when the panel is closed, with no notifications.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_closed_none")]
|
||||
closed_none: String,
|
||||
|
||||
/// Icon to show when the panel is closed, with notifications.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_closed_some")]
|
||||
closed_some: String,
|
||||
|
||||
/// Icon to show when the panel is closed, with DnD enabled.
|
||||
/// Takes higher priority than count-based icons.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_closed_dnd")]
|
||||
closed_dnd: String,
|
||||
|
||||
/// Icon to show when the panel is open, with no notifications.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_open_none")]
|
||||
open_none: String,
|
||||
|
||||
/// Icon to show when the panel is open, with notifications.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_open_some")]
|
||||
open_some: String,
|
||||
|
||||
/// Icon to show when the panel is open, with DnD enabled.
|
||||
/// Takes higher priority than count-based icons.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_open_dnd")]
|
||||
open_dnd: String,
|
||||
}
|
||||
|
|
|
@ -12,14 +12,29 @@ use tracing::error;
|
|||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ScriptModule {
|
||||
/// Path to script to execute.
|
||||
///
|
||||
/// This can be an absolute path,
|
||||
/// or relative to the working directory.
|
||||
///
|
||||
/// **Required**
|
||||
cmd: String,
|
||||
/// Script execution mode
|
||||
|
||||
/// Script execution mode.
|
||||
/// See [modes](#modes) for more info.
|
||||
///
|
||||
/// **Valid options**: `poll`, `watch`
|
||||
/// <br />
|
||||
/// **Default**: `poll`
|
||||
#[serde(default = "default_mode")]
|
||||
mode: ScriptMode,
|
||||
|
||||
/// Time in milliseconds between executions.
|
||||
///
|
||||
/// **Default**: `5000`
|
||||
#[serde(default = "default_interval")]
|
||||
interval: u64,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
|
|
@ -15,33 +15,76 @@ use tokio::time::sleep;
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct SysInfoModule {
|
||||
/// List of formatting strings.
|
||||
/// List of strings including formatting tokens.
|
||||
/// For available tokens, see [below](#formatting-tokens).
|
||||
///
|
||||
/// **Required**
|
||||
format: Vec<String>,
|
||||
/// Number of seconds between refresh
|
||||
|
||||
/// Number of seconds between refresh.
|
||||
///
|
||||
/// This can be set as a global interval,
|
||||
/// or passed as an object to customize the interval per-system.
|
||||
///
|
||||
/// **Default**: `5`
|
||||
#[serde(default = "Interval::default")]
|
||||
interval: Interval,
|
||||
|
||||
/// The orientation of text for the labels.
|
||||
///
|
||||
/// **Valid options**: `horizontal`, `vertical, `h`, `v`
|
||||
/// <br>
|
||||
/// **Default** : `horizontal`
|
||||
#[serde(default)]
|
||||
orientation: ModuleOrientation,
|
||||
|
||||
/// The orientation by which the labels are laid out.
|
||||
///
|
||||
/// **Valid options**: `horizontal`, `vertical, `h`, `v`
|
||||
/// <br>
|
||||
/// **Default** : `horizontal`
|
||||
direction: Option<ModuleOrientation>,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Copy, Clone)]
|
||||
pub struct Intervals {
|
||||
/// The number of seconds between refreshing memory data.
|
||||
///
|
||||
/// **Default**: `5`
|
||||
#[serde(default = "default_interval")]
|
||||
memory: u64,
|
||||
|
||||
/// The number of seconds between refreshing CPU data.
|
||||
///
|
||||
/// **Default**: `5`
|
||||
#[serde(default = "default_interval")]
|
||||
cpu: u64,
|
||||
|
||||
/// The number of seconds between refreshing temperature data.
|
||||
///
|
||||
/// **Default**: `5`
|
||||
#[serde(default = "default_interval")]
|
||||
temps: u64,
|
||||
|
||||
/// The number of seconds between refreshing disk data.
|
||||
///
|
||||
/// **Default**: `5`
|
||||
#[serde(default = "default_interval")]
|
||||
disks: u64,
|
||||
|
||||
/// The number of seconds between refreshing network data.
|
||||
///
|
||||
/// **Default**: `5`
|
||||
#[serde(default = "default_interval")]
|
||||
networks: u64,
|
||||
|
||||
/// The number of seconds between refreshing system data.
|
||||
///
|
||||
/// **Default**: `5`
|
||||
#[serde(default = "default_interval")]
|
||||
system: u64,
|
||||
}
|
||||
|
|
|
@ -20,15 +20,28 @@ use tracing::{debug, error, warn};
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct TrayModule {
|
||||
/// Requests that icons from the theme be used over the item-provided item.
|
||||
/// Most items only provide one or the other so this will have no effect in most circumstances.
|
||||
///
|
||||
/// **Default**: `true`
|
||||
#[serde(default = "crate::config::default_true")]
|
||||
prefer_theme_icons: bool,
|
||||
|
||||
/// Size in pixels to display the tray icons as.
|
||||
///
|
||||
/// **Default**: `16`
|
||||
#[serde(default = "default_icon_size")]
|
||||
icon_size: u32,
|
||||
|
||||
/// Direction to display the tray items.
|
||||
///
|
||||
/// **Valid options**: `top_to_bottom`, `bottom_to_top`, `left_to_right`, `right_to_left`
|
||||
/// <br>
|
||||
/// **Default**: `left_to_right` if bar is horizontal, `top_to_bottom` if bar is vertical
|
||||
#[serde(default, deserialize_with = "deserialize_orientation")]
|
||||
direction: Option<PackDirection>,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
|
|
@ -23,12 +23,20 @@ const MINUTE: i64 = 60;
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct UpowerModule {
|
||||
/// The format string to use for the widget button label.
|
||||
/// For available tokens, see [below](#formatting-tokens).
|
||||
///
|
||||
/// **Default**: `{percentage}%`
|
||||
#[serde(default = "default_format")]
|
||||
format: String,
|
||||
|
||||
/// The size to render the icon at, in pixels.
|
||||
///
|
||||
/// **Default**: `24`
|
||||
#[serde(default = "default_icon_size")]
|
||||
icon_size: i32,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
|
|
@ -15,15 +15,27 @@ use tokio::sync::mpsc;
|
|||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct VolumeModule {
|
||||
/// The format string to use for the widget button label.
|
||||
/// For available tokens, see [below](#formatting-tokens).
|
||||
///
|
||||
/// **Default**: `{icon} {percentage}%`
|
||||
#[serde(default = "default_format")]
|
||||
format: String,
|
||||
|
||||
/// Maximum value to allow volume sliders to reach.
|
||||
/// Pulse supports values > 100 but this may result in distortion.
|
||||
///
|
||||
/// **Default**: `100`
|
||||
#[serde(default = "default_max_volume")]
|
||||
max_volume: f64,
|
||||
|
||||
/// Volume state icons.
|
||||
///
|
||||
/// See [icons](#icons).
|
||||
#[serde(default)]
|
||||
icons: Icons,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
@ -34,12 +46,27 @@ fn default_format() -> String {
|
|||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Icons {
|
||||
/// Icon to show for high volume levels.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_volume_high")]
|
||||
volume_high: String,
|
||||
|
||||
/// Icon to show for medium volume levels.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_volume_medium")]
|
||||
volume_medium: String,
|
||||
|
||||
/// Icon to show for low volume levels.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_volume_low")]
|
||||
volume_low: String,
|
||||
|
||||
/// Icon to show for muted outputs.
|
||||
///
|
||||
/// **Default**: ``
|
||||
#[serde(default = "default_icon_muted")]
|
||||
muted: String,
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::clients::compositor::{Visibility, Workspace, WorkspaceClient, WorkspaceUpdate};
|
||||
use crate::config::CommonConfig;
|
||||
use crate::gtk_helpers::IronbarGtkExt;
|
||||
use crate::image::new_icon_button;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::{glib_recv, module_impl, send_async, spawn, try_send};
|
||||
use crate::{glib_recv, module_impl, send_async, spawn, try_send, Ironbar};
|
||||
use color_eyre::{Report, Result};
|
||||
use gtk::prelude::*;
|
||||
use gtk::{Button, IconTheme};
|
||||
|
@ -44,26 +45,69 @@ impl Default for Favorites {
|
|||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct WorkspacesModule {
|
||||
/// Map of actual workspace names to custom names.
|
||||
///
|
||||
/// Custom names can be [images](images).
|
||||
///
|
||||
/// If a workspace is not present in the map,
|
||||
/// it will fall back to using its actual name.
|
||||
name_map: Option<HashMap<String, String>>,
|
||||
|
||||
/// Array of always shown workspaces, and what monitor to show on
|
||||
/// Workspaces which should always be shown.
|
||||
/// This can either be an array of workspace names,
|
||||
/// or a map of monitor names to arrays of workspace names.
|
||||
///
|
||||
/// **Default**: `{}`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```corn
|
||||
/// // array format
|
||||
/// {
|
||||
/// type = "workspaces"
|
||||
/// favorites = ["1", "2", "3"]
|
||||
/// }
|
||||
///
|
||||
/// // map format
|
||||
/// {
|
||||
/// type = "workspaces"
|
||||
/// favorites.DP-1 = ["1", "2", "3"]
|
||||
/// favorites.DP-2 = ["4", "5", "6"]
|
||||
/// }
|
||||
/// ```
|
||||
#[serde(default)]
|
||||
favorites: Favorites,
|
||||
|
||||
/// List of workspace names to never show
|
||||
/// A list of workspace names to never show.
|
||||
///
|
||||
/// This may be useful for scratchpad/special workspaces, for example.
|
||||
///
|
||||
/// **Default**: `[]`
|
||||
#[serde(default)]
|
||||
hidden: Vec<String>,
|
||||
|
||||
/// Whether to display buttons for all monitors.
|
||||
/// Whether to display workspaces from all monitors.
|
||||
/// When false, only shows workspaces on the current monitor.
|
||||
///
|
||||
/// **Default**: `false`
|
||||
#[serde(default = "crate::config::default_false")]
|
||||
all_monitors: bool,
|
||||
|
||||
/// The method used for sorting workspaces.
|
||||
/// `added` always appends to the end, `alphanumeric` sorts by number/name.
|
||||
///
|
||||
/// **Valid options**: `added`, `alphanumeric`
|
||||
/// <br>
|
||||
/// **Default**: `alphanumeric`
|
||||
#[serde(default)]
|
||||
sort: SortOrder,
|
||||
|
||||
/// The size to render icons at (image icons only).
|
||||
///
|
||||
/// **Default**: `32`
|
||||
#[serde(default = "default_icon_size")]
|
||||
icon_size: i32,
|
||||
|
||||
/// See [common options](module-level-options#common-options).
|
||||
#[serde(flatten)]
|
||||
pub common: Option<CommonConfig>,
|
||||
}
|
||||
|
@ -133,6 +177,15 @@ fn reorder_workspaces(container: >k::Box) {
|
|||
}
|
||||
}
|
||||
|
||||
fn find_btn(map: &HashMap<i64, Button>, workspace: &Workspace) -> Option<Button> {
|
||||
map.get(&workspace.id)
|
||||
.or_else(|| {
|
||||
map.values()
|
||||
.find(|btn| btn.label().unwrap_or_default() == workspace.name)
|
||||
})
|
||||
.cloned()
|
||||
}
|
||||
|
||||
impl WorkspacesModule {
|
||||
fn show_workspace_check(&self, output: &String, work: &Workspace) -> bool {
|
||||
(work.visibility.is_focused() || !self.hidden.contains(&work.name))
|
||||
|
@ -193,7 +246,7 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
let favs = self.favorites.clone();
|
||||
let mut fav_names: Vec<String> = vec![];
|
||||
|
||||
let mut button_map: HashMap<String, Button> = HashMap::new();
|
||||
let mut button_map: HashMap<i64, Button> = HashMap::new();
|
||||
|
||||
{
|
||||
let container = container.clone();
|
||||
|
@ -213,7 +266,7 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
|
||||
let mut added = HashSet::new();
|
||||
|
||||
let mut add_workspace = |name: &str, visibility: Visibility| {
|
||||
let mut add_workspace = |id: i64, name: &str, visibility: Visibility| {
|
||||
let item = create_button(
|
||||
name,
|
||||
visibility,
|
||||
|
@ -224,13 +277,13 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
);
|
||||
|
||||
container.add(&item);
|
||||
button_map.insert(name.to_string(), item);
|
||||
button_map.insert(id, item);
|
||||
};
|
||||
|
||||
// add workspaces from client
|
||||
for workspace in &workspaces {
|
||||
if self.show_workspace_check(&output_name, workspace) {
|
||||
add_workspace(&workspace.name, workspace.visibility);
|
||||
add_workspace(workspace.id, &workspace.name, workspace.visibility);
|
||||
added.insert(workspace.name.to_string());
|
||||
}
|
||||
}
|
||||
|
@ -240,7 +293,11 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
fav_names.push(name.to_string());
|
||||
|
||||
if !added.contains(name) {
|
||||
add_workspace(name, Visibility::Hidden);
|
||||
// Favourites are added with the same name and ID
|
||||
// as Hyprland will initialize them this way.
|
||||
// Since existing workspaces are added above,
|
||||
// this means there shouldn't be any issues with renaming.
|
||||
add_workspace(-(Ironbar::unique_id() as i64), name, Visibility::Hidden);
|
||||
added.insert(name.to_string());
|
||||
}
|
||||
}
|
||||
|
@ -265,25 +322,28 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
}
|
||||
}
|
||||
WorkspaceUpdate::Focus { old, new } => {
|
||||
if let Some(btn) = old.as_ref().and_then(|w| button_map.get(&w.name)) {
|
||||
if Some(new.monitor) == old.map(|w| w.monitor) {
|
||||
if let Some(btn) = old.as_ref().and_then(|w| find_btn(&button_map, w)) {
|
||||
if Some(new.monitor.as_str()) == old.as_ref().map(|w| w.monitor.as_str()) {
|
||||
btn.style_context().remove_class("visible");
|
||||
}
|
||||
|
||||
btn.style_context().remove_class("focused");
|
||||
}
|
||||
|
||||
let new = button_map.get(&new.name);
|
||||
if let Some(btn) = new {
|
||||
let style = btn.style_context();
|
||||
|
||||
style.add_class("visible");
|
||||
style.add_class("focused");
|
||||
if let Some(btn) = find_btn(&button_map, &new) {
|
||||
btn.add_class("visible");
|
||||
btn.add_class("focused");
|
||||
}
|
||||
}
|
||||
WorkspaceUpdate::Rename { id, name } => {
|
||||
if let Some(btn) = button_map.get(&id) {
|
||||
let name = name_map.get(&name).unwrap_or(&name);
|
||||
btn.set_label(name);
|
||||
}
|
||||
}
|
||||
WorkspaceUpdate::Add(workspace) => {
|
||||
if fav_names.contains(&workspace.name) {
|
||||
let btn = button_map.get(&workspace.name);
|
||||
let btn = button_map.get(&workspace.id);
|
||||
if let Some(btn) = btn {
|
||||
btn.style_context().remove_class("inactive");
|
||||
}
|
||||
|
@ -306,7 +366,7 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
item.show();
|
||||
|
||||
if !name.is_empty() {
|
||||
button_map.insert(name, item);
|
||||
button_map.insert(workspace.id, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -332,9 +392,9 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
item.show();
|
||||
|
||||
if !name.is_empty() {
|
||||
button_map.insert(name, item);
|
||||
button_map.insert(workspace.id, item);
|
||||
}
|
||||
} else if let Some(item) = button_map.get(&workspace.name) {
|
||||
} else if let Some(item) = button_map.get(&workspace.id) {
|
||||
container.remove(item);
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +402,8 @@ impl Module<gtk::Box> for WorkspacesModule {
|
|||
WorkspaceUpdate::Remove(workspace) => {
|
||||
let button = button_map.get(&workspace);
|
||||
if let Some(item) = button {
|
||||
if fav_names.contains(&workspace) {
|
||||
if workspace < 0 {
|
||||
// if fav_names.contains(&workspace) {
|
||||
item.style_context().add_class("inactive");
|
||||
} else {
|
||||
container.remove(item);
|
||||
|
|
3
test-configs/workspaces.corn
Normal file
3
test-configs/workspaces.corn
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
start = [ { type = "workspaces" }]
|
||||
}
|
Loading…
Add table
Reference in a new issue