Merge feature/screenshot-mode: capture every breadbar view
All checks were successful
dev release / build (push) Successful in 4m29s
All checks were successful
dev release / build (push) Successful in 4m29s
This commit is contained in:
commit
872e7e1589
7 changed files with 735 additions and 161 deletions
377
Cargo.lock
generated
377
Cargo.lock
generated
|
|
@ -8,6 +8,62 @@ version = "2.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"once_cell_polyfill",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.104"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|
@ -40,7 +96,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -62,18 +118,18 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.89"
|
version = "0.1.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -94,12 +150,22 @@ version = "2.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bread-screenshots"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "git+https://git.breadway.dev/Breadway/bread-ecosystem?branch=dev#27b3b17c58b81f947a40cc0d3f9cd0862e7885ff"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bread-utils",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bread-shared"
|
name = "bread-shared"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "git+https://git.breadway.dev/Breadway/bread?tag=v0.7.0#22e34e2cf2202305d7960759dfccb54dc79f948b"
|
source = "git+https://git.breadway.dev/Breadway/bread?tag=v0.7.0#22e34e2cf2202305d7960759dfccb54dc79f948b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs",
|
"dirs 5.0.1",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"toml 0.8.23",
|
"toml 0.8.23",
|
||||||
|
|
@ -108,9 +174,9 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bread-shared"
|
name = "bread-shared"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "git+https://git.breadway.dev/Breadway/bread?branch=dev#8a794c03bfc7f2f294ff89d92494ad324afc30f5"
|
source = "git+https://git.breadway.dev/Breadway/bread?branch=dev#34854f147135143ca4baf1d628e8c609e2c1cc8c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs",
|
"dirs 6.0.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"toml 0.8.23",
|
"toml 0.8.23",
|
||||||
|
|
@ -119,9 +185,9 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bread-theme"
|
name = "bread-theme"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "git+https://github.com/Breadway/bread-ecosystem?branch=dev#77bca8a1cf90d7fd38745270d2deb291b8b22bfe"
|
source = "git+https://github.com/Breadway/bread-ecosystem?branch=dev#686af0d3dc93bf8039d62fbbd1e04a8b2db90154"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs",
|
"dirs 5.0.1",
|
||||||
"gtk4",
|
"gtk4",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
@ -130,10 +196,10 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bread-utils"
|
name = "bread-utils"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "git+https://git.breadway.dev/Breadway/bread-ecosystem?branch=dev#77bca8a1cf90d7fd38745270d2deb291b8b22bfe"
|
source = "git+https://git.breadway.dev/Breadway/bread-ecosystem?branch=dev#27b3b17c58b81f947a40cc0d3f9cd0862e7885ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bread-shared 0.7.0 (git+https://git.breadway.dev/Breadway/bread?tag=v0.7.0)",
|
"bread-shared 0.7.0 (git+https://git.breadway.dev/Breadway/bread?tag=v0.7.0)",
|
||||||
"dirs",
|
"dirs 5.0.1",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
@ -142,9 +208,12 @@ dependencies = [
|
||||||
name = "breadbar"
|
name = "breadbar"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bread-screenshots",
|
||||||
"bread-shared 0.7.0 (git+https://git.breadway.dev/Breadway/bread?branch=dev)",
|
"bread-shared 0.7.0 (git+https://git.breadway.dev/Breadway/bread?branch=dev)",
|
||||||
"bread-theme",
|
"bread-theme",
|
||||||
"bread-utils",
|
"bread-utils",
|
||||||
|
"clap",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"gtk4",
|
"gtk4",
|
||||||
"gtk4-layer-shell",
|
"gtk4-layer-shell",
|
||||||
|
|
@ -165,9 +234,9 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.25.1"
|
version = "1.25.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d6aedf8ae72766347502cf3cb4f41cf5e9cc37d28bee90f1fdaaae15f9cf9424"
|
checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
|
|
@ -215,14 +284,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "clap"
|
||||||
version = "2.5.0"
|
version = "4.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
checksum = "d91e0c145792ef73a6ad36d27c75ac09f1832222a3c209689d90f534685ee5b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-utils",
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 3.0.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
|
@ -241,12 +347,6 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-utils"
|
|
||||||
version = "0.8.22"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "data-url"
|
name = "data-url"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
|
@ -272,7 +372,7 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -282,7 +382,16 @@ version = "5.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs-sys",
|
"dirs-sys 0.4.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys 0.5.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -293,15 +402,27 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"option-ext",
|
"option-ext",
|
||||||
"redox_users",
|
"redox_users 0.4.6",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "dirs-sys"
|
||||||
version = "1.16.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
|
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"option-ext",
|
||||||
|
"redox_users 0.5.2",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "endi"
|
name = "endi"
|
||||||
|
|
@ -327,7 +448,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -357,11 +478,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "5.4.1"
|
version = "5.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
|
checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"concurrent-queue",
|
|
||||||
"parking",
|
"parking",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
@ -378,11 +498,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.4.1"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.3.4",
|
"getrandom 0.4.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -510,7 +630,7 @@ checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -611,20 +731,6 @@ dependencies = [
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.3.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"js-sys",
|
|
||||||
"libc",
|
|
||||||
"r-efi 5.3.0",
|
|
||||||
"wasip2",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
|
@ -632,8 +738,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
|
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"r-efi 6.0.0",
|
"r-efi",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -716,7 +824,7 @@ dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -850,7 +958,7 @@ dependencies = [
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -916,7 +1024,7 @@ checksum = "31157e6ccefbad4b0cd7e549db6696691a70c11b108f26bf6bf76eef26af8c10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -935,6 +1043,12 @@ dependencies = [
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_terminal_polyfill"
|
||||||
|
version = "1.70.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
|
@ -972,9 +1086,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.186"
|
version = "0.2.189"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
|
|
@ -1057,6 +1171,12 @@ version = "1.21.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell_polyfill"
|
||||||
|
version = "1.70.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option-ext"
|
name = "option-ext"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
@ -1159,28 +1279,22 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.106"
|
version = "1.0.107"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.46"
|
version = "1.0.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
|
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "r-efi"
|
|
||||||
version = "5.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "r-efi"
|
name = "r-efi"
|
||||||
version = "6.0.0"
|
version = "6.0.0"
|
||||||
|
|
@ -1195,7 +1309,18 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.17",
|
"getrandom 0.2.17",
|
||||||
"libredox",
|
"libredox",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_users"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.17",
|
||||||
|
"libredox",
|
||||||
|
"thiserror 2.0.19",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1229,7 +1354,7 @@ checksum = "36c9dbf50a60c82375e66b61d522c936b187a11b25c0a42e91c516326ad24a4f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1306,9 +1431,9 @@ checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.228"
|
version = "1.0.229"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
|
|
@ -1316,29 +1441,29 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_core"
|
name = "serde_core"
|
||||||
version = "1.0.228"
|
version = "1.0.229"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.228"
|
version = "1.0.229"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.150"
|
version = "1.0.151"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|
@ -1349,13 +1474,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_repr"
|
name = "serde_repr"
|
||||||
version = "0.1.20"
|
version = "0.1.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
|
checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1447,6 +1572,12 @@ dependencies = [
|
||||||
"float-cmp",
|
"float-cmp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "svgtypes"
|
name = "svgtypes"
|
||||||
version = "0.16.1"
|
version = "0.16.1"
|
||||||
|
|
@ -1468,6 +1599,17 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "3.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-deps"
|
name = "system-deps"
|
||||||
version = "7.0.8"
|
version = "7.0.8"
|
||||||
|
|
@ -1477,7 +1619,7 @@ dependencies = [
|
||||||
"cfg-expr",
|
"cfg-expr",
|
||||||
"heck",
|
"heck",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"toml 1.1.3+spec-1.1.0",
|
"toml 1.1.4+spec-1.1.0",
|
||||||
"version-compare",
|
"version-compare",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1506,7 +1648,16 @@ version = "1.0.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl 2.0.19",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1517,7 +1668,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1548,9 +1710,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.53.0"
|
version = "1.53.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d988bcd52dbe076d3d46903332f58c912b87a2c49b1428419a5845154762ffee"
|
checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -1571,7 +1733,7 @@ checksum = "6328af13490e73a9b4694030fafd93f8c8c6a9dede33e821c3fc63eddf8042ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1588,9 +1750,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "1.1.3+spec-1.1.0"
|
version = "1.1.4+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c"
|
checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
|
|
@ -1647,9 +1809,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_parser"
|
name = "toml_parser"
|
||||||
version = "1.1.2+spec-1.1.0"
|
version = "1.1.3+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
|
checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winnow 1.0.4",
|
"winnow 1.0.4",
|
||||||
]
|
]
|
||||||
|
|
@ -1685,7 +1847,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1748,6 +1910,12 @@ dependencies = [
|
||||||
"xmlwriter",
|
"xmlwriter",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.24.0"
|
version = "1.24.0"
|
||||||
|
|
@ -1771,15 +1939,6 @@ version = "0.11.1+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasip2"
|
|
||||||
version = "1.0.4+wasi-0.2.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
|
|
||||||
dependencies = [
|
|
||||||
"wit-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.126"
|
version = "0.2.126"
|
||||||
|
|
@ -1812,7 +1971,7 @@ dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1924,12 +2083,6 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wit-bindgen"
|
|
||||||
version = "0.57.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xml-rs"
|
name = "xml-rs"
|
||||||
version = "0.8.28"
|
version = "0.8.28"
|
||||||
|
|
@ -1981,7 +2134,7 @@ dependencies = [
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
"zbus_names",
|
"zbus_names",
|
||||||
"zvariant",
|
"zvariant",
|
||||||
"zvariant_utils",
|
"zvariant_utils",
|
||||||
|
|
@ -2027,7 +2180,7 @@ dependencies = [
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
"zvariant_utils",
|
"zvariant_utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -2040,6 +2193,6 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"serde",
|
"serde",
|
||||||
"syn",
|
"syn 2.0.119",
|
||||||
"winnow 1.0.4",
|
"winnow 1.0.4",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ bread-theme = { git = "https://github.com/Breadway/bread-ecosystem", branch = "d
|
||||||
# instead of hand-parsing serde_json::Value. See src/widgets/.
|
# instead of hand-parsing serde_json::Value. See src/widgets/.
|
||||||
bread-utils = { git = "https://git.breadway.dev/Breadway/bread-ecosystem", branch = "dev", features = ["bread-client"] }
|
bread-utils = { git = "https://git.breadway.dev/Breadway/bread-ecosystem", branch = "dev", features = ["bread-client"] }
|
||||||
bread-shared = { git = "https://git.breadway.dev/Breadway/bread", branch = "dev" }
|
bread-shared = { git = "https://git.breadway.dev/Breadway/bread", branch = "dev" }
|
||||||
|
# Capture primitives for `--screenshot` mode — see src/screenshot.rs.
|
||||||
|
bread-screenshots = { git = "https://git.breadway.dev/Breadway/bread-ecosystem", branch = "dev" }
|
||||||
gtk4 = { version = "0.11", features = ["v4_12"] }
|
gtk4 = { version = "0.11", features = ["v4_12"] }
|
||||||
gtk4-layer-shell = "0.8"
|
gtk4-layer-shell = "0.8"
|
||||||
relm4 = { version = "0.11", features = ["macros"] }
|
relm4 = { version = "0.11", features = ["macros"] }
|
||||||
|
|
@ -26,6 +28,8 @@ zbus = { version = "5", default-features = false, features = ["tokio"] }
|
||||||
tokio = { version = "1", features = ["rt-multi-thread", "macros", "time", "process", "signal", "sync"] }
|
tokio = { version = "1", features = ["rt-multi-thread", "macros", "time", "process", "signal", "sync"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
clap = { version = "4", features = ["derive"] }
|
||||||
|
anyhow = "1"
|
||||||
# Pure-Rust SVG rasteriser (default features off → no text/font deps; the icons
|
# Pure-Rust SVG rasteriser (default features off → no text/font deps; the icons
|
||||||
# are vector-only). Needed because librsvg dropped its gdk-pixbuf SVG loader.
|
# are vector-only). Needed because librsvg dropped its gdk-pixbuf SVG loader.
|
||||||
resvg = { version = "0.47", default-features = false }
|
resvg = { version = "0.47", default-features = false }
|
||||||
|
|
|
||||||
85
src/main.rs
85
src/main.rs
|
|
@ -7,6 +7,7 @@ macro_rules! asset {
|
||||||
mod bar;
|
mod bar;
|
||||||
mod notifications;
|
mod notifications;
|
||||||
mod osd;
|
mod osd;
|
||||||
|
mod screenshot;
|
||||||
mod theme;
|
mod theme;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
|
|
||||||
|
|
@ -124,7 +125,7 @@ pub enum AppInput {
|
||||||
|
|
||||||
#[relm4::component(pub)]
|
#[relm4::component(pub)]
|
||||||
impl SimpleComponent for App {
|
impl SimpleComponent for App {
|
||||||
type Init = ();
|
type Init = Option<screenshot::ScreenshotRequest>;
|
||||||
type Input = AppInput;
|
type Input = AppInput;
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
|
|
@ -141,7 +142,7 @@ impl SimpleComponent for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(
|
fn init(
|
||||||
_: Self::Init,
|
screenshot_req: Self::Init,
|
||||||
root: Self::Root,
|
root: Self::Root,
|
||||||
sender: ComponentSender<Self>,
|
sender: ComponentSender<Self>,
|
||||||
) -> ComponentParts<Self> {
|
) -> ComponentParts<Self> {
|
||||||
|
|
@ -644,6 +645,17 @@ impl SimpleComponent for App {
|
||||||
widgets.center_box.set_center_widget(Some(¢er_area));
|
widgets.center_box.set_center_widget(Some(¢er_area));
|
||||||
widgets.center_box.set_end_widget(Some(&stats_box));
|
widgets.center_box.set_end_widget(Some(&stats_box));
|
||||||
|
|
||||||
|
// Captured before these move into `model` (or are otherwise dropped
|
||||||
|
// as bare locals, never stored on `App` at all) — needed by the
|
||||||
|
// screenshot dispatch just before this function returns.
|
||||||
|
let control_popover_for_screenshot = control_popover.clone();
|
||||||
|
let connectivity_popover_for_screenshot = connectivity_popover.clone();
|
||||||
|
let wifi_tab_btn_for_screenshot = wifi_tab_btn.clone();
|
||||||
|
let bt_tab_btn_for_screenshot = bt_tab_btn.clone();
|
||||||
|
let media_popover_for_screenshot = media_popover.clone();
|
||||||
|
let media_widget_for_screenshot = media_widget.clone();
|
||||||
|
let media_track_lbl_for_screenshot = media_track_lbl.clone();
|
||||||
|
|
||||||
let model = App {
|
let model = App {
|
||||||
workspaces: vec![],
|
workspaces: vec![],
|
||||||
active_ws: 1,
|
active_ws: 1,
|
||||||
|
|
@ -710,8 +722,44 @@ impl SimpleComponent for App {
|
||||||
bar::wifi::spawn_status_poller(sender.clone());
|
bar::wifi::spawn_status_poller(sender.clone());
|
||||||
bar::media::spawn_poller(sender.clone());
|
bar::media::spawn_poller(sender.clone());
|
||||||
widgets::client::spawn(sender.clone());
|
widgets::client::spawn(sender.clone());
|
||||||
notifications::spawn();
|
|
||||||
osd::spawn();
|
// Screenshot mode primes these with sample content instead of the
|
||||||
|
// real D-Bus/pactl/backlight sources — see notifications::SampleKind
|
||||||
|
// and osd::SampleKind's doc comments.
|
||||||
|
let notif_sample = screenshot_req.as_ref().and_then(|r| match r.view.as_str() {
|
||||||
|
"notification" => Some(notifications::SampleKind::Normal),
|
||||||
|
"notification-critical" => Some(notifications::SampleKind::Critical),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
let notification_window = notifications::spawn(notif_sample);
|
||||||
|
let osd_sample = screenshot_req.as_ref().and_then(|r| match r.view.as_str() {
|
||||||
|
"osd-volume" => Some(osd::SampleKind::Volume),
|
||||||
|
"osd-brightness" => Some(osd::SampleKind::Brightness),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
let osd_window = osd::spawn(osd_sample);
|
||||||
|
|
||||||
|
if let Some(req) = screenshot_req {
|
||||||
|
let notification_window = matches!(req.view.as_str(), "notification" | "notification-critical")
|
||||||
|
.then_some(notification_window);
|
||||||
|
let osd_window = matches!(req.view.as_str(), "osd-volume" | "osd-brightness")
|
||||||
|
.then_some(osd_window);
|
||||||
|
screenshot::dispatch(
|
||||||
|
&root,
|
||||||
|
req,
|
||||||
|
screenshot::Handles {
|
||||||
|
control_popover: control_popover_for_screenshot,
|
||||||
|
connectivity_popover: connectivity_popover_for_screenshot,
|
||||||
|
wifi_tab_btn: wifi_tab_btn_for_screenshot,
|
||||||
|
bt_tab_btn: bt_tab_btn_for_screenshot,
|
||||||
|
media_popover: media_popover_for_screenshot,
|
||||||
|
media_widget: media_widget_for_screenshot,
|
||||||
|
media_track_lbl: media_track_lbl_for_screenshot,
|
||||||
|
notification_window,
|
||||||
|
osd_window,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ComponentParts { model, widgets }
|
ComponentParts { model, widgets }
|
||||||
}
|
}
|
||||||
|
|
@ -1136,7 +1184,7 @@ impl App {
|
||||||
if saved {
|
if saved {
|
||||||
bar::wifi::spawn_join(ssid_clone.clone());
|
bar::wifi::spawn_join(ssid_clone.clone());
|
||||||
} else {
|
} else {
|
||||||
show_add_network_dialog(btn, ssid_clone.clone());
|
show_add_network_dialog(btn, ssid_clone.clone(), |_| {});
|
||||||
}
|
}
|
||||||
close_parent_popover(btn);
|
close_parent_popover(btn);
|
||||||
});
|
});
|
||||||
|
|
@ -1293,8 +1341,11 @@ fn close_parent_popover(widget: >k4::Button) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Small modal prompting for a password, then saves + joins the network via
|
/// Small modal prompting for a password, then saves + joins the network via
|
||||||
/// `breadcrumbs add` + `breadcrumbs join`.
|
/// `breadcrumbs add` + `breadcrumbs join`. `on_build` runs on the freshly
|
||||||
fn show_add_network_dialog(anchor: >k4::Button, ssid: String) {
|
/// built dialog *before* it's presented — screenshot mode's only hook point,
|
||||||
|
/// since `connect_map` registered any later would miss a map that already
|
||||||
|
/// happened. The real call site passes a no-op.
|
||||||
|
fn show_add_network_dialog(anchor: &impl IsA<gtk4::Widget>, ssid: String, on_build: impl FnOnce(>k4::Window)) {
|
||||||
let dialog = gtk4::Window::new();
|
let dialog = gtk4::Window::new();
|
||||||
dialog.set_title(Some(&format!("Add “{ssid}”")));
|
dialog.set_title(Some(&format!("Add “{ssid}”")));
|
||||||
dialog.set_resizable(false);
|
dialog.set_resizable(false);
|
||||||
|
|
@ -1358,6 +1409,7 @@ fn show_add_network_dialog(anchor: >k4::Button, ssid: String) {
|
||||||
dialog_for_activate.close();
|
dialog_for_activate.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
on_build(&dialog);
|
||||||
dialog.present();
|
dialog.present();
|
||||||
entry.grab_focus();
|
entry.grab_focus();
|
||||||
}
|
}
|
||||||
|
|
@ -1411,6 +1463,10 @@ fn stat_label() -> gtk4::Label {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
use clap::Parser;
|
||||||
|
let cli = screenshot::Cli::parse();
|
||||||
|
let screenshot_req = cli.screenshot_request();
|
||||||
|
|
||||||
relm4::spawn(async {
|
relm4::spawn(async {
|
||||||
use tokio::signal::unix::{signal, SignalKind};
|
use tokio::signal::unix::{signal, SignalKind};
|
||||||
let mut stream = signal(SignalKind::hangup()).expect("SIGHUP handler");
|
let mut stream = signal(SignalKind::hangup()).expect("SIGHUP handler");
|
||||||
|
|
@ -1420,6 +1476,17 @@ fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let app = RelmApp::new("sh.breadway.breadbar");
|
// `with_args(vec![])` stops relm4 from handing our own --screenshot/
|
||||||
app.run::<App>(());
|
// --output flags to GLib's option parser (`app.run()`'s default), which
|
||||||
|
// would otherwise reject them as unrecognized before Cli::parse() above
|
||||||
|
// ever sees argv. allow_multiple_instances is needed for screenshot runs
|
||||||
|
// specifically: GApplication is single-instance by default, and a normal
|
||||||
|
// breadbar is typically already running, so without this a screenshot
|
||||||
|
// invocation would just activate that existing instance instead of
|
||||||
|
// starting a fresh one whose `init()` receives the request at all.
|
||||||
|
let app = RelmApp::new("sh.breadway.breadbar").with_args(vec![]);
|
||||||
|
if screenshot_req.is_some() {
|
||||||
|
app.allow_multiple_instances(true);
|
||||||
|
}
|
||||||
|
app.run::<App>(screenshot_req);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -172,38 +172,90 @@ impl NotifServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn() {
|
/// A fixed sample notification for `--screenshot notification`/
|
||||||
let (tx, rx) = mpsc::channel(32);
|
/// `notification-critical` — substitutes for a real `Notify` D-Bus call so a
|
||||||
let (conn_tx, conn_rx) = tokio::sync::oneshot::channel();
|
/// capture doesn't depend on some external sender firing one at just the
|
||||||
|
/// right moment.
|
||||||
|
pub enum SampleKind {
|
||||||
|
Normal,
|
||||||
|
Critical,
|
||||||
|
}
|
||||||
|
|
||||||
relm4::spawn(async move {
|
impl SampleKind {
|
||||||
let server = NotifServer {
|
fn sample_event(&self) -> NotifEvent {
|
||||||
tx,
|
let urgency = match self {
|
||||||
next_id: AtomicU32::new(1),
|
SampleKind::Normal => Urgency::Normal,
|
||||||
sync_tags: Mutex::new(HashMap::new()),
|
SampleKind::Critical => Urgency::Critical,
|
||||||
};
|
};
|
||||||
// Builder failures here would only occur with invalid static strings — safe to unwrap.
|
NotifEvent::Show {
|
||||||
let conn = zbus::connection::Builder::session()
|
id: 1,
|
||||||
.unwrap()
|
app_name: "Sample App".into(),
|
||||||
.name("org.freedesktop.Notifications")
|
summary: "Sample notification".into(),
|
||||||
.unwrap()
|
body: "This is what a notification card looks like.".into(),
|
||||||
.serve_at("/org/freedesktop/Notifications", server)
|
urgency,
|
||||||
.unwrap()
|
expire: Expire::Never,
|
||||||
.build()
|
|
||||||
.await
|
|
||||||
.expect("failed to claim org.freedesktop.Notifications on D-Bus session bus");
|
|
||||||
// Hand the connection to popup::run so it can emit `NotificationClosed`
|
|
||||||
// (spec-mandated whenever a notification actually goes away) — the
|
|
||||||
// dismiss decisions all happen over there, not in this interface impl.
|
|
||||||
let _ = conn_tx.send(conn);
|
|
||||||
std::future::pending::<()>().await
|
|
||||||
});
|
|
||||||
|
|
||||||
relm4::spawn_local(async move {
|
|
||||||
if let Ok(conn) = conn_rx.await {
|
|
||||||
popup::run(rx, conn).await;
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds the notification window synchronously (see
|
||||||
|
/// `popup::build_window`'s doc comment) and spawns the event loop that
|
||||||
|
/// shows/updates/hides it.
|
||||||
|
///
|
||||||
|
/// `sample`: `Some` skips real D-Bus registration entirely and seeds the
|
||||||
|
/// loop with one fixed sample event instead — screenshot mode only. Doing
|
||||||
|
/// the real `org.freedesktop.Notifications` registration in every
|
||||||
|
/// screenshot run would race the real breadbar (if running) for the same
|
||||||
|
/// well-known name for no benefit, since nothing needs to reach this
|
||||||
|
/// instance externally.
|
||||||
|
pub fn spawn(sample: Option<SampleKind>) -> gtk4::Window {
|
||||||
|
let (window, cards_box) = popup::build_window();
|
||||||
|
let (tx, rx) = mpsc::channel(32);
|
||||||
|
|
||||||
|
match sample {
|
||||||
|
Some(kind) => {
|
||||||
|
let _ = tx.try_send(kind.sample_event());
|
||||||
|
let window_for_loop = window.clone();
|
||||||
|
relm4::spawn_local(async move {
|
||||||
|
popup::run(window_for_loop, cards_box, rx, None).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let (conn_tx, conn_rx) = tokio::sync::oneshot::channel();
|
||||||
|
|
||||||
|
relm4::spawn(async move {
|
||||||
|
let server = NotifServer {
|
||||||
|
tx,
|
||||||
|
next_id: AtomicU32::new(1),
|
||||||
|
sync_tags: Mutex::new(HashMap::new()),
|
||||||
|
};
|
||||||
|
// Builder failures here would only occur with invalid static strings — safe to unwrap.
|
||||||
|
let conn = zbus::connection::Builder::session()
|
||||||
|
.unwrap()
|
||||||
|
.name("org.freedesktop.Notifications")
|
||||||
|
.unwrap()
|
||||||
|
.serve_at("/org/freedesktop/Notifications", server)
|
||||||
|
.unwrap()
|
||||||
|
.build()
|
||||||
|
.await
|
||||||
|
.expect("failed to claim org.freedesktop.Notifications on D-Bus session bus");
|
||||||
|
// Hand the connection to popup::run so it can emit `NotificationClosed`
|
||||||
|
// (spec-mandated whenever a notification actually goes away) — the
|
||||||
|
// dismiss decisions all happen over there, not in this interface impl.
|
||||||
|
let _ = conn_tx.send(conn);
|
||||||
|
std::future::pending::<()>().await
|
||||||
|
});
|
||||||
|
|
||||||
|
let window_for_loop = window.clone();
|
||||||
|
relm4::spawn_local(async move {
|
||||||
|
if let Ok(conn) = conn_rx.await {
|
||||||
|
popup::run(window_for_loop, cards_box, rx, Some(conn)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,11 @@ mod close_reason {
|
||||||
pub const CLOSE_NOTIFICATION_CALL: u32 = 3;
|
pub const CLOSE_NOTIFICATION_CALL: u32 = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(mut rx: Receiver<NotifEvent>, conn: zbus::Connection) {
|
/// Builds the notification window synchronously — so a caller (screenshot
|
||||||
|
/// mode in particular) has a real window to hook `connect_map` on before
|
||||||
|
/// `run`'s event loop, which needs an async `zbus::Connection` handshake in
|
||||||
|
/// the real path, ever starts.
|
||||||
|
pub fn build_window() -> (gtk4::Window, gtk4::Box) {
|
||||||
let window = create_window();
|
let window = create_window();
|
||||||
let cards_box = gtk4::Box::new(gtk4::Orientation::Vertical, 4);
|
let cards_box = gtk4::Box::new(gtk4::Orientation::Vertical, 4);
|
||||||
cards_box.set_margin_top(8);
|
cards_box.set_margin_top(8);
|
||||||
|
|
@ -31,7 +35,21 @@ pub async fn run(mut rx: Receiver<NotifEvent>, conn: zbus::Connection) {
|
||||||
cards_box.set_margin_start(8);
|
cards_box.set_margin_start(8);
|
||||||
cards_box.set_margin_end(8);
|
cards_box.set_margin_end(8);
|
||||||
window.set_child(Some(&cards_box));
|
window.set_child(Some(&cards_box));
|
||||||
|
(window, cards_box)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `conn`: `None` in screenshot mode, which skips real D-Bus registration
|
||||||
|
/// entirely (see `super::spawn`) — there's no external client that needs to
|
||||||
|
/// reach a screenshot-only instance, and registering the well-known name
|
||||||
|
/// would just race the real breadbar for it. `NotificationClosed` is a
|
||||||
|
/// spec-mandated signal for real clients only, so it's simply not emitted
|
||||||
|
/// when there's no real connection to emit it on.
|
||||||
|
pub async fn run(
|
||||||
|
window: gtk4::Window,
|
||||||
|
cards_box: gtk4::Box,
|
||||||
|
mut rx: Receiver<NotifEvent>,
|
||||||
|
conn: Option<zbus::Connection>,
|
||||||
|
) {
|
||||||
let cards: Cards = Rc::new(RefCell::new(HashMap::new()));
|
let cards: Cards = Rc::new(RefCell::new(HashMap::new()));
|
||||||
let generations: Generations = Rc::new(RefCell::new(HashMap::new()));
|
let generations: Generations = Rc::new(RefCell::new(HashMap::new()));
|
||||||
|
|
||||||
|
|
@ -109,8 +127,10 @@ fn dismiss(cards_box: >k4::Box, window: >k4::Window, cards: &Cards, id: u32)
|
||||||
/// Emits the spec-mandated `NotificationClosed(id, reason)` signal. Sent
|
/// Emits the spec-mandated `NotificationClosed(id, reason)` signal. Sent
|
||||||
/// directly over the connection rather than through the zbus interface
|
/// directly over the connection rather than through the zbus interface
|
||||||
/// macro's generated helper, since the dismiss decision happens here in the
|
/// macro's generated helper, since the dismiss decision happens here in the
|
||||||
/// popup task, not inside `NotifServer`'s own method bodies.
|
/// popup task, not inside `NotifServer`'s own method bodies. No-op when
|
||||||
async fn emit_closed(conn: &zbus::Connection, id: u32, reason: u32) {
|
/// `conn` is `None` (screenshot mode — see `run`'s doc comment).
|
||||||
|
async fn emit_closed(conn: &Option<zbus::Connection>, id: u32, reason: u32) {
|
||||||
|
let Some(conn) = conn else { return };
|
||||||
let result = conn
|
let result = conn
|
||||||
.emit_signal(
|
.emit_signal(
|
||||||
None::<&str>,
|
None::<&str>,
|
||||||
|
|
|
||||||
50
src/osd.rs
50
src/osd.rs
|
|
@ -9,14 +9,50 @@ enum OsdEvent {
|
||||||
Brightness { pct: u8 },
|
Brightness { pct: u8 },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn() {
|
/// A fixed sample event for `--screenshot osd-volume`/`osd-brightness` —
|
||||||
|
/// substitutes for the real `pactl subscribe`/backlight-sysfs watchers so a
|
||||||
|
/// capture doesn't depend on this machine's actual volume/brightness at
|
||||||
|
/// capture time.
|
||||||
|
pub enum SampleKind {
|
||||||
|
Volume,
|
||||||
|
Brightness,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SampleKind {
|
||||||
|
fn sample_event(&self) -> OsdEvent {
|
||||||
|
match self {
|
||||||
|
SampleKind::Volume => OsdEvent::Volume { pct: 65, muted: false },
|
||||||
|
SampleKind::Brightness => OsdEvent::Brightness { pct: 80 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds the OSD window synchronously (so a caller — screenshot mode, via
|
||||||
|
/// `sample`, in particular — has a real window to hook `connect_map` on
|
||||||
|
/// before the async event loop below ever runs) and spawns the event loop
|
||||||
|
/// that shows/updates/hides it.
|
||||||
|
///
|
||||||
|
/// `sample`: `Some` skips the real volume/brightness watchers entirely and
|
||||||
|
/// seeds the loop with one fixed sample event instead — screenshot mode
|
||||||
|
/// only, so a capture never depends on (or is disrupted by) this machine's
|
||||||
|
/// actual audio/backlight state.
|
||||||
|
pub fn spawn(sample: Option<SampleKind>) -> gtk4::Window {
|
||||||
let (tx, rx) = mpsc::channel::<OsdEvent>(8);
|
let (tx, rx) = mpsc::channel::<OsdEvent>(8);
|
||||||
|
|
||||||
let tx1 = tx.clone();
|
match sample {
|
||||||
std::thread::spawn(move || volume_watcher(tx1));
|
Some(kind) => {
|
||||||
std::thread::spawn(move || brightness_watcher(tx));
|
let _ = tx.try_send(kind.sample_event());
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let tx1 = tx.clone();
|
||||||
|
std::thread::spawn(move || volume_watcher(tx1));
|
||||||
|
std::thread::spawn(move || brightness_watcher(tx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
relm4::spawn_local(run_osd(rx));
|
let window = create_window();
|
||||||
|
relm4::spawn_local(run_osd(window.clone(), rx));
|
||||||
|
window
|
||||||
}
|
}
|
||||||
|
|
||||||
fn volume_watcher(tx: mpsc::Sender<OsdEvent>) {
|
fn volume_watcher(tx: mpsc::Sender<OsdEvent>) {
|
||||||
|
|
@ -119,9 +155,7 @@ fn brightness_watcher(tx: mpsc::Sender<OsdEvent>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_osd(mut rx: mpsc::Receiver<OsdEvent>) {
|
async fn run_osd(window: gtk4::Window, mut rx: mpsc::Receiver<OsdEvent>) {
|
||||||
let window = create_window();
|
|
||||||
|
|
||||||
let container = gtk4::Box::new(gtk4::Orientation::Horizontal, 0);
|
let container = gtk4::Box::new(gtk4::Orientation::Horizontal, 0);
|
||||||
container.set_margin_top(10);
|
container.set_margin_top(10);
|
||||||
container.set_margin_bottom(10);
|
container.set_margin_bottom(10);
|
||||||
|
|
|
||||||
244
src/screenshot.rs
Normal file
244
src/screenshot.rs
Normal file
|
|
@ -0,0 +1,244 @@
|
||||||
|
//! `--screenshot` CLI mode: render a specific view, capture it via
|
||||||
|
//! `bread-screenshots`, then exit — driven by `bread-ecosystem`'s
|
||||||
|
//! `bread-capture` orchestrator, or run standalone for one-off captures.
|
||||||
|
//!
|
||||||
|
//! Capture waits on GTK's `map` signal rather than a blind sleep before
|
||||||
|
//! grabbing pixels — the surface (or, for popover views, the popover itself)
|
||||||
|
//! genuinely isn't on screen yet before that fires, so a fixed delay would
|
||||||
|
//! either race a slow first paint or pad every fast one for nothing.
|
||||||
|
//!
|
||||||
|
//! breadbar is "a bar + the notification daemon + the OSD" (see its own
|
||||||
|
//! module docs), so its screenshot views span three separate top-level
|
||||||
|
//! surfaces, not just the bar: the bar itself and its popovers (this
|
||||||
|
//! module, anchored off `root`), plus the standalone notification and OSD
|
||||||
|
//! windows (`notifications::spawn`/`osd::spawn`, built and primed with
|
||||||
|
//! sample data by `main.rs` before `dispatch` runs — see [`Handles`]).
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use gtk4::prelude::*;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
/// Extra settle time after `map` for the first frame to actually paint
|
||||||
|
/// before grim runs — `map` fires once the surface exists, not once
|
||||||
|
/// anything has been drawn into it.
|
||||||
|
const SETTLE_DELAY: Duration = Duration::from_millis(300);
|
||||||
|
|
||||||
|
/// Settle time for views whose content depends on `bar::stats::spawn_poller`'s
|
||||||
|
/// 2-second background loop (control-panel's CPU/RAM/PWR/GPU/network labels,
|
||||||
|
/// gated on popover visibility) or a similar live-data popover load
|
||||||
|
/// (connectivity's wifi/bluetooth scan) — capturing any sooner leaves
|
||||||
|
/// placeholder dashes/"Scanning…" instead of real content.
|
||||||
|
const LIVE_DATA_SETTLE_DELAY: Duration = Duration::from_millis(2_200);
|
||||||
|
|
||||||
|
/// Delay between the bar's own `map` and calling `popover.popup()`. Calling
|
||||||
|
/// `popup()` synchronously from inside the root window's `map` handler
|
||||||
|
/// produces a popover that reports itself `map`ped but never actually paints
|
||||||
|
/// (confirmed by an independent `grim` capture taken mid-sequence, showing no
|
||||||
|
/// popover at all) — presumably the parent widget's own allocation isn't
|
||||||
|
/// settled yet at that exact point. Giving the initial layout pass a beat to
|
||||||
|
/// finish first is what makes it actually render.
|
||||||
|
const PRE_POPUP_DELAY: Duration = Duration::from_millis(300);
|
||||||
|
|
||||||
|
const KNOWN_VIEWS: &[&str] = &[
|
||||||
|
"bar",
|
||||||
|
"control-panel",
|
||||||
|
"connectivity-wifi",
|
||||||
|
"connectivity-bluetooth",
|
||||||
|
"media-popover",
|
||||||
|
"notification",
|
||||||
|
"notification-critical",
|
||||||
|
"osd-volume",
|
||||||
|
"osd-brightness",
|
||||||
|
"wifi-add-dialog",
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(name = "breadbar")]
|
||||||
|
pub struct Cli {
|
||||||
|
/// Render the named view, capture it, then exit instead of running
|
||||||
|
/// normally. See `screenshot::KNOWN_VIEWS` for the full list.
|
||||||
|
#[arg(long)]
|
||||||
|
pub screenshot: Option<String>,
|
||||||
|
|
||||||
|
/// PNG path to write the capture to. Required together with --screenshot.
|
||||||
|
#[arg(long)]
|
||||||
|
pub output: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Capture canvas width — matches the isolated compositor's output width
|
||||||
|
/// (`bread-capture --isolate-width`) so the geometry passed to `grim`
|
||||||
|
/// doesn't depend on querying anything at capture time.
|
||||||
|
#[arg(long, default_value_t = 1920)]
|
||||||
|
pub width: u32,
|
||||||
|
|
||||||
|
/// Capture canvas height — see `width`.
|
||||||
|
#[arg(long, default_value_t = 1080)]
|
||||||
|
pub height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ScreenshotRequest {
|
||||||
|
pub view: String,
|
||||||
|
pub output: PathBuf,
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cli {
|
||||||
|
/// `None` for a normal run. Exits the process with an error if
|
||||||
|
/// `--screenshot` was given without `--output`, before any GTK/relm4
|
||||||
|
/// setup happens.
|
||||||
|
pub fn screenshot_request(&self) -> Option<ScreenshotRequest> {
|
||||||
|
let view = self.screenshot.clone()?;
|
||||||
|
let Some(output) = self.output.clone() else {
|
||||||
|
eprintln!("breadbar: --screenshot requires --output");
|
||||||
|
std::process::exit(1);
|
||||||
|
};
|
||||||
|
Some(ScreenshotRequest { view, output, width: self.width, height: self.height })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Every widget/window `dispatch` might need, gathered by `main.rs`'s
|
||||||
|
/// `init()` — most of these are plain locals there that never otherwise
|
||||||
|
/// outlive `init()` (never stored on `App`), so they have to be cloned out
|
||||||
|
/// before dispatch time same as `control_popover` always was.
|
||||||
|
pub struct Handles {
|
||||||
|
pub control_popover: gtk4::Popover,
|
||||||
|
pub connectivity_popover: gtk4::Popover,
|
||||||
|
pub wifi_tab_btn: gtk4::ToggleButton,
|
||||||
|
pub bt_tab_btn: gtk4::ToggleButton,
|
||||||
|
pub media_popover: gtk4::Popover,
|
||||||
|
pub media_widget: gtk4::Box,
|
||||||
|
pub media_track_lbl: gtk4::Label,
|
||||||
|
/// Already built and primed with sample content by `main.rs` (via
|
||||||
|
/// `notifications::spawn(Some(kind))`) when `req.view` calls for it —
|
||||||
|
/// `None` otherwise.
|
||||||
|
pub notification_window: Option<gtk4::Window>,
|
||||||
|
/// Same deal as `notification_window`, via `osd::spawn(Some(kind))`.
|
||||||
|
pub osd_window: Option<gtk4::Window>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The bar's fixed height — matches `root.set_exclusive_zone(32)` /
|
||||||
|
/// `set_default_height: 32` in `main.rs`. Unlike the other views' full
|
||||||
|
/// canvas, this never varies with `--width`/`--height`.
|
||||||
|
const BAR_HEIGHT: i32 = 32;
|
||||||
|
|
||||||
|
pub fn dispatch(root: >k4::ApplicationWindow, req: ScreenshotRequest, handles: Handles) {
|
||||||
|
let output = req.output;
|
||||||
|
let (width, height) = (req.width as i32, req.height as i32);
|
||||||
|
|
||||||
|
match req.view.as_str() {
|
||||||
|
"bar" => {
|
||||||
|
root.connect_map(move |_| {
|
||||||
|
let output = output.clone();
|
||||||
|
gtk4::glib::timeout_add_local_once(SETTLE_DELAY, move || {
|
||||||
|
finish(bread_screenshots::capture_region(0, 0, width, BAR_HEIGHT, &output));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
"control-panel" => {
|
||||||
|
open_popover_on_root_map(root, handles.control_popover, LIVE_DATA_SETTLE_DELAY, output, width, height);
|
||||||
|
}
|
||||||
|
"connectivity-wifi" => {
|
||||||
|
handles.wifi_tab_btn.set_active(true);
|
||||||
|
open_popover_on_root_map(root, handles.connectivity_popover, LIVE_DATA_SETTLE_DELAY, output, width, height);
|
||||||
|
}
|
||||||
|
"connectivity-bluetooth" => {
|
||||||
|
handles.bt_tab_btn.set_active(true);
|
||||||
|
open_popover_on_root_map(root, handles.connectivity_popover, LIVE_DATA_SETTLE_DELAY, output, width, height);
|
||||||
|
}
|
||||||
|
"media-popover" => {
|
||||||
|
// Real media state only shows the widget/text when something's
|
||||||
|
// actually playing (see AppInput::MediaUpdate) — an automated
|
||||||
|
// run has nothing playing, so fake enough of it directly on the
|
||||||
|
// widgets to get a representative capture.
|
||||||
|
handles.media_widget.set_visible(true);
|
||||||
|
handles.media_track_lbl.set_text("Sample Track — Sample Artist");
|
||||||
|
open_popover_on_root_map(root, handles.media_popover, SETTLE_DELAY, output, width, height);
|
||||||
|
}
|
||||||
|
"notification" | "notification-critical" => {
|
||||||
|
let Some(window) = handles.notification_window else {
|
||||||
|
eprintln!("breadbar: internal error — no notification window built for '{}'", req.view);
|
||||||
|
std::process::exit(1);
|
||||||
|
};
|
||||||
|
capture_standalone_window(window, output, width, height);
|
||||||
|
}
|
||||||
|
"osd-volume" | "osd-brightness" => {
|
||||||
|
let Some(window) = handles.osd_window else {
|
||||||
|
eprintln!("breadbar: internal error — no OSD window built for '{}'", req.view);
|
||||||
|
std::process::exit(1);
|
||||||
|
};
|
||||||
|
capture_standalone_window(window, output, width, height);
|
||||||
|
}
|
||||||
|
"wifi-add-dialog" => {
|
||||||
|
let anchor = handles.wifi_tab_btn;
|
||||||
|
root.connect_map(move |_| {
|
||||||
|
let output = output.clone();
|
||||||
|
let anchor = anchor.clone();
|
||||||
|
gtk4::glib::timeout_add_local_once(PRE_POPUP_DELAY, move || {
|
||||||
|
crate::show_add_network_dialog(&anchor, "Sample Network".to_string(), move |dialog| {
|
||||||
|
capture_standalone_window(dialog.clone(), output.clone(), width, height);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
eprintln!(
|
||||||
|
"breadbar: unknown screenshot view '{other}' (known: {})",
|
||||||
|
KNOWN_VIEWS.join(", ")
|
||||||
|
);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shared shape for every popover view: force it open shortly after the bar
|
||||||
|
/// maps (autohide disabled — a programmatic `popup()` has no real input
|
||||||
|
/// event serial to grab the Wayland seat with), then capture the whole
|
||||||
|
/// canvas after `settle` once the popover itself maps.
|
||||||
|
fn open_popover_on_root_map(
|
||||||
|
root: >k4::ApplicationWindow,
|
||||||
|
popover: gtk4::Popover,
|
||||||
|
settle: Duration,
|
||||||
|
output: PathBuf,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
) {
|
||||||
|
let popover_to_open = popover.clone();
|
||||||
|
root.connect_map(move |_| {
|
||||||
|
popover_to_open.set_autohide(false);
|
||||||
|
let popover_to_open = popover_to_open.clone();
|
||||||
|
gtk4::glib::timeout_add_local_once(PRE_POPUP_DELAY, move || {
|
||||||
|
popover_to_open.popup();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
popover.connect_map(move |_| {
|
||||||
|
let output = output.clone();
|
||||||
|
gtk4::glib::timeout_add_local_once(settle, move || {
|
||||||
|
finish(bread_screenshots::capture_region(0, 0, width, height, &output));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shared shape for the standalone notification/OSD windows and the wifi
|
||||||
|
/// add-network dialog: wait for `map`, settle, capture, exit. These are
|
||||||
|
/// already-visible-or-about-to-be windows by the time this is called (their
|
||||||
|
/// sample event is queued before `dispatch` even runs), so this is just the
|
||||||
|
/// capture half.
|
||||||
|
fn capture_standalone_window(window: gtk4::Window, output: PathBuf, width: i32, height: i32) {
|
||||||
|
window.connect_map(move |_| {
|
||||||
|
let output = output.clone();
|
||||||
|
gtk4::glib::timeout_add_local_once(SETTLE_DELAY, move || {
|
||||||
|
finish(bread_screenshots::capture_region(0, 0, width, height, &output));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish(result: anyhow::Result<()>) {
|
||||||
|
match result {
|
||||||
|
Ok(()) => std::process::exit(0),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("breadbar: screenshot capture failed: {e}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue