1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-10-06 04:31:55 +02:00

Compare commits

..

48 commits

Author SHA1 Message Date
54e91facd3
Remove unused parts of pulseaudio module 2025-08-20 20:51:36 +02:00
d1f433c990
refactor(networkmanager): remove now unused state.rs 2025-08-20 19:56:39 +02:00
f4369b20d3
refactor(networkmanager): implement clippy::pedantic suggestions 2025-08-20 18:49:20 +02:00
92a1b3455d
Merge branch 'master' into develop
# Conflicts:
#	Cargo.toml
2025-08-20 18:04:33 +02:00
c7e002ee6c
Merge pull request #1107 from JakeStanger/dependabot/cargo/serde_json-1.0.142
build(deps): bump serde_json from 1.0.141 to 1.0.142
2025-08-06 09:49:47 +01:00
a2e72bcdde
Merge pull request #1106 from JakeStanger/dependabot/cargo/wayland-protocols-wlr-0.3.9
build(deps): bump wayland-protocols-wlr from 0.3.8 to 0.3.9
2025-08-06 09:49:36 +01:00
ef26554434
Merge pull request #1093 from slowsage/wmclass-async
fix(launcher): improve app ID handling: fallback for desktop entries.…
2025-08-05 15:10:07 +01:00
dependabot[bot]
ca77a991f7
build(deps): bump serde_json from 1.0.141 to 1.0.142
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.141 to 1.0.142.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.141...v1.0.142)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-version: 1.0.142
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-05 08:12:55 +00:00
dependabot[bot]
279ef938d1
build(deps): bump wayland-protocols-wlr from 0.3.8 to 0.3.9
Bumps [wayland-protocols-wlr](https://github.com/smithay/wayland-rs) from 0.3.8 to 0.3.9.
- [Release notes](https://github.com/smithay/wayland-rs/releases)
- [Changelog](https://github.com/Smithay/wayland-rs/blob/master/historical_changelog.md)
- [Commits](https://github.com/smithay/wayland-rs/commits)

---
updated-dependencies:
- dependency-name: wayland-protocols-wlr
  dependency-version: 0.3.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-05 08:12:51 +00:00
24ef1b700a
Merge pull request #1105 from JakeStanger/dependabot/cargo/clap-4.5.42
build(deps): bump clap from 4.5.41 to 4.5.42
2025-08-05 09:10:45 +01:00
b7557bc78b
Merge pull request #1104 from JakeStanger/dependabot/cargo/tokio-1.47.1
build(deps): bump tokio from 1.46.1 to 1.47.1
2025-08-05 09:10:18 +01:00
037de421cd
Merge pull request #1103 from JakeStanger/dependabot/cargo/notify-8.2.0
build(deps): bump notify from 8.1.0 to 8.2.0
2025-08-05 09:09:59 +01:00
dependabot[bot]
4041e080d0
build(deps): bump clap from 4.5.41 to 4.5.42
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.41 to 4.5.42.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.41...clap_complete-v4.5.42)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.42
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 18:51:20 +00:00
dependabot[bot]
491e055aa1
build(deps): bump tokio from 1.46.1 to 1.47.1
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.46.1 to 1.47.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.46.1...tokio-1.47.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.47.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 18:35:36 +00:00
dependabot[bot]
304b1d3e17
build(deps): bump notify from 8.1.0 to 8.2.0
Bumps [notify](https://github.com/notify-rs/notify) from 8.1.0 to 8.2.0.
- [Release notes](https://github.com/notify-rs/notify/releases)
- [Changelog](https://github.com/notify-rs/notify/blob/main/CHANGELOG.md)
- [Commits](https://github.com/notify-rs/notify/compare/notify-8.1.0...notify-8.2.0)

---
updated-dependencies:
- dependency-name: notify
  dependency-version: 8.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 18:13:45 +00:00
slowsage
0159c0155e fix: app_id StartupWMClass resolution in launcher 2025-08-03 16:22:06 -04:00
dea571506f
Merge pull request #1101 from JakeStanger/update_flake_lock_action
Update flake.lock
2025-08-01 08:42:25 +01:00
github-actions[bot]
bd5745f2ef flake.lock: Update
Flake lock file updates:

• Updated input 'naersk':
    'github:nix-community/naersk/38bc60bbc157ae266d4a0c96671c6c742ee17a5f?narHash=sha256-cyAAMal0aPrlb1NgzMxZqeN1mAJ2pJseDhm2m6Um8T0%3D' (2025-04-29)
  → 'github:nix-community/naersk/0e72363d0938b0208d6c646d10649164c43f4d64?narHash=sha256-uldUBFkZe/E7qbvxa3mH1ItrWZyT6w1dBKJQF/3ZSsc%3D' (2025-07-16)
• Added input 'naersk/fenix':
    'github:nix-community/fenix/bf0d6f70f4c9a9cf8845f992105652173f4b617f?narHash=sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU%3D' (2025-07-14)
• Added input 'naersk/fenix/nixpkgs':
    follows 'naersk/nixpkgs'
• Added input 'naersk/fenix/rust-analyzer-src':
    'github:rust-lang/rust-analyzer/591e3b7624be97e4443ea7b5542c191311aa141d?narHash=sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu%2BQEnJn2Sfg%3D' (2025-07-13)
• Updated input 'naersk/nixpkgs':
    'github:NixOS/nixpkgs/b95255df2360a45ddbb03817a68869d5cb01bf96?narHash=sha256-IJWIzZSkBsDzS7iS/iwSwur%2BxFkWqeLYC4kdf8ObtOM%3D' (2025-06-30)
  → 'github:NixOS/nixpkgs/be9e214982e20b8310878ac2baa063a961c1bdf6?narHash=sha256-HM791ZQtXV93xtCY%2BZxG1REzhQenSQO020cu6rHtAPk%3D' (2025-07-09)
• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/30e2e2857ba47844aa71991daa6ed1fc678bcbb7?narHash=sha256-krGXKxvkBhnrSC/kGBmg5MyupUUT5R6IBCLEzx9jhMM%3D' (2025-06-27)
  → 'github:nixos/nixpkgs/dc9637876d0dcc8c9e5e22986b857632effeb727?narHash=sha256-cKgvtz6fKuK1Xr5LQW/zOUiAC0oSQoA9nOISB0pJZqM%3D' (2025-07-28)
2025-08-01 00:20:13 +00:00
106e23e311
Merge pull request #1096 from JakeStanger/dependabot/cargo/serde_json-1.0.141
build(deps): bump serde_json from 1.0.140 to 1.0.141
2025-07-21 16:52:44 +01:00
546e75c43c
Merge pull request #1099 from JakeStanger/dependabot/cargo/zbus-5.9.0
build(deps): bump zbus from 5.8.0 to 5.9.0
2025-07-21 16:47:56 +01:00
50ab48500f
Merge pull request #1097 from JakeStanger/dependabot/cargo/mlua-0.11.1
build(deps): bump mlua from 0.11.0 to 0.11.1
2025-07-21 16:45:11 +01:00
798a71cc13
Merge pull request #1098 from JakeStanger/dependabot/cargo/sysinfo-0.36.1
build(deps): bump sysinfo from 0.36.0 to 0.36.1
2025-07-21 16:44:59 +01:00
dependabot[bot]
dca0e07ce2
build(deps): bump serde_json from 1.0.140 to 1.0.141
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.140 to 1.0.141.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.140...v1.0.141)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-version: 1.0.141
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 15:42:30 +00:00
dependabot[bot]
8c9673eb1f
build(deps): bump zbus from 5.8.0 to 5.9.0
Bumps [zbus](https://github.com/dbus2/zbus) from 5.8.0 to 5.9.0.
- [Release notes](https://github.com/dbus2/zbus/releases)
- [Commits](https://github.com/dbus2/zbus/compare/zbus-5.8.0...zbus-5.9.0)

---
updated-dependencies:
- dependency-name: zbus
  dependency-version: 5.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 15:35:25 +00:00
a92e6684a0
Merge pull request #1095 from JakeStanger/dependabot/cargo/rustix-1.0.8
build(deps): bump rustix from 1.0.7 to 1.0.8
2025-07-21 16:35:18 +01:00
dependabot[bot]
eadc7a7bab
build(deps): bump sysinfo from 0.36.0 to 0.36.1
Bumps [sysinfo](https://github.com/GuillaumeGomez/sysinfo) from 0.36.0 to 0.36.1.
- [Changelog](https://github.com/GuillaumeGomez/sysinfo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/GuillaumeGomez/sysinfo/compare/v0.36.0...v0.36.1)

---
updated-dependencies:
- dependency-name: sysinfo
  dependency-version: 0.36.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 15:32:44 +00:00
dependabot[bot]
c3c3dab11b
build(deps): bump mlua from 0.11.0 to 0.11.1
Bumps [mlua](https://github.com/mlua-rs/mlua) from 0.11.0 to 0.11.1.
- [Release notes](https://github.com/mlua-rs/mlua/releases)
- [Changelog](https://github.com/mlua-rs/mlua/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mlua-rs/mlua/compare/v0.11.0...v0.11.1)

---
updated-dependencies:
- dependency-name: mlua
  dependency-version: 0.11.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 15:29:37 +00:00
dependabot[bot]
dd9a0c2065
build(deps): bump rustix from 1.0.7 to 1.0.8
Bumps [rustix](https://github.com/bytecodealliance/rustix) from 1.0.7 to 1.0.8.
- [Release notes](https://github.com/bytecodealliance/rustix/releases)
- [Changelog](https://github.com/bytecodealliance/rustix/blob/main/CHANGES.md)
- [Commits](https://github.com/bytecodealliance/rustix/compare/v1.0.7...v1.0.8)

---
updated-dependencies:
- dependency-name: rustix
  dependency-version: 1.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 15:25:58 +00:00
Alan
5520562a18
feat: support glob patterns for keyboard layout icons (#949)
* Simplistic globbing for matching keyboard layout icons

Update the logic for determining the display text for the current keyboard layout.
Instead of a direct map lookup, iterate through the layout map to support wildcard matching.

Patterns ending with `*` will match any language string starting with the characters before the `*`. This allows grouping similar layouts (e.g., `English`, `English (Colemak-DH ISO)`) under a single pattern like `English*`.

* Use `IndexMap` instead of `HashMap` for keyboard layout icons map

This enables users to choose which globs to prioritize via ordering in the config

* Enable feature `serde` for `indexmap`

* Document wildcard matching for keyboard layouts

* Enable `indexmap2` feature flag for `schemars`

* Add missing period

* use string slices

* Fix formatting
2025-07-20 22:19:58 +01:00
233f7f1ee2
Merge pull request #1094 from JakeStanger/fix/launcher-regression
fix: regression caused by #1089
2025-07-20 16:26:33 +01:00
feccc29fd1
fix: regression caused by #1089
This resolves an issue caused by a previous fix which broke launching applications with the `launcher` and `menu` modules
2025-07-20 16:21:31 +01:00
ccb57c8458
Merge pull request #1092 from slowsage/app_id_lowercase
fix(desktop_file): case-insensitive app_id -> desktop_file find
2025-07-19 09:33:56 +01:00
slowsage
ff185d0de9 fix(desktop_file): case-insensitive app_id -> desktop_file find 2025-07-19 04:01:51 -04:00
34da5edfe0
docs(sysinfo): add info on querying values
Resolves #1090
2025-07-15 22:45:49 +01:00
622ca3cc4f
Merge pull request #1089 from JakeStanger/fix/gtk-launch-zombie
fix: opening programs via `launcher` and `menu` leaving zombie processes
2025-07-14 21:45:40 +01:00
40adfaf810
fix: opening programs via launcher and menu leaving zombie processes
Fixes #1020
2025-07-14 21:42:11 +01:00
749b9f0433
Merge pull request #1067 from JakeStanger/fix/ipc-limit
fix(ipc): message size limited to 1024 bytes
2025-07-14 21:10:31 +01:00
c4f5485d53
fix(ipc): message size limited to 1024 bytes
Fixes #1065
2025-07-14 21:06:57 +01:00
a67e722dee
Merge pull request #1088 from JakeStanger/chores
Chores
2025-07-14 20:09:20 +01:00
f1a8b42cfa
chore: clippy/fmt 2025-07-14 19:55:46 +01:00
3a3888a2d6
chore: update deps 2025-07-14 19:55:25 +01:00
b68e4b4af9
chore(deps): update system-tray 2025-07-14 19:34:04 +01:00
f1dc35e873
Merge pull request #1086 from JakeStanger/dependabot/cargo/clap-4.5.41
build(deps): bump clap from 4.5.40 to 4.5.41
2025-07-14 19:32:25 +01:00
dc8af7ada8
Merge pull request #1085 from JakeStanger/dependabot/cargo/sysinfo-0.36.0
build(deps): bump sysinfo from 0.35.2 to 0.36.0
2025-07-14 19:30:48 +01:00
613495ce0b
Merge pull request #1084 from JakeStanger/dependabot/cargo/zbus-5.8.0
build(deps): bump zbus from 5.7.1 to 5.8.0
2025-07-14 19:28:25 +01:00
dependabot[bot]
98e9af68d9
build(deps): bump clap from 4.5.40 to 4.5.41
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.40 to 4.5.41.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.40...clap_complete-v4.5.41)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.41
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 18:24:12 +00:00
dependabot[bot]
1fbe655480
build(deps): bump sysinfo from 0.35.2 to 0.36.0
Bumps [sysinfo](https://github.com/GuillaumeGomez/sysinfo) from 0.35.2 to 0.36.0.
- [Changelog](https://github.com/GuillaumeGomez/sysinfo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/GuillaumeGomez/sysinfo/compare/v0.35.2...v0.36.0)

---
updated-dependencies:
- dependency-name: sysinfo
  dependency-version: 0.36.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 17:46:09 +00:00
dependabot[bot]
93a797be3f
build(deps): bump zbus from 5.7.1 to 5.8.0
Bumps [zbus](https://github.com/dbus2/zbus) from 5.7.1 to 5.8.0.
- [Release notes](https://github.com/dbus2/zbus/releases)
- [Commits](https://github.com/dbus2/zbus/compare/zbus-5.7.1...zbus-5.8.0)

---
updated-dependencies:
- dependency-name: zbus
  dependency-version: 5.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 17:15:47 +00:00
22 changed files with 411 additions and 611 deletions

250
Cargo.lock generated
View file

@ -265,9 +265,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.9.0" version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -309,7 +309,7 @@ version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"cairo-sys-rs", "cairo-sys-rs",
"glib", "glib",
"libc", "libc",
@ -330,11 +330,11 @@ dependencies = [
[[package]] [[package]]
name = "calloop" name = "calloop"
version = "0.12.4" version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"log", "log",
"polling", "polling",
"rustix 0.38.44", "rustix 0.38.44",
@ -344,9 +344,9 @@ dependencies = [
[[package]] [[package]]
name = "calloop-wayland-source" name = "calloop-wayland-source"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
dependencies = [ dependencies = [
"calloop", "calloop",
"rustix 0.38.44", "rustix 0.38.44",
@ -410,9 +410,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.40" version = "4.5.42"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -420,9 +420,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.40" version = "4.5.42"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -432,18 +432,18 @@ dependencies = [
[[package]] [[package]]
name = "clap_complete" name = "clap_complete"
version = "4.5.54" version = "4.5.55"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677" checksum = "a5abde44486daf70c5be8b8f8f1b66c49f86236edf6fa2abadb4d961c4c6229a"
dependencies = [ dependencies = [
"clap", "clap",
] ]
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.5.40" version = "4.5.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
dependencies = [ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
@ -821,11 +821,11 @@ dependencies = [
[[package]] [[package]]
name = "evdev-rs" name = "evdev-rs"
version = "0.6.1" version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9812d5790fb6fcce449333eb6713dad335e8c979225ed98755c84a3987e06dba" checksum = "53b9cb6084eed4e72c0306e1cbcd3fd4c8acb613044e66810f9f5d3c7896bfb7"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.9.1",
"evdev-sys", "evdev-sys",
"libc", "libc",
"log", "log",
@ -833,9 +833,9 @@ dependencies = [
[[package]] [[package]]
name = "evdev-sys" name = "evdev-sys"
version = "0.2.5" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14ead42b547b15d47089c1243d907bcf0eb94e457046d3b315a26ac9c9e9ea6d" checksum = "cdcf0d489f4d9a80ac2b3b35b92fdd8fcf68d33bb67f947afe5cd36e482de576"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -1203,7 +1203,7 @@ version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-executor", "futures-executor",
@ -1303,7 +1303,7 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc759b3184830a547b31549ab40c4b54450ab702bba79ba23f049bc1d1e3ca98" checksum = "bc759b3184830a547b31549ab40c4b54450ab702bba79ba23f049bc1d1e3ca98"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"gdk", "gdk",
"glib", "glib",
"glib-sys 0.18.1", "glib-sys 0.18.1",
@ -1525,7 +1525,7 @@ dependencies = [
"libc", "libc",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"socket2", "socket2 0.5.10",
"tokio", "tokio",
"tower-service", "tower-service",
"tracing", "tracing",
@ -1755,7 +1755,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"inotify-sys", "inotify-sys",
"libc", "libc",
] ]
@ -1775,7 +1775,7 @@ version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"cfg-if", "cfg-if",
"libc", "libc",
] ]
@ -1824,7 +1824,7 @@ dependencies = [
"notify", "notify",
"regex", "regex",
"reqwest", "reqwest",
"rustix 1.0.7", "rustix 1.0.8",
"schemars", "schemars",
"serde", "serde",
"serde_json", "serde_json",
@ -1842,7 +1842,7 @@ dependencies = [
"universal-config", "universal-config",
"walkdir", "walkdir",
"wayland-client", "wayland-client",
"wayland-protocols-wlr 0.3.8", "wayland-protocols-wlr",
"zbus", "zbus",
] ]
@ -1896,9 +1896,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.173" version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]] [[package]]
name = "libcorn" name = "libcorn"
@ -1929,7 +1929,7 @@ version = "2.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "909eb3049e16e373680fe65afe6e2a722ace06b671250cc4849557bc57d6a397" checksum = "909eb3049e16e373680fe65afe6e2a722ace06b671250cc4849557bc57d6a397"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"libc", "libc",
"libpulse-sys", "libpulse-sys",
"num-derive", "num-derive",
@ -1956,7 +1956,7 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"libc", "libc",
] ]
@ -1990,9 +1990,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.26" version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]] [[package]]
name = "lua-src" name = "lua-src"
@ -2065,9 +2065,9 @@ dependencies = [
[[package]] [[package]]
name = "mlua" name = "mlua"
version = "0.10.5" version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1f5f8fbebc7db5f671671134b9321c4b9aa9adeafccfd9a8c020ae45c6a35d0" checksum = "de25fc513588ac1273aa8c6dc0fffee6d32c12f38dc75f5cdc74547121a107ef"
dependencies = [ dependencies = [
"bstr", "bstr",
"either", "either",
@ -2080,9 +2080,9 @@ dependencies = [
[[package]] [[package]]
name = "mlua-sys" name = "mlua-sys"
version = "0.6.8" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380c1f7e2099cafcf40e51d3a9f20a346977587aa4d012eae1f043149a728a93" checksum = "bcdf7c9e260ca82aaa32ac11148941952b856bb8c69aa5a9e65962f21fcb8637"
dependencies = [ dependencies = [
"cc", "cc",
"cfg-if", "cfg-if",
@ -2163,7 +2163,7 @@ version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"cfg-if", "cfg-if",
"cfg_aliases", "cfg_aliases",
"libc", "libc",
@ -2182,11 +2182,11 @@ dependencies = [
[[package]] [[package]]
name = "notify" name = "notify"
version = "8.1.0" version = "8.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3163f59cd3fa0e9ef8c32f242966a7b9994fd7378366099593e0e73077cd8c97" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"inotify", "inotify",
"kqueue", "kqueue",
"libc", "libc",
@ -2254,7 +2254,7 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
] ]
[[package]] [[package]]
@ -2288,7 +2288,7 @@ version = "0.10.72"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"cfg-if", "cfg-if",
"foreign-types", "foreign-types",
"libc", "libc",
@ -2658,7 +2658,7 @@ version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
] ]
[[package]] [[package]]
@ -2672,6 +2672,26 @@ dependencies = [
"thiserror 2.0.12", "thiserror 2.0.12",
] ]
[[package]]
name = "ref-cast"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
dependencies = [
"proc-macro2",
"quote 1.0.39",
"syn 2.0.99",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.11.1" version = "1.11.1"
@ -2775,7 +2795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beceb6f7bf81c73e73aeef6dd1356d9a1b2b4909e1f0fc3e59b034f9572d7b7f" checksum = "beceb6f7bf81c73e73aeef6dd1356d9a1b2b4909e1f0fc3e59b034f9572d7b7f"
dependencies = [ dependencies = [
"base64", "base64",
"bitflags 2.9.0", "bitflags 2.9.1",
"serde", "serde",
"serde_derive", "serde_derive",
"unicode-ident", "unicode-ident",
@ -2808,7 +2828,7 @@ version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"errno", "errno",
"libc", "libc",
"linux-raw-sys 0.4.15", "linux-raw-sys 0.4.15",
@ -2817,15 +2837,15 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "1.0.7" version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"errno", "errno",
"libc", "libc",
"linux-raw-sys 0.9.3", "linux-raw-sys 0.9.3",
"windows-sys 0.59.0", "windows-sys 0.60.2",
] ]
[[package]] [[package]]
@ -2890,11 +2910,13 @@ dependencies = [
[[package]] [[package]]
name = "schemars" name = "schemars"
version = "0.8.22" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
dependencies = [ dependencies = [
"dyn-clone", "dyn-clone",
"indexmap",
"ref-cast",
"schemars_derive", "schemars_derive",
"serde", "serde",
"serde_json", "serde_json",
@ -2902,9 +2924,9 @@ dependencies = [
[[package]] [[package]]
name = "schemars_derive" name = "schemars_derive"
version = "0.8.22" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.39", "quote 1.0.39",
@ -2924,7 +2946,7 @@ version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"core-foundation", "core-foundation",
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@ -2980,9 +3002,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.140" version = "1.0.142"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@ -3093,11 +3115,11 @@ checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
[[package]] [[package]]
name = "smithay-client-toolkit" name = "smithay-client-toolkit"
version = "0.18.1" version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"calloop", "calloop",
"calloop-wayland-source", "calloop-wayland-source",
"cursor-icon", "cursor-icon",
@ -3110,8 +3132,8 @@ dependencies = [
"wayland-client", "wayland-client",
"wayland-csd-frame", "wayland-csd-frame",
"wayland-cursor", "wayland-cursor",
"wayland-protocols 0.31.2", "wayland-protocols",
"wayland-protocols-wlr 0.2.0", "wayland-protocols-wlr",
"wayland-scanner", "wayland-scanner",
"xkeysym", "xkeysym",
] ]
@ -3126,6 +3148,16 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "socket2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
dependencies = [
"libc",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.0" version = "1.2.0"
@ -3254,9 +3286,9 @@ dependencies = [
[[package]] [[package]]
name = "sysinfo" name = "sysinfo"
version = "0.35.2" version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e" checksum = "252800745060e7b9ffb7b2badbd8b31cfa4aa2e61af879d0a3bf2a317c20217d"
dependencies = [ dependencies = [
"libc", "libc",
"memchr", "memchr",
@ -3294,10 +3326,11 @@ dependencies = [
[[package]] [[package]]
name = "system-tray" name = "system-tray"
version = "0.7.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3397841ed755bf361606a845779e0f7333d35fb4e39627ef6f656d7cdad4c73" checksum = "90d5d024b1573d22079347055d817863c21ea0903df404668095499c08800e4a"
dependencies = [ dependencies = [
"cfg-if",
"dbusmenu-gtk3-sys", "dbusmenu-gtk3-sys",
"futures-lite", "futures-lite",
"gtk", "gtk",
@ -3421,9 +3454,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.46.1" version = "1.47.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@ -3433,10 +3466,10 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"slab", "slab",
"socket2", "socket2 0.6.0",
"tokio-macros", "tokio-macros",
"tracing", "tracing",
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -3571,7 +3604,7 @@ version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc2d9e086a412a451384326f521c8123a99a466b329941a9403696bff9b0da2" checksum = "5cc2d9e086a412a451384326f521c8123a99a466b329941a9403696bff9b0da2"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"bytes", "bytes",
"futures-util", "futures-util",
"http", "http",
@ -3929,25 +3962,25 @@ dependencies = [
[[package]] [[package]]
name = "wayland-backend" name = "wayland-backend"
version = "0.3.10" version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121" checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35"
dependencies = [ dependencies = [
"cc", "cc",
"downcast-rs", "downcast-rs",
"rustix 0.38.44", "rustix 1.0.8",
"smallvec", "smallvec",
"wayland-sys", "wayland-sys",
] ]
[[package]] [[package]]
name = "wayland-client" name = "wayland-client"
version = "0.31.10" version = "0.31.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"rustix 0.38.44", "rustix 1.0.8",
"wayland-backend", "wayland-backend",
"wayland-scanner", "wayland-scanner",
] ]
@ -3958,7 +3991,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"cursor-icon", "cursor-icon",
"wayland-backend", "wayland-backend",
] ]
@ -3976,23 +4009,11 @@ dependencies = [
[[package]] [[package]]
name = "wayland-protocols" name = "wayland-protocols"
version = "0.31.2" version = "0.32.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"wayland-backend",
"wayland-client",
"wayland-scanner",
]
[[package]]
name = "wayland-protocols"
version = "0.32.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a"
dependencies = [
"bitflags 2.9.0",
"wayland-backend", "wayland-backend",
"wayland-client", "wayland-client",
"wayland-scanner", "wayland-scanner",
@ -4000,35 +4021,22 @@ dependencies = [
[[package]] [[package]]
name = "wayland-protocols-wlr" name = "wayland-protocols-wlr"
version = "0.2.0" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
"wayland-backend", "wayland-backend",
"wayland-client", "wayland-client",
"wayland-protocols 0.31.2", "wayland-protocols",
"wayland-scanner",
]
[[package]]
name = "wayland-protocols-wlr"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf"
dependencies = [
"bitflags 2.9.0",
"wayland-backend",
"wayland-client",
"wayland-protocols 0.32.8",
"wayland-scanner", "wayland-scanner",
] ]
[[package]] [[package]]
name = "wayland-scanner" name = "wayland-scanner"
version = "0.31.6" version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quick-xml", "quick-xml",
@ -4037,9 +4045,9 @@ dependencies = [
[[package]] [[package]]
name = "wayland-sys" name = "wayland-sys"
version = "0.31.6" version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142"
dependencies = [ dependencies = [
"pkg-config", "pkg-config",
] ]
@ -4374,7 +4382,7 @@ version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.1",
] ]
[[package]] [[package]]
@ -4427,9 +4435,9 @@ dependencies = [
[[package]] [[package]]
name = "zbus" name = "zbus"
version = "5.7.1" version = "5.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3a7c7cee313d044fca3f48fa782cb750c79e4ca76ba7bc7718cd4024cdf6f68" checksum = "4bb4f9a464286d42851d18a605f7193b8febaf5b0919d71c6399b7b26e5b0aad"
dependencies = [ dependencies = [
"async-broadcast", "async-broadcast",
"async-recursion", "async-recursion",
@ -4455,9 +4463,9 @@ dependencies = [
[[package]] [[package]]
name = "zbus_macros" name = "zbus_macros"
version = "5.7.1" version = "5.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a17e7e5eec1550f747e71a058df81a9a83813ba0f6a95f39c4e218bdc7ba366a" checksum = "ef9859f68ee0c4ee2e8cde84737c78e3f4c54f946f2a38645d0d4c7a95327659"
dependencies = [ dependencies = [
"proc-macro-crate 3.2.0", "proc-macro-crate 3.2.0",
"proc-macro2", "proc-macro2",

View file

@ -115,7 +115,7 @@ schema = ["dep:schemars"]
gtk = "0.18.2" gtk = "0.18.2"
gtk-layer-shell = "0.8.2" gtk-layer-shell = "0.8.2"
glib = "0.18.5" glib = "0.18.5"
tokio = { version = "1.46.1", features = [ tokio = { version = "1.47.1", features = [
"macros", "macros",
"rt-multi-thread", "rt-multi-thread",
"time", "time",
@ -132,13 +132,13 @@ tracing-appender = "0.2.3"
strip-ansi-escapes = "0.2.0" strip-ansi-escapes = "0.2.0"
color-eyre = "0.6.5" color-eyre = "0.6.5"
serde = { version = "1.0.219", features = ["derive"] } serde = { version = "1.0.219", features = ["derive"] }
indexmap = "2.10.0" indexmap = { version = "2.10.0", features = ["serde"] }
dirs = "6.0.0" dirs = "6.0.0"
walkdir = "2.5.0" walkdir = "2.5.0"
notify = { version = "8.1.0", default-features = false } notify = { version = "8.2.0", default-features = false }
wayland-client = "0.31.1" wayland-client = "0.31.1"
wayland-protocols-wlr = { version = "0.3.8", features = ["client"] } wayland-protocols-wlr = { version = "0.3.9", features = ["client"] }
smithay-client-toolkit = { version = "0.18.1", default-features = false, features = [ smithay-client-toolkit = { version = "0.19.2", default-features = false, features = [
"calloop", "calloop",
] } ] }
universal-config = { version = "0.5.1", default-features = false } universal-config = { version = "0.5.1", default-features = false }
@ -146,14 +146,14 @@ ctrlc = "3.4.7"
cfg-if = "1.0.1" cfg-if = "1.0.1"
# cli # cli
clap = { version = "4.5.40", optional = true, features = ["derive"] } clap = { version = "4.5.42", optional = true, features = ["derive"] }
# http # http
reqwest = { version = "0.12.22", default-features = false, features = ["default-tls", "http2"], optional = true } reqwest = { version = "0.12.22", default-features = false, features = ["default-tls", "http2"], optional = true }
# cairo # cairo
lua-src = { version = "548.1.1", optional = true } lua-src = { version = "548.1.1", optional = true }
mlua = { version = "0.10.5", optional = true, features = ["luajit", "send"] } mlua = { version = "0.11.1", optional = true, features = ["luajit", "send"] }
cairo-rs = { version = "0.18.5", optional = true, features = ["png"] } cairo-rs = { version = "0.18.5", optional = true, features = ["png"] }
# clock # clock
@ -161,7 +161,7 @@ chrono = { version = "0.4.41", optional = true, default-features = false, featur
# keyboard # keyboard
colpetto = { version = "0.6.0", features = ["tokio", "tracing"], optional = true } colpetto = { version = "0.6.0", features = ["tokio", "tracing"], optional = true }
evdev-rs = { version = "0.6.1", optional = true } evdev-rs = { version = "0.6.2", optional = true }
# music # music
mpd-utils = { version = "0.2.1", optional = true } mpd-utils = { version = "0.2.1", optional = true }
@ -174,27 +174,28 @@ regex = { version = "1.11.1", default-features = false, features = [
tokio-stream = { version = "0.1.17", optional = true } tokio-stream = { version = "0.1.17", optional = true }
# sys_info # sys_info
sysinfo = { version = "0.35.2", optional = true } sysinfo = { version = "0.36.1", optional = true }
# tray # tray
system-tray = { version = "0.7.0", features = ["dbusmenu-gtk3"], optional = true } system-tray = { version = "0.8.1", features = ["dbusmenu-gtk3"], optional = true }
# volume # volume
libpulse-binding = { version = "2.30.1", optional = true } libpulse-binding = { version = "2.30.1", optional = true }
# shared # shared
futures-lite = { version = "2.6.0", optional = true } # network_manager, upower, workspaces, keyboard futures-lite = { version = "2.6.0", optional = true } # network_manager, upower, workspaces, keyboard
zbus = { version = "5.7.1", default-features = false, features = ["blocking-api", "tokio"], optional = true } # network_manager, notifications, upower zbus = { version = "5.9.0", default-features = false, features = ["tokio"], optional = true } # network_manager, notifications, upower
swayipc-async = { version = "2.1.0", optional = true } # workspaces, keyboard swayipc-async = { version = "2.1.0", optional = true } # workspaces, keyboard
hyprland = { version = "0.4.0-beta.2", optional = true } # workspaces, keyboard hyprland = { version = "0.4.0-beta.2", optional = true } # workspaces, keyboard
rustix = { version = "1.0.7", default-features = false, features = ["std", "fs", "pipe", "event"], optional = true } # clipboard, input rustix = { version = "1.0.8", default-features = false, features = ["std", "fs", "pipe", "event"], optional = true } # clipboard, input
serde_json = { version = "1.0.140", optional = true } # ipc, niri serde_json = { version = "1.0.142", optional = true } # ipc, niri
# schema # schema
schemars = { version = "0.8.22", optional = true }
schemars = { version = "1.0.4", optional = true, features = ["indexmap2"] }
[build-dependencies] [build-dependencies]
clap = { version = "4.5.40", features = ["derive"] } clap = { version = "4.5.42", features = ["derive"] }
clap_complete = "4.5.54" clap_complete = "4.5.55"
serde = { version = "1.0.219", features = ["derive"] } serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140" serde_json = "1.0.142"

View file

@ -36,12 +36,10 @@ The server listens on a Unix socket.
The path is printed on startup, and can usually be found at `/run/user/$UID/ironbar-ipc.sock`. The path is printed on startup, and can usually be found at `/run/user/$UID/ironbar-ipc.sock`.
Commands and responses are sent as JSON objects. Commands and responses are sent as JSON objects.
The JSON should be minified and must NOT contain any `\n` characters.
Commands will have a `command` key, and a `subcommand` key when part of a sub-command. Commands will have a `command` key, and a `subcommand` key when part of a sub-command.
The message buffer is currently limited to `1024` bytes.
Particularly large messages will be truncated or cause an error.
The full spec can be found below. The full spec can be found below.
## Libraries ## Libraries

View file

@ -25,7 +25,7 @@ Displays the toggle state of the capslock, num lock and scroll lock keys, and th
| `icons.num_off` | `string` or [image](images) | `''` | Icon to show for disabled num lock indicator. | | `icons.num_off` | `string` or [image](images) | `''` | Icon to show for disabled num lock indicator. |
| `icons.scroll_on` | `string` or [image](images) | `` | Icon to show for enabled scroll lock indicator. | | `icons.scroll_on` | `string` or [image](images) | `` | Icon to show for enabled scroll lock indicator. |
| `icons.scroll_off` | `string` or [image](images) | `''` | Icon to show for disabled scroll lock indicator. | | `icons.scroll_off` | `string` or [image](images) | `''` | Icon to show for disabled scroll lock indicator. |
| `icons.layout_map` | `Map<string, string or image>` | `{}` | Map of icons or labels to show for a particular keyboard layout. Layouts use their actual name if not present in the map. | | `icons.layout_map` | `Map<string, string or image>` | `{}` | Map of icons or labels to show for a particular keyboard layout. Layouts use their actual name if not present in the map. Layouts are matched in the order they appear in the map. If a pattern to match ends with a `*`, it acts as a wildcard, matching any layout name that begins with the part before the `*`. |
| `seat` | `string` | `seat0` | ID of the Wayland seat to attach to. | | `seat` | `string` | `seat0` | ID of the Wayland seat to attach to. |
<details> <details>

View file

@ -194,12 +194,12 @@ The list of available functions is shown below:
It is also possible to get only a single value from the set by specifying a name instead of a function. It is also possible to get only a single value from the set by specifying a name instead of a function.
| Token category | Valid name | | Token category | Valid name |
|----------------|-------------------------------------------------------------------------| |----------------|------------------------------------------|
| CPU | A CPU thread, eg `cpu0`, `cpu1`, ... | | CPU | A CPU thread, eg `cpu0`, `cpu1`, ... |
| Temperature | A sensor name, eg `CPUTIN`. These line up with the output of `sensors`. | | Temperature | A sensor name, eg `CPUTIN`. |
| Disk | A disk mountpoint, eg `/`, `/home`, ... | | Disk | A disk mountpoint, eg `/`, `/home`, ... |
| Network | An adapter name, eg `eth0` or `enp30s0`. | | Network | An adapter name, eg `eth0` or `enp30s0`. |
To specify a name or function, use a `@`. For example, to show disk percent for `/home`: To specify a name or function, use a `@`. For example, to show disk percent for `/home`:
@ -214,6 +214,22 @@ To show total CPU utilization where each core represents 100% (like `htop` etc):
"{cpu_percent@sum}%" "{cpu_percent@sum}%"
``` ```
> [!TIP]
> Available values can be queried over IPC using the CLI.
> This can be particularly useful for sensors, which tend not to have obvious names.
>
> ```shell
> ironbar var list sysinfo.temp_c
> ```
>
> Some usual cases to look out for:
>
> - `k10temp` is an AMD CPU internal sensor
> - Motherboard chipsets tend to prefix their sensors accordingly. For example, `CPUTIN`, `nct6687 CPU`, `asusec AMD`.
> - `amdgpu` is as it suggests.
>
> Sensor names are pulled from `hwmon` and should vaguely line up with the output of `sensors`
#### Prefixes and units #### Prefixes and units
For tokens which return an appropriate unit, you can specify the SI prefix (or unit in some special cases). For tokens which return an appropriate unit, you can specify the SI prefix (or unit in some special cases).

58
flake.lock generated
View file

@ -1,5 +1,27 @@
{ {
"nodes": { "nodes": {
"fenix": {
"inputs": {
"nixpkgs": [
"naersk",
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1752475459,
"narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=",
"owner": "nix-community",
"repo": "fenix",
"rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
"flake-compat": { "flake-compat": {
"locked": { "locked": {
"lastModified": 1747046372, "lastModified": 1747046372,
@ -17,14 +39,15 @@
}, },
"naersk": { "naersk": {
"inputs": { "inputs": {
"fenix": "fenix",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1745925850, "lastModified": 1752689277,
"narHash": "sha256-cyAAMal0aPrlb1NgzMxZqeN1mAJ2pJseDhm2m6Um8T0=", "narHash": "sha256-uldUBFkZe/E7qbvxa3mH1ItrWZyT6w1dBKJQF/3ZSsc=",
"owner": "nix-community", "owner": "nix-community",
"repo": "naersk", "repo": "naersk",
"rev": "38bc60bbc157ae266d4a0c96671c6c742ee17a5f", "rev": "0e72363d0938b0208d6c646d10649164c43f4d64",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -50,11 +73,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1751251929, "lastModified": 1752077645,
"narHash": "sha256-IJWIzZSkBsDzS7iS/iwSwur+xFkWqeLYC4kdf8ObtOM=", "narHash": "sha256-HM791ZQtXV93xtCY+ZxG1REzhQenSQO020cu6rHtAPk=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "b95255df2360a45ddbb03817a68869d5cb01bf96", "rev": "be9e214982e20b8310878ac2baa063a961c1bdf6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -66,11 +89,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1751011381, "lastModified": 1753694789,
"narHash": "sha256-krGXKxvkBhnrSC/kGBmg5MyupUUT5R6IBCLEzx9jhMM=", "narHash": "sha256-cKgvtz6fKuK1Xr5LQW/zOUiAC0oSQoA9nOISB0pJZqM=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "30e2e2857ba47844aa71991daa6ed1fc678bcbb7", "rev": "dc9637876d0dcc8c9e5e22986b857632effeb727",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -87,6 +110,23 @@
"nix-systems": "nix-systems", "nix-systems": "nix-systems",
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_2"
} }
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1752428706,
"narHash": "sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu+QEnJn2Sfg=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "591e3b7624be97e4443ea7b5542c191311aa141d",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View file

@ -44,7 +44,7 @@ impl Client {
spawn(watch_device(added_device.to_owned(), tx.clone())); spawn(watch_device(added_device.to_owned(), tx.clone()));
} }
let removed_devices = devices.difference(&new_devices); let _removed_devices = devices.difference(&new_devices);
// TODO: Cook up some way to notify closures for removed devices to exit // TODO: Cook up some way to notify closures for removed devices to exit
devices = new_devices; devices = new_devices;

View file

@ -1,165 +0,0 @@
use crate::clients::networkmanager::dbus::{
ActiveConnectionDbusProxy, DeviceDbusProxy, DeviceState, DeviceType,
};
use color_eyre::Result;
use std::collections::HashMap;
use zbus::zvariant::ObjectPath;
type PathMap<'l, ValueType> = HashMap<ObjectPath<'l>, ValueType>;
#[derive(Clone, Debug)]
pub struct State {
pub wired: WiredState,
pub wifi: WifiState,
pub cellular: CellularState,
pub vpn: VpnState,
}
#[derive(Clone, Debug)]
pub enum WiredState {
Connected,
Disconnected,
NotPresent,
Unknown,
}
#[derive(Clone, Debug)]
pub enum WifiState {
Connected(WifiConnectedState),
Disconnected,
Disabled,
NotPresent,
Unknown,
}
#[derive(Clone, Debug)]
pub struct WifiConnectedState {
pub ssid: String,
}
#[derive(Clone, Debug)]
pub enum CellularState {
Connected,
Disconnected,
Disabled,
NotPresent,
Unknown,
}
#[derive(Clone, Debug)]
pub enum VpnState {
Connected(VpnConnectedState),
Disconnected,
Unknown,
}
#[derive(Clone, Debug)]
pub struct VpnConnectedState {
pub name: String,
}
pub(super) async fn determine_wired_state(
devices: &PathMap<'_, DeviceDbusProxy<'_>>,
) -> Result<WiredState> {
let mut present = false;
let mut connected = false;
for device in devices.values() {
if device.device_type().await? == DeviceType::Ethernet {
present = true;
if device.state().await?.is_enabled() {
connected = true;
break;
}
}
}
if connected {
Ok(WiredState::Connected)
} else if present {
Ok(WiredState::Disconnected)
} else {
Ok(WiredState::NotPresent)
}
}
pub(super) async fn determine_wifi_state(
devices: &PathMap<'_, DeviceDbusProxy<'_>>,
) -> Result<WifiState> {
let mut present = false;
let mut enabled = false;
let mut connected = false;
for device in devices.values() {
if device.device_type().await? == DeviceType::Wifi {
present = true;
if device.state().await?.is_enabled() {
enabled = true;
if device.state().await? == DeviceState::Activated {
connected = true;
break;
}
}
}
}
if connected {
Ok(WifiState::Connected(WifiConnectedState {
// TODO: Implement obtaining SSID
ssid: "unknown".into(),
}))
} else if enabled {
Ok(WifiState::Disconnected)
} else if present {
Ok(WifiState::Disabled)
} else {
Ok(WifiState::NotPresent)
}
}
pub(super) async fn determine_cellular_state(
devices: &PathMap<'_, DeviceDbusProxy<'_>>,
) -> Result<CellularState> {
let mut present = false;
let mut enabled = false;
let mut connected = false;
for device in devices.values() {
if device.device_type().await? == DeviceType::Modem {
present = true;
if device.state().await?.is_enabled() {
enabled = true;
if device.state().await? == DeviceState::Activated {
connected = true;
break;
}
}
}
}
if connected {
Ok(CellularState::Connected)
} else if enabled {
Ok(CellularState::Disconnected)
} else if present {
Ok(CellularState::Disabled)
} else {
Ok(CellularState::NotPresent)
}
}
pub(super) async fn determine_vpn_state(
active_connections: &PathMap<'_, ActiveConnectionDbusProxy<'_>>,
) -> Result<VpnState> {
for connection in active_connections.values() {
match connection.type_().await?.as_str() {
"vpn" | "wireguard" => {
return Ok(VpnState::Connected(VpnConnectedState {
name: "unknown".into(),
}));
}
_ => {}
}
}
Ok(VpnState::Disconnected)
}

View file

@ -3,7 +3,7 @@ mod sink_input;
use crate::{APP_ID, arc_mut, lock, register_client, spawn_blocking}; use crate::{APP_ID, arc_mut, lock, register_client, spawn_blocking};
use libpulse_binding::callbacks::ListResult; use libpulse_binding::callbacks::ListResult;
use libpulse_binding::context::introspect::{Introspector, ServerInfo}; use libpulse_binding::context::introspect::ServerInfo;
use libpulse_binding::context::subscribe::{Facility, InterestMaskSet, Operation}; use libpulse_binding::context::subscribe::{Facility, InterestMaskSet, Operation};
use libpulse_binding::context::{Context, FlagSet, State}; use libpulse_binding::context::{Context, FlagSet, State};
use libpulse_binding::mainloop::standard::{IterateResult, Mainloop}; use libpulse_binding::mainloop::standard::{IterateResult, Mainloop};
@ -24,11 +24,11 @@ type ArcMutVec<T> = Arc<Mutex<Vec<T>>>;
pub enum Event { pub enum Event {
AddSink(Sink), AddSink(Sink),
UpdateSink(Sink), UpdateSink(Sink),
RemoveSink(String), RemoveSink,
AddInput(SinkInput), AddInput,
UpdateInput(SinkInput), UpdateInput,
RemoveInput(u32), RemoveInput,
} }
#[derive(Debug)] #[derive(Debug)]
@ -51,10 +51,7 @@ struct Data {
pub enum ConnectionState { pub enum ConnectionState {
Disconnected, Disconnected,
Connected { Connected,
context: Arc<Mutex<Context>>,
introspector: Introspector,
},
} }
impl Debug for ConnectionState { impl Debug for ConnectionState {
@ -64,7 +61,7 @@ impl Debug for ConnectionState {
"{}", "{}",
match self { match self {
Self::Disconnected => "Disconnected", Self::Disconnected => "Disconnected",
Self::Connected { .. } => "Connected", Self::Connected => "Connected",
} }
) )
} }
@ -120,14 +117,9 @@ impl Client {
error!("{err:?}"); error!("{err:?}");
} }
let introspector = lock!(context).introspect();
{ {
let mut inner = lock!(self.connection); let mut inner = lock!(self.connection);
*inner = ConnectionState::Connected { *inner = ConnectionState::Connected;
context,
introspector,
};
} }
loop { loop {
@ -291,22 +283,4 @@ fn volume_to_percent(volume: ChannelVolumes) -> f64 {
((avg - Volume::MUTED.0) as f64 / base_delta).round() ((avg - Volume::MUTED.0) as f64 / base_delta).round()
} }
/// Converts a percentage volume into a Pulse volume value,
/// which can be used for setting channel volumes.
pub fn percent_to_volume(target_percent: f64) -> u32 {
let base_delta = (Volume::NORMAL.0 as f32 - Volume::MUTED.0 as f32) / 100.0;
if target_percent < 0.0 {
Volume::MUTED.0
} else if target_percent == 100.0 {
Volume::NORMAL.0
} else if target_percent >= 150.0 {
(Volume::NORMAL.0 as f32 * 1.5) as u32
} else if target_percent < 100.0 {
Volume::MUTED.0 + target_percent as u32 * base_delta as u32
} else {
Volume::NORMAL.0 + (target_percent - 100.0) as u32 * base_delta as u32
}
}
register_client!(Client, volume); register_client!(Client, volume);

View file

@ -1,4 +1,4 @@
use super::{ArcMutVec, Client, ConnectionState, Event, percent_to_volume, volume_to_percent}; use super::{ArcMutVec, Client, Event, volume_to_percent};
use crate::channels::SyncSenderExt; use crate::channels::SyncSenderExt;
use crate::lock; use crate::lock;
use libpulse_binding::callbacks::ListResult; use libpulse_binding::callbacks::ListResult;
@ -6,7 +6,7 @@ use libpulse_binding::context::Context;
use libpulse_binding::context::introspect::SinkInfo; use libpulse_binding::context::introspect::SinkInfo;
use libpulse_binding::context::subscribe::Operation; use libpulse_binding::context::subscribe::Operation;
use libpulse_binding::def::SinkState; use libpulse_binding::def::SinkState;
use std::sync::{Arc, Mutex, mpsc}; use std::sync::{Arc, Mutex};
use tokio::sync::broadcast; use tokio::sync::broadcast;
use tracing::{debug, error, instrument, trace}; use tracing::{debug, error, instrument, trace};
@ -14,7 +14,6 @@ use tracing::{debug, error, instrument, trace};
pub struct Sink { pub struct Sink {
index: u32, index: u32,
pub name: String, pub name: String,
pub description: String,
pub volume: f64, pub volume: f64,
pub muted: bool, pub muted: bool,
pub active: bool, pub active: bool,
@ -29,11 +28,6 @@ impl From<&SinkInfo<'_>> for Sink {
.as_ref() .as_ref()
.map(ToString::to_string) .map(ToString::to_string)
.unwrap_or_default(), .unwrap_or_default(),
description: value
.description
.as_ref()
.map(ToString::to_string)
.unwrap_or_default(),
muted: value.mute, muted: value.mute,
volume: volume_to_percent(value.volume), volume: volume_to_percent(value.volume),
active: value.state == SinkState::Running, active: value.state == SinkState::Running,
@ -46,43 +40,6 @@ impl Client {
pub fn sinks(&self) -> Arc<Mutex<Vec<Sink>>> { pub fn sinks(&self) -> Arc<Mutex<Vec<Sink>>> {
self.data.sinks.clone() self.data.sinks.clone()
} }
#[instrument(level = "trace")]
pub fn set_default_sink(&self, name: &str) {
if let ConnectionState::Connected { context, .. } = &*lock!(self.connection) {
lock!(context).set_default_sink(name, |_| {});
}
}
#[instrument(level = "trace")]
pub fn set_sink_volume(&self, name: &str, volume_percent: f64) {
if let ConnectionState::Connected { introspector, .. } = &mut *lock!(self.connection) {
let (tx, rx) = mpsc::channel();
introspector.get_sink_info_by_name(name, move |info| {
let ListResult::Item(info) = info else {
return;
};
tx.send_expect(info.volume);
});
let new_volume = percent_to_volume(volume_percent);
let mut volume = rx.recv().expect("to receive info");
for v in volume.get_mut() {
v.0 = new_volume;
}
introspector.set_sink_volume_by_name(name, &volume, None);
}
}
#[instrument(level = "trace")]
pub fn set_sink_muted(&self, name: &str, muted: bool) {
if let ConnectionState::Connected { introspector, .. } = &mut *lock!(self.connection) {
introspector.set_sink_mute_by_name(name, muted, None);
}
}
} }
pub fn on_event( pub fn on_event(
@ -177,10 +134,9 @@ fn update(
fn remove(index: u32, sinks: &ArcMutVec<Sink>, tx: &broadcast::Sender<Event>) { fn remove(index: u32, sinks: &ArcMutVec<Sink>, tx: &broadcast::Sender<Event>) {
trace!("removing {index}"); trace!("removing {index}");
let mut sinks = lock!(sinks); let sinks = lock!(sinks);
if let Some(pos) = sinks.iter().position(|s| s.index == index) { if let Some(_pos) = sinks.iter().position(|s| s.index == index) {
let info = sinks.remove(pos); tx.send_expect(Event::RemoveSink);
tx.send_expect(Event::RemoveSink(info.name));
} }
} }

View file

@ -1,37 +1,22 @@
use super::{ArcMutVec, Client, ConnectionState, Event, percent_to_volume, volume_to_percent}; use super::{ArcMutVec, Client, Event};
use crate::channels::SyncSenderExt; use crate::channels::SyncSenderExt;
use crate::lock; use crate::lock;
use libpulse_binding::callbacks::ListResult; use libpulse_binding::callbacks::ListResult;
use libpulse_binding::context::Context; use libpulse_binding::context::Context;
use libpulse_binding::context::introspect::SinkInputInfo; use libpulse_binding::context::introspect::SinkInputInfo;
use libpulse_binding::context::subscribe::Operation; use libpulse_binding::context::subscribe::Operation;
use std::sync::{Arc, Mutex, mpsc}; use std::sync::{Arc, Mutex};
use tokio::sync::broadcast; use tokio::sync::broadcast;
use tracing::{debug, error, instrument, trace}; use tracing::{debug, error, instrument, trace};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SinkInput { pub struct SinkInput {
pub index: u32, pub index: u32,
pub name: String,
pub volume: f64,
pub muted: bool,
pub can_set_volume: bool,
} }
impl From<&SinkInputInfo<'_>> for SinkInput { impl From<&SinkInputInfo<'_>> for SinkInput {
fn from(value: &SinkInputInfo) -> Self { fn from(value: &SinkInputInfo) -> Self {
Self { Self { index: value.index }
index: value.index,
name: value
.name
.as_ref()
.map(ToString::to_string)
.unwrap_or_default(),
muted: value.mute,
volume: volume_to_percent(value.volume),
can_set_volume: value.has_volume && value.volume_writable,
}
} }
} }
@ -40,36 +25,6 @@ impl Client {
pub fn sink_inputs(&self) -> Arc<Mutex<Vec<SinkInput>>> { pub fn sink_inputs(&self) -> Arc<Mutex<Vec<SinkInput>>> {
self.data.sink_inputs.clone() self.data.sink_inputs.clone()
} }
#[instrument(level = "trace")]
pub fn set_input_volume(&self, index: u32, volume_percent: f64) {
if let ConnectionState::Connected { introspector, .. } = &mut *lock!(self.connection) {
let (tx, rx) = mpsc::channel();
introspector.get_sink_input_info(index, move |info| {
let ListResult::Item(info) = info else {
return;
};
tx.send_expect(info.volume);
});
let new_volume = percent_to_volume(volume_percent);
let mut volume = rx.recv().expect("to receive info");
for v in volume.get_mut() {
v.0 = new_volume;
}
introspector.set_sink_input_volume(index, &volume, None);
}
}
#[instrument(level = "trace")]
pub fn set_input_muted(&self, index: u32, muted: bool) {
if let ConnectionState::Connected { introspector, .. } = &mut *lock!(self.connection) {
introspector.set_sink_input_mute(index, muted, None);
}
}
} }
pub fn on_event( pub fn on_event(
@ -119,7 +74,7 @@ pub fn add(
trace!("adding {info:?}"); trace!("adding {info:?}");
lock!(inputs).push(info.into()); lock!(inputs).push(info.into());
tx.send_expect(Event::AddInput(info.into())); tx.send_expect(Event::AddInput);
} }
fn update( fn update(
@ -143,16 +98,15 @@ fn update(
inputs[pos] = info.into(); inputs[pos] = info.into();
} }
tx.send_expect(Event::UpdateInput(info.into())); tx.send_expect(Event::UpdateInput);
} }
fn remove(index: u32, inputs: &ArcMutVec<SinkInput>, tx: &broadcast::Sender<Event>) { fn remove(index: u32, inputs: &ArcMutVec<SinkInput>, tx: &broadcast::Sender<Event>) {
let mut inputs = lock!(inputs); let inputs = lock!(inputs);
trace!("removing {index}"); trace!("removing {index}");
if let Some(pos) = inputs.iter().position(|s| s.index == index) { if let Some(_pos) = inputs.iter().position(|s| s.index == index) {
let info = inputs.remove(pos); tx.send_expect(Event::RemoveInput);
tx.send_expect(Event::RemoveInput(info.index));
} }
} }

View file

@ -52,16 +52,11 @@ where
} }
#[cfg(feature = "schema")] #[cfg(feature = "schema")]
pub fn schema_layer(generator: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { pub fn schema_layer(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
use schemars::JsonSchema; schemars::json_schema!({
let mut schema: schemars::schema::SchemaObject = <String>::json_schema(generator).into(); "type": "string",
schema.enum_values = Some(vec![ "enum": ["background", "bottom", "top", "overlay"],
"background".into(), })
"bottom".into(),
"top".into(),
"overlay".into(),
]);
schema.into()
} }
impl BarPosition { impl BarPosition {

View file

@ -3,9 +3,10 @@ use color_eyre::{Help, Report, Result};
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{Command, Stdio}; use std::process::Stdio;
use std::sync::Arc; use std::sync::Arc;
use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::process::Command;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tracing::{debug, error}; use tracing::{debug, error};
use walkdir::{DirEntry, WalkDir}; use walkdir::{DirEntry, WalkDir};
@ -238,6 +239,7 @@ impl DesktopFiles {
/// Checks file contents for an exact or partial match of the provided input. /// Checks file contents for an exact or partial match of the provided input.
async fn find_by_file_contents(&self, app_id: &str) -> Result<Option<DesktopFile>> { async fn find_by_file_contents(&self, app_id: &str) -> Result<Option<DesktopFile>> {
let mut files = self.files.lock().await; let mut files = self.files.lock().await;
let app_id_lower = app_id.to_lowercase();
// first pass - check name for exact match // first pass - check name for exact match
for (_, file_ref) in files.iter_mut() { for (_, file_ref) in files.iter_mut() {
@ -253,7 +255,7 @@ impl DesktopFiles {
for (_, file_ref) in files.iter_mut() { for (_, file_ref) in files.iter_mut() {
let file = file_ref.get().await?; let file = file_ref.get().await?;
if let Some(name) = &file.name { if let Some(name) = &file.name {
if name.to_lowercase().contains(app_id) { if name.to_lowercase().contains(&app_id_lower) {
return Ok(Some(file)); return Ok(Some(file));
} }
} }
@ -264,19 +266,19 @@ impl DesktopFiles {
let file = file_ref.get().await?; let file = file_ref.get().await?;
if let Some(name) = &file.exec { if let Some(name) = &file.exec {
if name.to_lowercase().contains(app_id) { if name.to_lowercase().contains(&app_id_lower) {
return Ok(Some(file)); return Ok(Some(file));
} }
} }
if let Some(name) = &file.startup_wm_class { if let Some(name) = &file.startup_wm_class {
if name.to_lowercase().contains(app_id) { if name.to_lowercase().contains(&app_id_lower) {
return Ok(Some(file)); return Ok(Some(file));
} }
} }
if let Some(name) = &file.icon { if let Some(name) = &file.icon {
if name.to_lowercase().contains(app_id) { if name.to_lowercase().contains(&app_id_lower) {
return Ok(Some(file)); return Ok(Some(file));
} }
} }
@ -325,21 +327,37 @@ fn files(dir: &Path) -> Vec<PathBuf> {
} }
/// Starts a `.desktop` file with the provided formatted command. /// Starts a `.desktop` file with the provided formatted command.
pub fn open_program(file_name: &str, str: &str) { pub async fn open_program(file_name: &str, launch_command: &str) {
let expanded = str.replace("{app_name}", file_name); let expanded = launch_command.replace("{app_name}", file_name);
let launch_command_parts: Vec<&str> = expanded.split_whitespace().collect(); let launch_command_parts: Vec<&str> = expanded.split_whitespace().collect();
if let Err(err) = Command::new(&launch_command_parts[0])
debug!("running {launch_command_parts:?}");
let exit_status = match Command::new(launch_command_parts[0])
.args(&launch_command_parts[1..]) .args(&launch_command_parts[1..])
.stdin(Stdio::null())
.stdout(Stdio::null()) .stdout(Stdio::null())
.stderr(Stdio::null()) .stderr(Stdio::null())
.kill_on_drop(true)
.spawn() .spawn()
{ {
error!( Ok(mut child) => Some(child.wait().await),
"{:?}", Err(err) => {
Report::new(err) error!(
.wrap_err("Failed to run launch command.") "{:?}",
.suggestion("Perhaps the applications file is invalid?") Report::new(err)
); .wrap_err("Failed to run launch command.")
.suggestion("Perhaps the desktop file is invalid or orphaned?")
);
None
}
};
match exit_status {
Some(Ok(exit_status)) if !exit_status.success() => {
error!("received non-success exit status running {launch_command_parts:?}")
}
Some(Err(err)) => error!("{err:?}"),
_ => {}
} }
} }

View file

@ -2,7 +2,7 @@ use super::Ipc;
use crate::ipc::{Command, Response}; use crate::ipc::{Command, Response};
use color_eyre::Result; use color_eyre::Result;
use color_eyre::{Help, Report}; use color_eyre::{Help, Report};
use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::UnixStream; use tokio::net::UnixStream;
impl Ipc { impl Ipc {
@ -16,18 +16,20 @@ impl Ipc {
.suggestion("Is Ironbar running?")), .suggestion("Is Ironbar running?")),
}?; }?;
let write_buffer = serde_json::to_vec(&command)?; let mut write_buffer = serde_json::to_vec(&command)?;
if debug { if debug {
eprintln!("REQUEST JSON: {}", serde_json::to_string(&command)?); eprintln!("REQUEST JSON: {}", serde_json::to_string(&command)?);
} }
write_buffer.push(b'\n');
stream.write_all(&write_buffer).await?; stream.write_all(&write_buffer).await?;
let mut read_buffer = vec![0; 1024]; let mut read_buffer = String::new();
let bytes = stream.read(&mut read_buffer).await?; let mut reader = BufReader::new(stream);
let bytes = reader.read_line(&mut read_buffer).await?;
let response = serde_json::from_slice(&read_buffer[..bytes])?; let response = serde_json::from_str(&read_buffer[..bytes])?;
Ok(response) Ok(response)
} }
} }

View file

@ -8,10 +8,10 @@ use std::rc::Rc;
use color_eyre::{Report, Result}; use color_eyre::{Report, Result};
use gtk::Application; use gtk::Application;
use gtk::prelude::*; use gtk::prelude::*;
use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::{UnixListener, UnixStream}; use tokio::net::{UnixListener, UnixStream};
use tokio::sync::mpsc::{self, Receiver, Sender}; use tokio::sync::mpsc::{self, Receiver, Sender};
use tracing::{debug, error, info, warn}; use tracing::{debug, error, info, trace, warn};
use super::Ipc; use super::Ipc;
use crate::channels::{AsyncSenderExt, MpscReceiverExt}; use crate::channels::{AsyncSenderExt, MpscReceiverExt};
@ -52,11 +52,13 @@ impl Ipc {
loop { loop {
match listener.accept().await { match listener.accept().await {
Ok((stream, _addr)) => { Ok((stream, _addr)) => {
debug!("handling incoming connection");
if let Err(err) = if let Err(err) =
Self::handle_connection(stream, &cmd_tx, &mut res_rx).await Self::handle_connection(stream, &cmd_tx, &mut res_rx).await
{ {
error!("{err:?}"); error!("{err:?}");
} }
debug!("done");
} }
Err(err) => { Err(err) => {
error!("{err:?}"); error!("{err:?}");
@ -80,10 +82,16 @@ impl Ipc {
cmd_tx: &Sender<Command>, cmd_tx: &Sender<Command>,
res_rx: &mut Receiver<Response>, res_rx: &mut Receiver<Response>,
) -> Result<()> { ) -> Result<()> {
let (mut stream_read, mut stream_write) = stream.split(); trace!("awaiting readable state");
stream.readable().await?;
let mut read_buffer = vec![0; 1024]; let mut read_buffer = Vec::with_capacity(1024);
let bytes = stream_read.read(&mut read_buffer).await?;
let mut reader = BufReader::new(&mut stream);
trace!("reading bytes");
let bytes = reader.read_until(b'\n', &mut read_buffer).await?;
debug!("read {} bytes", bytes);
// FIXME: Error on invalid command // FIXME: Error on invalid command
let command = serde_json::from_slice::<Command>(&read_buffer[..bytes])?; let command = serde_json::from_slice::<Command>(&read_buffer[..bytes])?;
@ -95,10 +103,18 @@ impl Ipc {
.recv() .recv()
.await .await
.unwrap_or(Response::Err { message: None }); .unwrap_or(Response::Err { message: None });
let res = serde_json::to_vec(&res)?;
stream_write.write_all(&res).await?; let mut res = serde_json::to_vec(&res)?;
stream_write.shutdown().await?; res.push(b'\n');
trace!("awaiting writable state");
stream.writable().await?;
debug!("writing {} bytes", res.len());
stream.write_all(&res).await?;
trace!("bytes written, shutting down stream");
stream.shutdown().await?;
Ok(()) Ok(())
} }

View file

@ -1,8 +1,7 @@
use std::collections::HashMap;
use color_eyre::Result; use color_eyre::Result;
use color_eyre::eyre::Report; use color_eyre::eyre::Report;
use gtk::prelude::*; use gtk::prelude::*;
use indexmap::IndexMap;
use serde::Deserialize; use serde::Deserialize;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tracing::{debug, trace}; use tracing::{debug, trace};
@ -129,7 +128,7 @@ struct Icons {
/// } /// }
/// ``` /// ```
#[serde(default)] #[serde(default)]
layout_map: HashMap<String, String>, layout_map: IndexMap<String, String>,
} }
impl Default for Icons { impl Default for Icons {
@ -141,7 +140,7 @@ impl Default for Icons {
num_off: String::new(), num_off: String::new(),
scroll_on: default_icon_scroll(), scroll_on: default_icon_scroll(),
scroll_off: String::new(), scroll_off: String::new(),
layout_map: HashMap::new(), layout_map: IndexMap::new(),
} }
} }
} }
@ -338,7 +337,19 @@ impl Module<gtk::Box> for KeyboardModule {
} }
} }
KeyboardUpdate::Layout(KeyboardLayoutUpdate(language)) => { KeyboardUpdate::Layout(KeyboardLayoutUpdate(language)) => {
let text = icons.layout_map.get(&language).unwrap_or(&language); let text = icons
.layout_map
.iter()
.find_map(|(pattern, display_text)| {
let is_match = if pattern.ends_with("*") {
language.starts_with(&pattern[..pattern.len() - 1])
} else {
pattern == &language
};
is_match.then(|| display_text)
})
.unwrap_or(&language);
layout_button.set_label(text); layout_button.set_label(text);
} }
}); });

View file

@ -244,21 +244,43 @@ impl Module<gtk::Box> for LauncherModule {
let tx2 = context.tx.clone(); let tx2 = context.tx.clone();
let wl = context.client::<wayland::Client>(); let wl = context.client::<wayland::Client>();
let desktop_files = context.ironbar.desktop_files();
spawn(async move { spawn(async move {
let items = items2; let items = items2;
let tx = tx2; let tx = tx2;
// Build app_id mapping once at startup
let mut app_id_map = IndexMap::<String, String>::new();
{
let favorites: Vec<_> = lock!(items).keys().cloned().collect();
for fav in favorites {
if let Ok(Some(file)) = desktop_files.find(&fav).await {
if let Some(wm_class) = file.startup_wm_class {
app_id_map.insert(wm_class, fav);
}
}
}
}
let resolve_app_id = |app_id: &str| {
app_id_map
.get(app_id)
.cloned()
.unwrap_or_else(|| app_id.to_string())
};
let mut wlrx = wl.subscribe_toplevels(); let mut wlrx = wl.subscribe_toplevels();
let handles = wl.toplevel_info_all(); let handles = wl.toplevel_info_all();
for info in handles { for info in handles {
let mut items = lock!(items); let mut items = lock!(items);
let item = items.get_mut(&info.app_id); let app_id = resolve_app_id(&info.app_id);
if let Some(item) = item { if let Some(item) = items.get_mut(&app_id) {
item.merge_toplevel(info.clone()); item.merge_toplevel(info.clone());
} else { } else {
let item = Item::from(info.clone()); let mut item = Item::from(info.clone());
items.insert(info.app_id.clone(), item); item.app_id = app_id.clone();
items.insert(app_id, item);
} }
} }
@ -284,14 +306,14 @@ impl Module<gtk::Box> for LauncherModule {
match event { match event {
ToplevelEvent::New(info) => { ToplevelEvent::New(info) => {
let app_id = info.app_id.clone(); let app_id = resolve_app_id(&info.app_id);
let new_item = { let new_item = {
let mut items = lock!(items); let mut items = lock!(items);
let item = items.get_mut(&info.app_id); match items.get_mut(&app_id) {
match item {
None => { None => {
let item: Item = info.into(); let mut item: Item = info.into();
item.app_id = app_id.clone();
items.insert(app_id.clone(), item.clone()); items.insert(app_id.clone(), item.clone());
ItemOrWindow::Item(item) ItemOrWindow::Item(item)
@ -313,9 +335,10 @@ impl Module<gtk::Box> for LauncherModule {
}?; }?;
} }
ToplevelEvent::Update(info) => { ToplevelEvent::Update(info) => {
let app_id = resolve_app_id(&info.app_id);
// check if open, as updates can be sent as program closes // check if open, as updates can be sent as program closes
// if it's a focused favourite closing, it otherwise incorrectly re-focuses. // 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) { let is_open = if let Some(item) = lock!(items).get_mut(&app_id) {
item.set_window_focused(info.id, info.focused); item.set_window_focused(info.id, info.focused);
item.set_window_name(info.id, info.title.clone()); item.set_window_name(info.id, info.title.clone());
@ -325,27 +348,27 @@ impl Module<gtk::Box> for LauncherModule {
}; };
send_update(LauncherUpdate::Focus( send_update(LauncherUpdate::Focus(
info.app_id.clone(), app_id.clone(),
is_open && info.focused, is_open && info.focused,
)) ))
.await?; .await?;
send_update(LauncherUpdate::Title( send_update(LauncherUpdate::Title(
info.app_id.clone(), app_id.clone(),
info.id, info.id,
info.title.clone(), info.title.clone(),
)) ))
.await?; .await?;
} }
ToplevelEvent::Remove(info) => { ToplevelEvent::Remove(info) => {
let app_id = resolve_app_id(&info.app_id);
let remove_item = { let remove_item = {
let mut items = lock!(items); let mut items = lock!(items);
let item = items.get_mut(&info.app_id); match items.get_mut(&app_id) {
match item {
Some(item) => { Some(item) => {
item.unmerge_toplevel(&info); item.unmerge_toplevel(&info);
if item.windows.is_empty() { if item.windows.is_empty() {
items.shift_remove(&info.app_id); items.shift_remove(&app_id);
Some(ItemOrWindowId::Item) Some(ItemOrWindowId::Item)
} else { } else {
Some(ItemOrWindowId::Window) Some(ItemOrWindowId::Window)
@ -357,15 +380,11 @@ impl Module<gtk::Box> for LauncherModule {
match remove_item { match remove_item {
Some(ItemOrWindowId::Item) => { Some(ItemOrWindowId::Item) => {
send_update(LauncherUpdate::RemoveItem(info.app_id.clone())) send_update(LauncherUpdate::RemoveItem(app_id.clone())).await?;
.await?;
} }
Some(ItemOrWindowId::Window) => { Some(ItemOrWindowId::Window) => {
send_update(LauncherUpdate::RemoveWindow( send_update(LauncherUpdate::RemoveWindow(app_id.clone(), info.id))
info.app_id.clone(), .await?;
info.id,
))
.await?;
} }
None => {} None => {}
} }
@ -388,7 +407,7 @@ impl Module<gtk::Box> for LauncherModule {
if let ItemEvent::OpenItem(app_id) = event { if let ItemEvent::OpenItem(app_id) = event {
match desktop_files.find(&app_id).await { match desktop_files.find(&app_id).await {
Ok(Some(file)) => { Ok(Some(file)) => {
open_program(&file.file_name, &launch_command_str); open_program(&file.file_name, &launch_command_str).await;
} }
Ok(None) => warn!("Could not find applications file for {}", app_id), Ok(None) => warn!("Could not find applications file for {}", app_id),
Err(err) => error!("Failed to find parse file for {}: {}", app_id, err), Err(err) => error!("Failed to find parse file for {}: {}", app_id, err),

View file

@ -100,7 +100,11 @@ where
let tx = tx.clone(); let tx = tx.clone();
button.connect_clicked(move |_button| { button.connect_clicked(move |_button| {
open_program(&file_name, &command); // TODO: this needs refactoring to call open from the controller
let file_name = file_name.clone();
let command = command.clone();
spawn(async move { open_program(&file_name, &command).await });
sub_menu.hide(); sub_menu.hide();
tx.send_spawn(ModuleUpdateEvent::ClosePopup); tx.send_spawn(ModuleUpdateEvent::ClosePopup);

View file

@ -122,38 +122,34 @@ async fn handle_update_events(
fn get_icon_for_device_state(r#type: &DeviceType, state: &DeviceState) -> Option<&'static str> { fn get_icon_for_device_state(r#type: &DeviceType, state: &DeviceState) -> Option<&'static str> {
match r#type { match r#type {
DeviceType::Ethernet => match state { DeviceType::Ethernet => match state {
DeviceState::Unavailable => Some("icon:network-wired-disconnected-symbolic"), DeviceState::Unavailable
DeviceState::Disconnected => Some("icon:network-wired-disconnected-symbolic"), | DeviceState::Disconnected
DeviceState::Prepare => Some("icon:network-wired-disconnected-symbolic"), | DeviceState::Prepare
DeviceState::Config => Some("icon:network-wired-disconnected-symbolic"), | DeviceState::Config
DeviceState::NeedAuth => Some("icon:network-wired-disconnected-symbolic"), | DeviceState::NeedAuth
DeviceState::IpConfig => Some("icon:network-wired-disconnected-symbolic"), | DeviceState::IpConfig
DeviceState::IpCheck => Some("icon:network-wired-disconnected-symbolic"), | DeviceState::IpCheck
DeviceState::Secondaries => Some("icon:network-wired-disconnected-symbolic"), | DeviceState::Secondaries
| DeviceState::Deactivating
| DeviceState::Failed => Some("icon:network-wired-disconnected-symbolic"),
DeviceState::Activated => Some("icon:network-wired-symbolic"), DeviceState::Activated => Some("icon:network-wired-symbolic"),
DeviceState::Deactivating => Some("icon:network-wired-disconnected-symbolic"),
DeviceState::Failed => Some("icon:network-wired-disconnected-symbolic"),
_ => None, _ => None,
}, },
DeviceType::Wifi => match state { DeviceType::Wifi => match state {
DeviceState::Unavailable => Some("icon:network-wireless-hardware-disabled-symbolic"), DeviceState::Unavailable => Some("icon:network-wireless-hardware-disabled-symbolic"),
DeviceState::Disconnected => Some("icon:network-wireless-offline-symbolic"), DeviceState::Disconnected
DeviceState::Prepare => Some("icon:network-wireless-offline-symbolic"), | DeviceState::Prepare
DeviceState::Config => Some("icon:network-wireless-offline-symbolic"), | DeviceState::Config
DeviceState::NeedAuth => Some("icon:network-wireless-offline-symbolic"), | DeviceState::NeedAuth
DeviceState::IpConfig => Some("icon:network-wireless-offline-symbolic"), | DeviceState::IpConfig
DeviceState::IpCheck => Some("icon:network-wireless-offline-symbolic"), | DeviceState::IpCheck
DeviceState::Secondaries => Some("icon:network-wireless-offline-symbolic"), | DeviceState::Secondaries
| DeviceState::Deactivating
| DeviceState::Failed => Some("icon:network-wireless-offline-symbolic"),
DeviceState::Activated => Some("icon:network-wireless-connected-symbolic"), DeviceState::Activated => Some("icon:network-wireless-connected-symbolic"),
DeviceState::Deactivating => Some("icon:network-wireless-offline-symbolic"),
DeviceState::Failed => Some("icon:network-wireless-offline-symbolic"),
_ => None, _ => None,
}, },
DeviceType::Tun => match state { DeviceType::Tun | DeviceType::Wireguard => match state {
DeviceState::Activated => Some("icon:network-vpn-symbolic"),
_ => None,
},
DeviceType::Wireguard => match state {
DeviceState::Activated => Some("icon:network-vpn-symbolic"), DeviceState::Activated => Some("icon:network-vpn-symbolic"),
_ => None, _ => None,
}, },

View file

@ -11,6 +11,7 @@ use std::collections::HashSet;
use std::ffi::CStr; use std::ffi::CStr;
use std::os::raw::{c_char, c_int}; use std::os::raw::{c_char, c_int};
use std::ptr; use std::ptr;
use system_tray::item::IconPixmap;
/// Gets the GTK icon theme search paths by calling the FFI function. /// Gets the GTK icon theme search paths by calling the FFI function.
/// Conveniently returns the result as a `HashSet`. /// Conveniently returns the result as a `HashSet`.
@ -45,10 +46,10 @@ pub fn get_image(
icon_theme: &IconTheme, icon_theme: &IconTheme,
) -> Result<Image> { ) -> Result<Image> {
if !prefer_icons && item.icon_pixmap.is_some() { if !prefer_icons && item.icon_pixmap.is_some() {
get_image_from_pixmap(item, size) get_image_from_pixmap(item.icon_pixmap.as_deref(), size)
} else { } else {
get_image_from_icon_name(item, size, icon_theme) get_image_from_icon_name(item, size, icon_theme)
.or_else(|_| get_image_from_pixmap(item, size)) .or_else(|_| get_image_from_pixmap(item.icon_pixmap.as_deref(), size))
} }
} }
@ -81,12 +82,10 @@ fn get_image_from_icon_name(item: &TrayMenu, size: u32, icon_theme: &IconTheme)
/// which has 8 bits per sample and a bit stride of `4*width`. /// which has 8 bits per sample and a bit stride of `4*width`.
/// The Pixbuf expects RGBA32 format, so some channel shuffling /// The Pixbuf expects RGBA32 format, so some channel shuffling
/// is required. /// is required.
fn get_image_from_pixmap(item: &TrayMenu, size: u32) -> Result<Image> { fn get_image_from_pixmap(item: Option<&[IconPixmap]>, size: u32) -> Result<Image> {
const BITS_PER_SAMPLE: i32 = 8; const BITS_PER_SAMPLE: i32 = 8;
let pixmap = item let pixmap = item
.icon_pixmap
.as_ref()
.and_then(|pixmap| pixmap.first()) .and_then(|pixmap| pixmap.first())
.ok_or_else(|| Report::msg("Failed to get pixmap from tray icon"))?; .ok_or_else(|| Report::msg("Failed to get pixmap from tray icon"))?;

View file

@ -181,9 +181,14 @@ fn on_update(
UpdateEvent::AttentionIcon(_icon) => { UpdateEvent::AttentionIcon(_icon) => {
warn!("received unimplemented NewAttentionIcon event"); warn!("received unimplemented NewAttentionIcon event");
} }
UpdateEvent::Icon(icon) => { UpdateEvent::Icon {
if icon.as_ref() != menu_item.icon_name() { icon_name,
menu_item.set_icon_name(icon); icon_pixmap,
} => {
menu_item.icon_pixmap = icon_pixmap;
if icon_name.as_ref() != menu_item.icon_name() {
menu_item.set_icon_name(icon_name);
match icon::get_image(menu_item, icon_size, prefer_icons, icon_theme) { match icon::get_image(menu_item, icon_size, prefer_icons, icon_theme) {
Ok(image) => menu_item.set_image(&image), Ok(image) => menu_item.set_image(&image),
Err(_) => menu_item.show_label(), Err(_) => menu_item.show_label(),

View file

@ -1,13 +1,13 @@
use crate::channels::{AsyncSenderExt, BroadcastReceiverExt}; use crate::channels::{AsyncSenderExt, BroadcastReceiverExt};
use crate::clients::volume::{self, Event}; use crate::clients::volume::{self, Event};
use crate::config::{CommonConfig, LayoutConfig, TruncateMode}; use crate::config::CommonConfig;
use crate::gtk_helpers::IronbarGtkExt; use crate::gtk_helpers::IronbarGtkExt;
use crate::modules::{ use crate::modules::{
Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, PopupButton, WidgetContext, Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, PopupButton, WidgetContext,
}; };
use crate::{lock, module_impl, spawn}; use crate::{lock, module_impl, spawn};
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{Button, Image, Label, Scale, ToggleButton}; use gtk::{Button, Image};
use serde::Deserialize; use serde::Deserialize;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tracing::trace; use tracing::trace;
@ -15,48 +15,21 @@ use tracing::trace;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct VolumeModule { pub struct VolumeModule {
/// 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,
#[serde(default = "default_icon_size")] #[serde(default = "default_icon_size")]
icon_size: i32, icon_size: i32,
// -- Common -- // -- Common --
/// See [truncate options](module-level-options#truncate-mode).
///
/// **Default**: `null`
pub(crate) truncate: Option<TruncateMode>,
/// See [layout options](module-level-options#layout)
#[serde(default, flatten)]
layout: LayoutConfig,
/// See [common options](module-level-options#common-options). /// See [common options](module-level-options#common-options).
#[serde(flatten)] #[serde(flatten)]
pub common: Option<CommonConfig>, pub common: Option<CommonConfig>,
} }
const fn default_max_volume() -> f64 {
100.0
}
const fn default_icon_size() -> i32 { const fn default_icon_size() -> i32 {
24 24
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Update { pub enum Update {}
SinkChange(String),
SinkVolume(String, f64),
SinkMute(String, bool),
InputVolume(u32, f64),
InputMute(u32, bool),
}
impl Module<Button> for VolumeModule { impl Module<Button> for VolumeModule {
type SendMessage = Event; type SendMessage = Event;
@ -68,7 +41,7 @@ impl Module<Button> for VolumeModule {
&self, &self,
_info: &ModuleInfo, _info: &ModuleInfo,
context: &WidgetContext<Self::SendMessage, Self::ReceiveMessage>, context: &WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
mut rx: mpsc::Receiver<Self::ReceiveMessage>, _rx: mpsc::Receiver<Self::ReceiveMessage>,
) -> color_eyre::Result<()> ) -> color_eyre::Result<()>
where where
<Self as Module<Button>>::SendMessage: Clone, <Self as Module<Button>>::SendMessage: Clone,
@ -102,8 +75,8 @@ impl Module<Button> for VolumeModule {
tx.send_update(Event::AddSink(sink)).await; tx.send_update(Event::AddSink(sink)).await;
} }
for input in inputs { for _input in inputs {
tx.send_update(Event::AddInput(input)).await; tx.send_update(Event::AddInput).await;
} }
// recv loop // recv loop
@ -114,19 +87,6 @@ impl Module<Button> for VolumeModule {
}); });
} }
// ui events
spawn(async move {
while let Some(update) = rx.recv().await {
match update {
Update::SinkChange(name) => client.set_default_sink(&name),
Update::SinkVolume(name, volume) => client.set_sink_volume(&name, volume),
Update::SinkMute(name, muted) => client.set_sink_muted(&name, muted),
Update::InputVolume(index, volume) => client.set_input_volume(index, volume),
Update::InputMute(index, muted) => client.set_input_muted(index, muted),
}
}
});
Ok(()) Ok(())
} }
@ -179,13 +139,6 @@ impl Module<Button> for VolumeModule {
} }
} }
struct InputUi {
container: gtk::Box,
label: Label,
slider: Scale,
btn_mute: ToggleButton,
}
fn determine_volume_icon(muted: bool, volume: f64) -> String { fn determine_volume_icon(muted: bool, volume: f64) -> String {
let icon_variant = if muted { let icon_variant = if muted {
"muted" "muted"