diff --git a/.cargo/config.toml b/.cargo/config.toml
new file mode 100644
index 0000000..d42531f
--- /dev/null
+++ b/.cargo/config.toml
@@ -0,0 +1,5 @@
+[build]
+rustflags = ["-C", "target-cpu=native"]
+
+[target.x86_64-unknown-linux-gnu]
+rustflags = ["-C", "target-cpu=native", "-C", "link-arg=-fuse-ld=lld"]
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7ad650f..ad586db 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -32,3 +32,13 @@ jobs:
- run: cargo check --workspace
- run: cargo clippy --workspace --all-targets -- -D warnings
- run: cargo test --workspace
+ - name: Verify workspace version consistency
+ run: |
+ set -euo pipefail
+ VERSION="$(cargo metadata --no-deps --format-version 1 | jq -re '.packages[] | select(.name=="wallr") | .version')"
+ for crate in wallr wallr-common wallr-core; do
+ crate_version="$(cargo metadata --no-deps --format-version 1 | jq -re ".packages[] | select(.name==\"$crate\") | .version")"
+ test "$crate_version" = "$VERSION"
+ done
+ test "$VERSION" = "0.7.0"
+ grep -q "## \[0.7.0\]" CHANGELOG.md
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 058c803..3ed7bde 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -7,7 +7,7 @@ on:
workflow_dispatch:
inputs:
tag_name:
- description: 'Tag name for release (e.g. v0.6.4)'
+ description: 'Tag name for release (e.g. v0.7.0)'
required: false
type: string
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 62cb1d7..6d25d6e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,95 @@ All notable changes to Wallr are documented here.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and versions follow [Semantic Versioning](https://semver.org/).
+## [0.7.0] - 2026-10-19
+
+### Added
+
+- `wallr-common` now reports missing environment variables while expanding
+ configured paths instead of silently dropping them.
+- IPC sockets are now created with mode `0600`, guarded by an advisory
+ startup lock, and removed only when the daemon still owns the original
+ inode.
+- IPC requests, responses, handler execution, and client connections now have
+ timeouts; malformed or flooding clients can no longer stall the daemon.
+- GIF frame timing now aligns each graphic control extension with the next
+ image descriptor, including repeated or trailing extensions.
+- `wallr ipc seek` accepts `HH:MM:SS`, `MM:SS`, seconds, and fractional
+ seconds with overflow checks.
+- Regression tests cover IPC ownership, theme cache identity, duration
+ overflow, GIF timing, and video metadata bounds.
+
+### Changed
+
+- Theme providers, hooks, reload commands, config reload, and post-render
+ theme work now run on blocking workers instead of the Tokio runtime.
+- External theme/hook/reload commands are killed after bounded timeouts.
+- GIF decoding validates input size, frame count, screen dimensions, and frame
+ rectangles before allocating canvases or compositing.
+- Video metadata conversion and frame copying now reject malformed dimensions
+ and truncated planes instead of panicking.
+- `FrameScheduler` uses an offset-based clock so seeking beyond system uptime
+ cannot underflow.
+- IPC socket defaults now use `$XDG_RUNTIME_DIR/wallr.sock` consistently.
+- `DaemonConfig.auto_start` and `ThemeConfig.provider` now have serde
+ defaults that match their programmatic defaults.
+- Static wallpaper state paths are read and written as raw bytes, preserving
+ non-UTF-8 paths.
+- `wallr set -` stages stdin with a bounded read and private temp files.
+
+### Fixed
+
+- Duration parsing no longer panics for extreme finite values and no longer
+ truncates milliseconds during narrowing conversions.
+- Theme cache keys now include sub-second mtime, file size, and raw path
+ bytes, preventing collisions within one timestamp granularity and
+ non-UTF-8 aliasing.
+- GIF graphic control delays are no longer misaligned with image frames.
+- `wallr set` no longer invokes the removed `IpcCommand::Preview` variant.
+- `wallr config set` rejects unknown final config keys.
+- `wallr reload`, `monitor`, and `quit` propagate daemon failures instead of
+ ignoring them.
+- Wayland surface handles are documented and retained by `Arc` instead of
+ being leaked.
+- `FrameScheduler::seek` no longer underflows when the requested position
+ exceeds elapsed runtime.
+
+### Security/Hardening
+
+- IPC sockets are mode `0600` and validated as owned sockets before reuse.
+- Theme/hook/reload subprocesses have bounded runtimes.
+- GIF and video input limits bound memory before expensive allocations.
+- IPC concurrency is capped at 64 connections.
+- Client and server IPC operations are bounded by timeouts.
+- `wallr set -` limits stdin to 256 MiB.
+
+### Dependencies
+
+- Updated patch-level workspace dependencies reported by `cargo update
+ --dry-run`; lockfile remains reproducible.
+
+### Breaking Changes
+
+- `expand_path` now returns `Result`; callers must
+ handle missing environment variables.
+- `start_ipc_server` now requires an `IpcSocket` reservation through
+ `IpcSocket::acquire` for safe ownership.
+- `Daemon::new` accepts the same configuration; use `with_config_path` to
+ preserve an explicit config path.
+
+### Changed
+
+- MSRV bumped to 1.88; dependencies upgraded to latest compatible releases
+ (wgpu 30, smithay-client-toolkit 0.21, dirs 7, sha2 0.11, gif 0.14, zstd 0.14).
+- Release profile now uses fat LTO, `panic = "abort"`, disabled overflow checks,
+ and native CPU targeting via `.cargo/config.toml`.
+- `wallr` binary now uses `mimalloc` as its global allocator.
+
+### Performance
+
+- Hot paths continue to avoid redundant allocations and blocking the IPC loop;
+ release builds target maximum runtime performance.
+
## [0.6.4] - 2026-09-30
### Fixed
diff --git a/Cargo.lock b/Cargo.lock
index 42b3b3c..055025a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -17,6 +17,12 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
[[package]]
name = "android_system_properties"
version = "0.1.6"
@@ -62,7 +68,7 @@ version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys",
]
[[package]]
@@ -73,7 +79,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
- "windows-sys 0.61.2",
+ "windows-sys",
]
[[package]]
@@ -105,20 +111,19 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "bindgen"
-version = "0.72.1"
+version = "0.73.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
+checksum = "787ef8ef523575546b106a58213d6e6b06198a05c2f757258c68a74273670cfa"
dependencies = [
- "bitflags 2.13.2",
+ "bitflags",
"cexpr",
"clang-sys",
- "itertools",
"proc-macro2",
"quote",
"regex",
"rustc-hash 2.1.3",
- "shlex 1.3.0",
- "syn 2.0.119",
+ "shlex",
+ "syn 3.0.9",
]
[[package]]
@@ -127,7 +132,16 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
dependencies = [
- "bit-vec",
+ "bit-vec 0.8.0",
+]
+
+[[package]]
+name = "bit-set"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2f926cc3060f09db9ebc5b52823d85268d24bb917e472c0c4bea35780a7d"
+dependencies = [
+ "bit-vec 0.9.1",
]
[[package]]
@@ -137,33 +151,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
[[package]]
-name = "bitflags"
-version = "1.3.2"
+name = "bit-vec"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51"
[[package]]
name = "bitflags"
version = "2.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
-dependencies = [
- "serde_core",
-]
-
-[[package]]
-name = "block"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "block-buffer"
-version = "0.10.4"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
dependencies = [
- "generic-array",
+ "hybrid-array",
]
[[package]]
@@ -189,7 +194,7 @@ checksum = "6a1f896587b6f2c069c73d2f0913e2d590c3990285cd2f0b6aa02b786b4c679c"
dependencies = [
"proc-macro2",
"quote",
- "syn 3.0.5",
+ "syn 3.0.9",
]
[[package]]
@@ -206,40 +211,38 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
[[package]]
name = "calloop"
-version = "0.13.0"
+version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
+checksum = "43b32313e937c8721c9d17ee9bf60699a6402b4b7c2cb6ac1bee0ffcaa4b4e5e"
dependencies = [
- "bitflags 2.13.2",
- "log",
+ "bitflags",
"polling",
- "rustix 0.38.44",
- "slab",
- "thiserror 1.0.69",
+ "rustix",
+ "tracing",
]
[[package]]
name = "calloop-wayland-source"
-version = "0.3.0"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
+checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa"
dependencies = [
"calloop",
- "rustix 0.38.44",
+ "rustix",
"wayland-backend",
"wayland-client",
]
[[package]]
name = "cc"
-version = "1.4.6"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3eb0f42d6c360dc3f8a821f6bf2fdea7f72bfd36b3076eb0e6d1e9e0752fff4"
+checksum = "877bf67ac8e52449eb2f9e98a344ea163beb70dd1f9eebe3cc5357dcfeaee4df"
dependencies = [
"find-msvc-tools",
"jobserver",
"libc",
- "shlex 2.0.1",
+ "shlex",
]
[[package]]
@@ -253,9 +256,9 @@ dependencies = [
[[package]]
name = "cfg-if"
-version = "1.0.4"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
[[package]]
name = "cfg_aliases"
@@ -305,7 +308,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 3.0.5",
+ "syn 3.0.9",
]
[[package]]
@@ -321,7 +324,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
- "unicode-width",
+ "unicode-width 0.1.14",
+]
+
+[[package]]
+name = "codespan-reporting"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681"
+dependencies = [
+ "unicode-width 0.2.2",
]
[[package]]
@@ -342,7 +354,7 @@ version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys",
]
[[package]]
@@ -354,38 +366,11 @@ dependencies = [
"crossbeam-utils",
]
-[[package]]
-name = "core-foundation"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "core-foundation-sys"
-version = "0.8.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
-
-[[package]]
-name = "core-graphics-types"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
-dependencies = [
- "bitflags 1.3.2",
- "core-foundation",
- "libc",
-]
-
[[package]]
name = "cpufeatures"
-version = "0.2.17"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566"
dependencies = [
"libc",
]
@@ -414,14 +399,19 @@ version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
+[[package]]
+name = "crunchy"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
+
[[package]]
name = "crypto-common"
-version = "0.1.7"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
+checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
dependencies = [
- "generic-array",
- "typenum",
+ "hybrid-array",
]
[[package]]
@@ -432,9 +422,9 @@ checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
[[package]]
name = "digest"
-version = "0.10.7"
+version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
dependencies = [
"block-buffer",
"crypto-common",
@@ -442,9 +432,9 @@ dependencies = [
[[package]]
name = "dirs"
-version = "6.0.0"
+version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
+checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f"
dependencies = [
"dirs-sys",
]
@@ -458,7 +448,17 @@ dependencies = [
"libc",
"option-ext",
"redox_users",
- "windows-sys 0.61.2",
+ "windows-sys",
+]
+
+[[package]]
+name = "dispatch2"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
+dependencies = [
+ "bitflags",
+ "objc2",
]
[[package]]
@@ -485,17 +485,11 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
-[[package]]
-name = "either"
-version = "1.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
-
[[package]]
name = "equivalent"
-version = "1.0.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826"
[[package]]
name = "errno"
@@ -504,7 +498,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
- "windows-sys 0.61.2",
+ "windows-sys",
]
[[package]]
@@ -516,7 +510,7 @@ dependencies = [
"cfg-if",
"document-features",
"num-traits",
- "thiserror 2.0.20",
+ "thiserror",
]
[[package]]
@@ -540,16 +534,16 @@ version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6380599799e175191eb7ffe82c97f36a2a90a36cbc54c738a903e5287d7f516a"
dependencies = [
- "bitflags 2.13.2",
+ "bitflags",
"ffmpeg-sys-next",
"libc",
]
[[package]]
name = "ffmpeg-sys-next"
-version = "9.0.0"
+version = "9.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b939bf79dd5949412a4b81cfe21a07f48ea21b47fcbb5f57816c8c2de5ae30b"
+checksum = "c6f932d8c1cede016c65d4f1435f323369c99c74df55143b18676aa10e7603f9"
dependencies = [
"bindgen",
"cc",
@@ -561,9 +555,9 @@ dependencies = [
[[package]]
name = "find-msvc-tools"
-version = "0.1.12"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d"
+checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48"
[[package]]
name = "flate2"
@@ -578,36 +572,9 @@ dependencies = [
[[package]]
name = "foldhash"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
-
-[[package]]
-name = "foreign-types"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
-dependencies = [
- "foreign-types-macros",
- "foreign-types-shared",
-]
-
-[[package]]
-name = "foreign-types-macros"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 3.0.5",
-]
-
-[[package]]
-name = "foreign-types-shared"
-version = "0.3.1"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
+checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
name = "futures-core"
@@ -633,27 +600,6 @@ dependencies = [
"slab",
]
-[[package]]
-name = "generic-array"
-version = "0.14.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
-dependencies = [
- "typenum",
- "version_check",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
[[package]]
name = "getrandom"
version = "0.4.3"
@@ -665,16 +611,6 @@ dependencies = [
"r-efi",
]
-[[package]]
-name = "gif"
-version = "0.13.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
-dependencies = [
- "color_quant",
- "weezl",
-]
-
[[package]]
name = "gif"
version = "0.14.2"
@@ -704,9 +640,9 @@ checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b"
[[package]]
name = "glow"
-version = "0.16.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08"
+checksum = "29038e1c483364cc6bb3cf78feee1816002e127c331a1eec55a4d202b9e1adb5"
dependencies = [
"js-sys",
"slotmap",
@@ -724,50 +660,38 @@ dependencies = [
]
[[package]]
-name = "gpu-alloc"
-version = "0.6.2"
+name = "gpu-allocator"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45cf04b2726f02df5508c6de726acdc90cdf97ac771a9a0ffd8ba10a6e696bf9"
+checksum = "51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795"
dependencies = [
- "bitflags 2.13.2",
- "gpu-alloc-types",
-]
-
-[[package]]
-name = "gpu-alloc-types"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2bbed164dd10ed526c2e4fe3e721ca4a71c61730e5aafac6844b417b3227058"
-dependencies = [
- "bitflags 2.13.2",
-]
-
-[[package]]
-name = "gpu-descriptor"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca"
-dependencies = [
- "bitflags 2.13.2",
- "gpu-descriptor-types",
- "hashbrown 0.15.5",
+ "ash",
+ "hashbrown 0.16.1",
+ "log",
+ "presser",
+ "thiserror",
]
[[package]]
-name = "gpu-descriptor-types"
-version = "0.2.0"
+name = "half"
+version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91"
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
dependencies = [
- "bitflags 2.13.2",
+ "cfg-if",
+ "crunchy",
+ "num-traits",
+ "zerocopy",
]
[[package]]
name = "hashbrown"
-version = "0.15.5"
+version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
dependencies = [
+ "allocator-api2",
+ "equivalent",
"foldhash",
]
@@ -776,6 +700,9 @@ name = "hashbrown"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
+dependencies = [
+ "foldhash",
+]
[[package]]
name = "heck"
@@ -801,6 +728,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
+[[package]]
+name = "hybrid-array"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17"
+dependencies = [
+ "typenum",
+]
+
[[package]]
name = "image"
version = "0.25.10"
@@ -810,7 +746,7 @@ dependencies = [
"bytemuck",
"byteorder-lite",
"color_quant",
- "gif 0.14.2",
+ "gif",
"image-webp",
"moxcms",
"num-traits",
@@ -845,15 +781,6 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
-[[package]]
-name = "itertools"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
-dependencies = [
- "either",
-]
-
[[package]]
name = "itoa"
version = "1.0.18"
@@ -894,15 +821,15 @@ version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3"
dependencies = [
- "getrandom 0.4.3",
+ "getrandom",
"libc",
]
[[package]]
name = "js-sys"
-version = "0.3.105"
+version = "0.3.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e"
+checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5"
dependencies = [
"cfg-if",
"futures-util",
@@ -928,9 +855,9 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "lazy_static"
-version = "1.5.0"
+version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb"
[[package]]
name = "libc"
@@ -949,19 +876,28 @@ dependencies = [
]
[[package]]
-name = "libredox"
-version = "0.1.24"
+name = "libm"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
+
+[[package]]
+name = "libmimalloc-sys"
+version = "0.1.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6480ccc157a1389bb2e4891b24751b0f798ba640d22386f23143fbcc89da195a"
+checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9"
dependencies = [
- "libc",
+ "cc",
]
[[package]]
-name = "linux-raw-sys"
-version = "0.4.15"
+name = "libredox"
+version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
+checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d"
+dependencies = [
+ "libc",
+]
[[package]]
name = "linux-raw-sys"
@@ -971,9 +907,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "litrs"
-version = "1.0.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
+checksum = "4744e383959f0db86ede514b809b1c53251889093803c05267acc7d4e7030d70"
[[package]]
name = "lock_api"
@@ -990,15 +926,6 @@ version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
-[[package]]
-name = "malloc_buf"
-version = "0.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
-dependencies = [
- "libc",
-]
-
[[package]]
name = "matchers"
version = "0.2.0"
@@ -1024,18 +951,12 @@ dependencies = [
]
[[package]]
-name = "metal"
-version = "0.31.0"
+name = "mimalloc"
+version = "0.1.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e"
+checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862"
dependencies = [
- "bitflags 2.13.2",
- "block",
- "core-graphics-types",
- "foreign-types",
- "log",
- "objc",
- "paste",
+ "libmimalloc-sys",
]
[[package]]
@@ -1066,13 +987,13 @@ dependencies = [
[[package]]
name = "mio"
-version = "1.2.3"
+version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8"
+checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee"
dependencies = [
"libc",
"wasi",
- "windows-sys 0.61.2",
+ "windows-sys",
]
[[package]]
@@ -1092,26 +1013,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e"
dependencies = [
"arrayvec",
- "bit-set",
- "bitflags 2.13.2",
+ "bit-set 0.8.0",
+ "bitflags",
"cfg_aliases",
- "codespan-reporting",
+ "codespan-reporting 0.11.1",
"hexf-parse",
"indexmap",
"log",
"rustc-hash 1.1.0",
- "spirv",
"strum",
"termcolor",
- "thiserror 2.0.20",
+ "thiserror",
"unicode-xid",
]
+[[package]]
+name = "naga"
+version = "30.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a616d2fb8c89516ac2723a581f69d6c18576046bed761bd6b305e5618e6ae130"
+dependencies = [
+ "arrayvec",
+ "bit-set 0.10.0",
+ "bitflags",
+ "cfg-if",
+ "cfg_aliases",
+ "codespan-reporting 0.13.1",
+ "half",
+ "hashbrown 0.17.1",
+ "indexmap",
+ "libm",
+ "log",
+ "naga-types",
+ "num-traits",
+ "once_cell",
+ "rustc-hash 1.1.0",
+ "spirv",
+ "thiserror",
+ "unicode-ident",
+]
+
+[[package]]
+name = "naga-types"
+version = "30.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "590afbf58a6f4f62873cd5cff4468061844bafa1cdf399cc954537c22d768d49"
+dependencies = [
+ "hashbrown 0.17.1",
+ "indexmap",
+ "rustc-hash 1.1.0",
+ "thiserror",
+]
+
[[package]]
name = "ndk-sys"
-version = "0.5.0+25.2.9519653"
+version = "0.6.0+11769913"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691"
+checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
dependencies = [
"jni-sys 0.3.1",
]
@@ -1132,7 +1090,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys",
]
[[package]]
@@ -1142,6 +1100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
+ "libm",
]
[[package]]
@@ -1155,12 +1114,64 @@ dependencies = [
]
[[package]]
-name = "objc"
-version = "0.2.7"
+name = "objc2"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
+dependencies = [
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-core-foundation"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
+checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
dependencies = [
- "malloc_buf",
+ "bitflags",
+ "dispatch2",
+ "objc2",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
+
+[[package]]
+name = "objc2-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-core-foundation",
+]
+
+[[package]]
+name = "objc2-metal"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-quartz-core"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
+dependencies = [
+ "bitflags",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-foundation",
+ "objc2-metal",
]
[[package]]
@@ -1183,9 +1194,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "ordered-float"
-version = "4.6.0"
+version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951"
+checksum = "c860fd3227ca4ac3cc032e2cd20cba3f02ccdf4b610538f8ee6584d56bb62e96"
dependencies = [
"num-traits",
]
@@ -1213,12 +1224,6 @@ dependencies = [
"windows-link",
]
-[[package]]
-name = "paste"
-version = "1.0.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
-
[[package]]
name = "pin-project-lite"
version = "0.2.17"
@@ -1237,7 +1242,7 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
dependencies = [
- "bitflags 2.13.2",
+ "bitflags",
"crc32fast",
"fdeflate",
"flate2",
@@ -1254,10 +1259,31 @@ dependencies = [
"concurrent-queue",
"hermit-abi",
"pin-project-lite",
- "rustix 1.1.4",
- "windows-sys 0.61.2",
+ "rustix",
+ "windows-sys",
]
+[[package]]
+name = "portable-atomic"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
+
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
+name = "presser"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa"
+
[[package]]
name = "proc-macro2"
version = "1.0.107"
@@ -1315,24 +1341,35 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
+[[package]]
+name = "raw-window-metal"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135"
+dependencies = [
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-foundation",
+ "objc2-quartz-core",
+]
+
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
- "bitflags 2.13.2",
+ "bitflags",
]
[[package]]
name = "redox_users"
-version = "0.5.2"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
+checksum = "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0"
dependencies = [
- "getrandom 0.2.17",
"libredox",
- "thiserror 2.0.20",
+ "thiserror",
]
[[package]]
@@ -1384,28 +1421,15 @@ checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
[[package]]
name = "rustix"
-version = "0.38.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
-dependencies = [
- "bitflags 2.13.2",
- "errno",
- "libc",
- "linux-raw-sys 0.4.15",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "rustix"
-version = "1.1.4"
+version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
+checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d"
dependencies = [
- "bitflags 2.13.2",
+ "bitflags",
"errno",
"libc",
- "linux-raw-sys 0.12.1",
- "windows-sys 0.61.2",
+ "linux-raw-sys",
+ "windows-sys",
]
[[package]]
@@ -1459,14 +1483,14 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
- "syn 3.0.5",
+ "syn 3.0.9",
]
[[package]]
name = "serde_json"
-version = "1.0.151"
+version = "1.0.154"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
+checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6"
dependencies = [
"itoa",
"memchr",
@@ -1490,9 +1514,9 @@ dependencies = [
[[package]]
name = "sha2"
-version = "0.10.9"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
+checksum = "47d7069beb7d6ac7b9acd1039986e73443f24234f41074da099d6f994ac9ad19"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -1508,12 +1532,6 @@ dependencies = [
"lazy_static",
]
-[[package]]
-name = "shlex"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
-
[[package]]
name = "shlex"
version = "2.0.1"
@@ -1553,30 +1571,30 @@ dependencies = [
[[package]]
name = "smallvec"
-version = "1.16.1"
+version = "1.16.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891"
+checksum = "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b"
[[package]]
name = "smithay-client-toolkit"
-version = "0.19.2"
+version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
+checksum = "74dc9ee14b0fdcb535f9556141bacac070c994a977d2240ee455d7438a617f00"
dependencies = [
- "bitflags 2.13.2",
+ "bitflags",
"calloop",
"calloop-wayland-source",
"cursor-icon",
- "libc",
"log",
"memmap2",
- "rustix 0.38.44",
- "thiserror 1.0.69",
- "wayland-backend",
+ "rustix",
+ "thiserror",
"wayland-client",
"wayland-csd-frame",
"wayland-cursor",
"wayland-protocols",
+ "wayland-protocols-experimental",
+ "wayland-protocols-misc",
"wayland-protocols-wlr",
"wayland-scanner",
"xkeysym",
@@ -1589,16 +1607,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
dependencies = [
"libc",
- "windows-sys 0.61.2",
+ "windows-sys",
]
[[package]]
name = "spirv"
-version = "0.3.0+sdk-1.3.268.0"
+version = "0.4.0+sdk-1.4.341.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
+checksum = "d9571ea910ebd84c86af4b3ed27f9dbdc6ad06f17c5f96146b2b671e2976744f"
dependencies = [
- "bitflags 2.13.2",
+ "bitflags",
]
[[package]]
@@ -1648,9 +1666,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "3.0.5"
+version = "3.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9"
+checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
dependencies = [
"proc-macro2",
"quote",
@@ -1664,10 +1682,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [
"fastrand",
- "getrandom 0.4.3",
+ "getrandom",
"once_cell",
- "rustix 1.1.4",
- "windows-sys 0.61.2",
+ "rustix",
+ "windows-sys",
]
[[package]]
@@ -1681,42 +1699,22 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.69"
+version = "2.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e"
dependencies = [
- "thiserror-impl 1.0.69",
-]
-
-[[package]]
-name = "thiserror"
-version = "2.0.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f"
-dependencies = [
- "thiserror-impl 2.0.20",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.119",
+ "thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "2.0.20"
+version = "2.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
+checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"
dependencies = [
"proc-macro2",
"quote",
- "syn 3.0.5",
+ "syn 3.0.9",
]
[[package]]
@@ -1730,9 +1728,9 @@ dependencies = [
[[package]]
name = "tokio"
-version = "1.53.1"
+version = "1.53.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
+checksum = "ce3335fa71841cda333a58d7615b03901380ecf09d59b3296d21f8bbac0dde4e"
dependencies = [
"bytes",
"libc",
@@ -1741,7 +1739,7 @@ dependencies = [
"signal-hook-registry",
"socket2",
"tokio-macros",
- "windows-sys 0.61.2",
+ "windows-sys",
]
[[package]]
@@ -1752,7 +1750,7 @@ checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e"
dependencies = [
"proc-macro2",
"quote",
- "syn 3.0.5",
+ "syn 3.0.9",
]
[[package]]
@@ -1761,6 +1759,7 @@ version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
+ "log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@@ -1810,9 +1809,9 @@ checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
[[package]]
name = "unicode-ident"
-version = "1.0.24"
+version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
[[package]]
name = "unicode-width"
@@ -1820,6 +1819,12 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+[[package]]
+name = "unicode-width"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
+
[[package]]
name = "unicode-xid"
version = "0.2.6"
@@ -1852,11 +1857,12 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wallr"
-version = "0.6.4"
+version = "0.7.0"
dependencies = [
"anyhow",
"clap",
"colored",
+ "mimalloc",
"serde_yaml",
"tokio",
"tracing",
@@ -1867,18 +1873,18 @@ dependencies = [
[[package]]
name = "wallr-common"
-version = "0.6.4"
+version = "0.7.0"
dependencies = [
"bytemuck",
"clap",
"serde",
"serde_yaml",
- "thiserror 2.0.20",
+ "thiserror",
]
[[package]]
name = "wallr-core"
-version = "0.6.4"
+version = "0.7.0"
dependencies = [
"anyhow",
"bytemuck",
@@ -1887,11 +1893,11 @@ dependencies = [
"dirs",
"fast_image_resize",
"ffmpeg-next",
- "gif 0.13.3",
+ "gif",
"hex",
"image",
"libc",
- "naga",
+ "naga 24.0.0",
"raw-window-handle",
"serde",
"serde_json",
@@ -1899,7 +1905,7 @@ dependencies = [
"sha2",
"smithay-client-toolkit",
"tempfile",
- "thiserror 2.0.20",
+ "thiserror",
"tokio",
"tracing",
"wallr-common",
@@ -1918,9 +1924,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasm-bindgen"
-version = "0.2.128"
+version = "0.2.129"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf"
+checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409"
dependencies = [
"cfg-if",
"once_cell",
@@ -1929,21 +1935,11 @@ dependencies = [
"wasm-bindgen-shared",
]
-[[package]]
-name = "wasm-bindgen-futures"
-version = "0.4.78"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ef4c5d3d2cdf5c54f4231181768f5510842e350db025faf1f7163b1030ed928"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.128"
+version = "0.2.129"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed"
+checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1951,22 +1947,22 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.128"
+version = "0.2.129"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a"
+checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
- "syn 3.0.5",
+ "syn 3.0.9",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.128"
+version = "0.2.129"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e"
+checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6"
dependencies = [
"unicode-ident",
]
@@ -1979,7 +1975,7 @@ checksum = "38a91b4eaddff87b1cd1074985e3713da4af2c49742d1b356b2c01670a67a078"
dependencies = [
"cc",
"downcast-rs",
- "rustix 1.1.4",
+ "rustix",
"scoped-tls",
"smallvec",
"wayland-sys",
@@ -1991,8 +1987,8 @@ version = "0.31.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c36a0f861ad76d0901f2800b46321410d9f73f2ea88aac0650d86c32688073"
dependencies = [
- "bitflags 2.13.2",
- "rustix 1.1.4",
+ "bitflags",
+ "rustix",
"wayland-backend",
"wayland-scanner",
]
@@ -2003,7 +1999,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
dependencies = [
- "bitflags 2.13.2",
+ "bitflags",
"cursor-icon",
"wayland-backend",
]
@@ -2014,7 +2010,7 @@ version = "0.31.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d"
dependencies = [
- "rustix 1.1.4",
+ "rustix",
"wayland-client",
"xcursor",
]
@@ -2025,9 +2021,35 @@ version = "0.32.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6"
dependencies = [
- "bitflags 2.13.2",
+ "bitflags",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols-experimental"
+version = "20251230.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91c6c3e7178e553d093d46999032bc79aafea9dedd71dd702c8ace7bbc25cf13"
+dependencies = [
+ "bitflags",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols-misc"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e9567599ef23e09b8dad6e429e5738d4509dfc46b3b21f32841a304d16b29c8"
+dependencies = [
+ "bitflags",
"wayland-backend",
"wayland-client",
+ "wayland-protocols",
"wayland-scanner",
]
@@ -2037,7 +2059,7 @@ version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234"
dependencies = [
- "bitflags 2.13.2",
+ "bitflags",
"wayland-backend",
"wayland-client",
"wayland-protocols",
@@ -2063,14 +2085,15 @@ checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be"
dependencies = [
"dlib",
"log",
+ "once_cell",
"pkg-config",
]
[[package]]
name = "web-sys"
-version = "0.3.105"
+version = "0.3.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fbddc4a036f00ec4f18c83445bd3115cb306a91da554919a099d9222fe4a7f8"
+checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -2084,24 +2107,23 @@ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
[[package]]
name = "wgpu"
-version = "24.0.5"
+version = "30.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b0b3436f0729f6cdf2e6e9201f3d39dc95813fad61d826c1ed07918b4539353"
+checksum = "527ccdf43dd5b2e8676eed9984ce00e2bbb0a1b85b70c1969dcb6cd2eb55ab9e"
dependencies = [
"arrayvec",
- "bitflags 2.13.2",
+ "bitflags",
+ "bytemuck",
+ "cfg-if",
"cfg_aliases",
"document-features",
- "js-sys",
+ "hashbrown 0.17.1",
"log",
- "parking_lot",
+ "portable-atomic",
"profiling",
"raw-window-handle",
"smallvec",
"static_assertions",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
"wgpu-core",
"wgpu-hal",
"wgpu-types",
@@ -2109,79 +2131,124 @@ dependencies = [
[[package]]
name = "wgpu-core"
-version = "24.0.5"
+version = "30.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f0aa306497a238d169b9dc70659105b4a096859a34894544ca81719242e1499"
+checksum = "14c018fce9b6270aa203c2fdd56f3cce996713534bd757e4ea58c8560b121f14"
dependencies = [
"arrayvec",
- "bit-vec",
- "bitflags 2.13.2",
+ "bit-set 0.10.0",
+ "bit-vec 0.9.1",
+ "bitflags",
+ "bytemuck",
"cfg_aliases",
"document-features",
+ "hashbrown 0.17.1",
"indexmap",
"log",
- "naga",
+ "naga 30.0.1",
+ "naga-types",
"once_cell",
"parking_lot",
+ "portable-atomic",
"profiling",
"raw-window-handle",
"rustc-hash 1.1.0",
"smallvec",
- "thiserror 2.0.20",
+ "thiserror",
+ "wgpu-core-deps-emscripten",
+ "wgpu-core-deps-windows-linux-android",
"wgpu-hal",
+ "wgpu-naga-bridge",
"wgpu-types",
]
+[[package]]
+name = "wgpu-core-deps-emscripten"
+version = "30.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d98b86cf4abf524a902dd35f18ca6a3f08fc2ae9847c8f10b48e30491b1f0b86"
+dependencies = [
+ "wgpu-hal",
+]
+
+[[package]]
+name = "wgpu-core-deps-windows-linux-android"
+version = "30.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7586165fd5f6d881cb9ce4bb71f40d6caab2c0f1837e3fc1d9788a197fb6004f"
+dependencies = [
+ "wgpu-hal",
+]
+
[[package]]
name = "wgpu-hal"
-version = "24.0.4"
+version = "30.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259"
+checksum = "b6b7fb58561a792bc237628ba0792e332de418fefe145f13b5ed8201e6d52f58"
dependencies = [
"android_system_properties",
"arrayvec",
"ash",
- "bitflags 2.13.2",
+ "bitflags",
"bytemuck",
+ "cfg-if",
"cfg_aliases",
- "core-graphics-types",
"glow",
"glutin_wgl_sys",
- "gpu-alloc",
- "gpu-descriptor",
+ "gpu-allocator",
+ "hashbrown 0.17.1",
"js-sys",
"khronos-egl",
"libc",
"libloading",
"log",
- "metal",
- "naga",
+ "naga 30.0.1",
+ "naga-types",
"ndk-sys",
- "objc",
- "once_cell",
+ "objc2",
"ordered-float",
"parking_lot",
+ "portable-atomic",
+ "portable-atomic-util",
"profiling",
"raw-window-handle",
+ "raw-window-metal",
"renderdoc-sys",
- "rustc-hash 1.1.0",
"smallvec",
- "thiserror 2.0.20",
+ "static_assertions",
+ "thiserror",
"wasm-bindgen",
+ "wayland-sys",
"web-sys",
+ "wgpu-naga-bridge",
"wgpu-types",
"windows",
+ "windows-result",
+]
+
+[[package]]
+name = "wgpu-naga-bridge"
+version = "30.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2f62e73117bb7a62bfd9c5a5841438a823f6566c6442a808ee269d2d055c081"
+dependencies = [
+ "naga 30.0.1",
+ "wgpu-types",
]
[[package]]
name = "wgpu-types"
-version = "24.0.0"
+version = "30.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c"
+checksum = "99dad6f1fbdbbdb4c278a6508b059d44688f5cebddf78d005a46a31340269286"
dependencies = [
- "bitflags 2.13.2",
+ "bitflags",
+ "bytemuck",
"js-sys",
"log",
+ "naga-types",
+ "raw-window-handle",
+ "static_assertions",
"web-sys",
]
@@ -2191,37 +2258,59 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
- "windows-sys 0.61.2",
+ "windows-sys",
]
[[package]]
name = "windows"
-version = "0.58.0"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
+dependencies = [
+ "windows-collections",
+ "windows-core",
+ "windows-future",
+ "windows-numerics",
+]
+
+[[package]]
+name = "windows-collections"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
+checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
dependencies = [
"windows-core",
- "windows-targets",
]
[[package]]
name = "windows-core"
-version = "0.58.0"
+version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
+ "windows-link",
"windows-result",
"windows-strings",
- "windows-targets",
+]
+
+[[package]]
+name = "windows-future"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
+dependencies = [
+ "windows-core",
+ "windows-link",
+ "windows-threading",
]
[[package]]
name = "windows-implement"
-version = "0.58.0"
+version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
@@ -2230,9 +2319,9 @@ dependencies = [
[[package]]
name = "windows-interface"
-version = "0.58.0"
+version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
@@ -2246,31 +2335,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
-name = "windows-result"
-version = "0.2.0"
+name = "windows-numerics"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
+checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
dependencies = [
- "windows-targets",
+ "windows-core",
+ "windows-link",
]
[[package]]
-name = "windows-strings"
-version = "0.1.0"
+name = "windows-result"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
- "windows-result",
- "windows-targets",
+ "windows-link",
]
[[package]]
-name = "windows-sys"
-version = "0.59.0"
+name = "windows-strings"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
- "windows-targets",
+ "windows-link",
]
[[package]]
@@ -2283,69 +2372,14 @@ dependencies = [
]
[[package]]
-name = "windows-targets"
-version = "0.52.6"
+name = "windows-threading"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows-link",
]
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
[[package]]
name = "xcursor"
version = "0.3.11"
@@ -2364,6 +2398,26 @@ version = "0.8.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7"
+[[package]]
+name = "zerocopy"
+version = "0.8.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
[[package]]
name = "zlib-rs"
version = "0.6.8"
@@ -2378,27 +2432,27 @@ checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
[[package]]
name = "zstd"
-version = "0.13.3"
+version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
+checksum = "db3ae9bf90af6e40197bef767eeefc46ad6397420fe873830bd85e5fbbfb3c70"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
-version = "7.3.0"
+version = "8.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882"
+checksum = "ded520f16b29e1a9b771c722221b2b0a0398c2316d9bb3c42b458a5414d7434b"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
-version = "2.1.0+zstd.1.5.7"
+version = "2.1.2+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ef0a8027ec3ee71300ab3bcbcd0393f434aa72b91ca6d635a39941deae8eea0"
+checksum = "481ada9c543b2323cbb7bbdbb5249177fbf0188ed959ed2c15e4b22421c84ed3"
dependencies = [
"cc",
"pkg-config",
diff --git a/Cargo.toml b/Cargo.toml
index 55df1bb..b8e385b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,9 +1,9 @@
[workspace]
members = ["wallr", "wallr-common", "wallr-core"]
-resolver = "2"
+resolver = "3"
[workspace.package]
-version = "0.6.4"
+version = "0.7.0"
edition = "2024"
authors = ["Wallr Contributors"]
license = "MIT"
@@ -11,7 +11,7 @@ repository = "https://github.com/programmersd21/wallr"
description = "The wallpaper engine for Wayland - GPU transitions, video wallpapers, and theme pipeline integration."
categories = ["command-line-utilities", "rendering"]
keywords = ["wallpaper", "wayland", "wgpu", "daemon", "matugen"]
-rust-version = "1.85"
+rust-version = "1.88"
# Optimized profile settings for faster compilation and better runtime performance
[profile.dev]
@@ -21,9 +21,11 @@ incremental = true # Enable incremental compilation
[profile.release]
opt-level = 3 # Full optimizations
-lto = "thin" # Thin LTO for faster linking with good optimization
+lto = "fat" # Fat LTO for maximum runtime optimization
codegen-units = 1 # Better optimization, slower compile (worth it for release)
strip = true # Strip symbols for smaller binary
+panic = "abort" # Smaller/faster, no unwinding in release
+overflow-checks = false
debug = false # No debug info in release
[profile.release-with-debug]
@@ -36,8 +38,8 @@ strip = false
opt-level = 2 # Optimize dependencies even in dev mode
[workspace.dependencies]
-wallr-common = { path = "wallr-common", version = "0.6.4" }
-wallr-core = { path = "wallr-core", version = "0.6.4" }
+wallr-common = { path = "wallr-common", version = "0.7.0" }
+wallr-core = { path = "wallr-core", version = "0.7.0" }
# Core utilities
anyhow = "1"
@@ -81,22 +83,22 @@ image = { version = "0.25", default-features = false, features = [
fast_image_resize = "6"
# Graphics
-wgpu = { version = "24", default-features = false, features = ["wgsl"] }
+wgpu = { version = "30", default-features = false, features = ["wgsl", "vulkan", "gles"] }
raw-window-handle = "0.6"
# Wayland
wayland-client = "0.31"
wayland-protocols = { version = "0.32", features = ["client"] }
-smithay-client-toolkit = { version = "0.19", default-features = false, features = [
+smithay-client-toolkit = { version = "0.21", default-features = false, features = [
"calloop",
] }
wayland-backend = { version = "0.3", features = ["client_system"] }
# File operations
-dirs = "6"
+dirs = "7"
# Crypto & utilities
-sha2 = { version = "0.10", default-features = false }
+sha2 = { version = "0.11", default-features = false }
hex = "0.4"
# Video support
diff --git a/README.md b/README.md
index d81b0af..534ff6c 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ GPU-accelerated wallpaper engine for Wayland, rendered natively with `wgpu` on `
-
+
diff --git a/wallr-common/src/cli.rs b/wallr-common/src/cli.rs
index 6792de9..50f6b06 100644
--- a/wallr-common/src/cli.rs
+++ b/wallr-common/src/cli.rs
@@ -117,6 +117,64 @@ fn parse_vec2(s: &str) -> Option<[f32; 2]> {
Some([x, y])
}
+/// Parse an IPC seek timestamp into milliseconds.
+///
+/// Accepts `SS`, `MM:SS`, or `HH:MM:SS` with optional fractional seconds for
+/// the bare-seconds form. Rejects non-finite, negative, and overflowing input
+/// instead of saturating or wrapping through a cast.
+pub fn parse_timestamp_ms(timestamp: &str) -> Result {
+ let timestamp = timestamp.trim();
+ if timestamp.is_empty() {
+ return Err("timestamp cannot be empty".to_string());
+ }
+ if timestamp.contains(':') {
+ let parts: Vec<&str> = timestamp.split(':').collect();
+ if !matches!(parts.len(), 2 | 3) {
+ return Err("invalid timestamp format. Use HH:MM:SS or seconds".to_string());
+ }
+ let mut values = Vec::with_capacity(parts.len());
+ for part in &parts {
+ let value: u64 = part
+ .parse()
+ .map_err(|_| format!("invalid timestamp component: {part}"))?;
+ values.push(value);
+ }
+ let seconds = if values.len() == 3 {
+ if values[1] >= 60 || values[2] >= 60 {
+ return Err("minutes and seconds must be below 60".to_string());
+ }
+ values[0]
+ .checked_mul(3600)
+ .and_then(|v| v.checked_add(values[1] * 60))
+ .and_then(|v| v.checked_add(values[2]))
+ .ok_or_else(|| "timestamp overflows".to_string())?
+ } else {
+ if values[1] >= 60 {
+ return Err("seconds must be below 60".to_string());
+ }
+ values[0]
+ .checked_mul(60)
+ .and_then(|v| v.checked_add(values[1]))
+ .ok_or_else(|| "timestamp overflows".to_string())?
+ };
+ seconds
+ .checked_mul(1000)
+ .ok_or_else(|| "timestamp overflows".to_string())
+ } else {
+ let seconds: f64 = timestamp
+ .parse()
+ .map_err(|_| format!("invalid timestamp: {timestamp}"))?;
+ if !seconds.is_finite() || seconds < 0.0 {
+ return Err("timestamp must be a finite non-negative number".to_string());
+ }
+ let millis = (seconds * 1000.0).round();
+ if millis > u64::MAX as f64 {
+ return Err("timestamp overflows".to_string());
+ }
+ Ok(millis as u64)
+ }
+}
+
#[derive(Parser, Debug)]
#[command(
name = "wallr",
@@ -238,8 +296,6 @@ pub enum IpcCommands {
},
/// Re-render current wallpaper
Reload,
- /// Trigger preview transition
- Preview,
/// Shut down the daemon
Stop,
/// Query daemon status
@@ -275,3 +331,24 @@ pub enum IpcCommands {
effect_args: EffectArgs,
},
}
+
+#[cfg(test)]
+mod tests {
+ use super::parse_timestamp_ms;
+
+ #[test]
+ fn parses_seek_timestamps() {
+ assert_eq!(parse_timestamp_ms("0").unwrap(), 0);
+ assert_eq!(parse_timestamp_ms("90").unwrap(), 90_000);
+ assert_eq!(parse_timestamp_ms("1.5").unwrap(), 1_500);
+ assert_eq!(parse_timestamp_ms("01:30").unwrap(), 90_000);
+ assert_eq!(parse_timestamp_ms("01:02:03").unwrap(), 3_723_000);
+ }
+
+ #[test]
+ fn rejects_invalid_seek_timestamps() {
+ for value in ["", "-1", "NaN", "inf", "1e300", "1:60", "1:2:60", "1:2:3:4"] {
+ assert!(parse_timestamp_ms(value).is_err(), "{value} should fail");
+ }
+ }
+}
diff --git a/wallr-common/src/config.rs b/wallr-common/src/config.rs
index 13da9fe..a04b97c 100644
--- a/wallr-common/src/config.rs
+++ b/wallr-common/src/config.rs
@@ -83,7 +83,7 @@ pub struct MonitorConfig {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThemeConfig {
- #[serde(default)]
+ #[serde(default = "default_theme_provider")]
pub provider: ThemeProvider,
}
@@ -136,7 +136,7 @@ pub struct HooksConfig {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DaemonConfig {
- #[serde(default)]
+ #[serde(default = "default_true")]
pub auto_start: bool,
#[serde(default = "default_socket")]
pub socket: String,
@@ -167,8 +167,12 @@ fn default_mode() -> String {
fn default_scheme() -> String {
"scheme-tonal-spot".to_string()
}
+fn default_theme_provider() -> ThemeProvider {
+ ThemeProvider::Matugen
+}
+
fn default_socket() -> String {
- "/tmp/wallr.sock".to_string()
+ "$XDG_RUNTIME_DIR/wallr.sock".to_string()
}
#[derive(Debug, thiserror::Error)]
@@ -181,16 +185,27 @@ pub enum ConfigError {
InvalidDuration(String),
#[error("invalid config value: {0}")]
InvalidValue(String),
+ #[error("environment variable {0} is not set")]
+ UnsetEnv(String),
}
pub fn load_config(path: Option<&Path>) -> Result {
- let p = path.map(|p| p.to_path_buf()).unwrap_or_else(config_path);
- if !p.exists() {
- return Ok(apply_environment_overrides(WallrConfig::default()));
+ match path {
+ Some(path) => {
+ let content = std::fs::read_to_string(path)?;
+ let config: WallrConfig = serde_yaml::from_str(&content)?;
+ Ok(apply_environment_overrides(config))
+ }
+ None => {
+ let path = config_path();
+ if !path.exists() {
+ return Ok(apply_environment_overrides(WallrConfig::default()));
+ }
+ let content = std::fs::read_to_string(path)?;
+ let config: WallrConfig = serde_yaml::from_str(&content)?;
+ Ok(apply_environment_overrides(config))
+ }
}
- let content = std::fs::read_to_string(p)?;
- let config: WallrConfig = serde_yaml::from_str(&content)?;
- Ok(apply_environment_overrides(config))
}
/// Applies process-scoped overrides used by launchers and isolated benchmarks.
@@ -205,42 +220,75 @@ fn apply_environment_overrides(mut config: WallrConfig) -> WallrConfig {
config
}
-pub fn expand_path(path: &str) -> PathBuf {
+/// Expands a leading `~`, `$VAR`, and `${VAR}` in a configured path.
+///
+/// Referencing a variable that is not set is an error instead of silently
+/// deleting the reference: dropping `$XDG_RUNTIME_DIR` from a socket path
+/// used to turn `/run/user/1000/wallr.sock` into `/wallr.sock`, which either
+/// failed with a confusing permission error or connected to the wrong path.
+pub fn expand_path(path: &str) -> Result {
let mut path_str = path.to_string();
- if (path_str.starts_with("~/") || path_str == "~")
- && let Ok(home) = std::env::var("HOME")
- {
- if path_str == "~" {
- path_str = home;
+ if path_str == "~" || path_str.starts_with("~/") {
+ let home = std::env::var("HOME").map_err(|_| ConfigError::UnsetEnv("HOME".into()))?;
+ path_str = if path_str == "~" {
+ home
} else {
- path_str = path_str.replacen("~", &home, 1);
- }
+ path_str.replacen('~', &home, 1)
+ };
}
let mut expanded = String::new();
let mut chars = path_str.chars().peekable();
while let Some(c) = chars.next() {
- if c == '$' {
- let mut env_var = String::new();
+ if c != '$' {
+ expanded.push(c);
+ continue;
+ }
+
+ let mut env_var = String::new();
+ if chars.peek() == Some(&'{') {
+ chars.next();
+ let mut closed = false;
+ for next_c in chars.by_ref() {
+ if next_c == '}' {
+ closed = true;
+ break;
+ }
+ if !(next_c.is_ascii_alphanumeric() || next_c == '_') {
+ return Err(ConfigError::InvalidValue(format!(
+ "invalid environment variable reference near '${{{env_var}{next_c}'"
+ )));
+ }
+ env_var.push(next_c);
+ }
+ if !closed || env_var.is_empty() {
+ return Err(ConfigError::InvalidValue(
+ "unterminated or empty ${...} environment variable reference".into(),
+ ));
+ }
+ } else {
while let Some(&next_c) = chars.peek() {
- if next_c.is_alphanumeric() || next_c == '_' {
+ if next_c.is_ascii_alphanumeric() || next_c == '_' {
env_var.push(next_c);
chars.next();
} else {
break;
}
}
- if let Ok(val) = std::env::var(&env_var) {
- expanded.push_str(&val);
+ if env_var.is_empty() {
+ // A literal `$` (including `$$`) is not an environment reference.
+ expanded.push('$');
+ continue;
}
- } else {
- expanded.push(c);
}
+
+ let value = std::env::var(&env_var).map_err(|_| ConfigError::UnsetEnv(env_var))?;
+ expanded.push_str(&value);
}
- PathBuf::from(expanded)
+ Ok(PathBuf::from(expanded))
}
pub fn config_path() -> PathBuf {
@@ -273,7 +321,10 @@ pub fn parse_duration(s: &str) -> Result {
if !val.is_finite() || val < 0.0 {
return Err(ConfigError::InvalidDuration(s.to_string()));
}
- Ok(std::time::Duration::from_secs_f64(val))
+ // `from_secs_f64` panics when the value exceeds `Duration::MAX`;
+ // malformed or hostile config must produce an error instead.
+ std::time::Duration::try_from_secs_f64(val)
+ .map_err(|_| ConfigError::InvalidDuration(s.to_string()))
} else if let Ok(val) = s.parse::() {
Ok(std::time::Duration::from_millis(val))
} else {
@@ -290,13 +341,29 @@ mod tests {
let cfg = WallrConfig::default();
assert_eq!(cfg.wallpaper.mode, ScalingMode::Fill);
assert!(cfg.matugen.enabled);
+ assert!(cfg.daemon.auto_start);
+ assert_eq!(cfg.daemon.socket, "$XDG_RUNTIME_DIR/wallr.sock");
+ assert_eq!(cfg.theme.provider, ThemeProvider::Matugen);
+ }
+
+ #[test]
+ fn partial_daemon_section_matches_programmatic_defaults() {
+ let cfg: WallrConfig = serde_yaml::from_str("daemon: {max_fps: 30}\n").unwrap();
+ assert!(cfg.daemon.auto_start);
+ assert_eq!(cfg.daemon.socket, "$XDG_RUNTIME_DIR/wallr.sock");
+ assert_eq!(cfg.daemon.max_fps, Some(30));
+ }
+
+ #[test]
+ fn partial_theme_section_keeps_matugen_default() {
+ let cfg: WallrConfig = serde_yaml::from_str("theme: {}\n").unwrap();
+ assert_eq!(cfg.theme.provider, ThemeProvider::Matugen);
}
#[test]
fn test_load_config_missing_file() {
- let path = Path::new("/nonexistent/config.yaml");
- let cfg = load_config(Some(path)).unwrap();
- assert_eq!(cfg.wallpaper.mode, ScalingMode::Fill);
+ let path = Path::new("/nonexistent/wallr-test-config.yaml");
+ assert!(load_config(Some(path)).is_err());
}
#[test]
@@ -307,23 +374,45 @@ mod tests {
#[test]
fn test_parse_duration_s() {
- let dur = parse_duration("2s").unwrap();
- assert_eq!(dur.as_secs(), 2);
+ assert_eq!(parse_duration("2s").unwrap().as_secs(), 2);
+ assert_eq!(parse_duration("1.5s").unwrap().as_millis(), 1500);
+ }
+
+ #[test]
+ fn parse_duration_rejects_extreme_and_invalid_values_without_panicking() {
+ for value in ["1e300s", "inf", "NaN", "-1s", "18446744073709551616ms"] {
+ assert!(parse_duration(value).is_err(), "{value} should be rejected");
+ }
}
#[test]
fn test_expand_path_tilde() {
- let expanded = expand_path("~/test.jpg");
+ let expanded = expand_path("~/test.jpg").unwrap();
assert!(!expanded.to_string_lossy().starts_with('~'));
}
#[test]
fn test_expand_path_env() {
- unsafe {
- std::env::set_var("TEST_VAR", "my_folder");
- }
- let expanded = expand_path("/tmp/$TEST_VAR/file.png");
- assert!(expanded.to_string_lossy().contains("my_folder"));
+ let expanded = expand_path("/tmp/$PATH/file.png").unwrap();
+ assert!(
+ expanded
+ .to_string_lossy()
+ .contains(std::env::var("PATH").unwrap().as_str())
+ );
+ let braced = expand_path("/tmp/${PATH}/file.png").unwrap();
+ assert_eq!(expanded, braced);
+ }
+
+ #[test]
+ fn expand_path_reports_unset_and_malformed_references() {
+ let missing = format!("${}", "WALLR_TEST_VAR_THAT_IS_NOT_SET");
+ assert!(matches!(
+ expand_path(&missing),
+ Err(ConfigError::UnsetEnv(_))
+ ));
+ assert!(expand_path("/tmp/${/x").is_err());
+ assert!(expand_path("/tmp/${}").is_err());
+ assert_eq!(expand_path("/tmp/a$").unwrap(), PathBuf::from("/tmp/a$"));
}
#[test]
@@ -332,5 +421,7 @@ mod tests {
let yaml = serde_yaml::to_string(&cfg).unwrap();
let parsed: WallrConfig = serde_yaml::from_str(&yaml).unwrap();
assert_eq!(parsed.wallpaper.mode, cfg.wallpaper.mode);
+ assert_eq!(parsed.daemon.socket, cfg.daemon.socket);
+ assert_eq!(parsed.theme.provider, cfg.theme.provider);
}
}
diff --git a/wallr-common/src/effect.rs b/wallr-common/src/effect.rs
index 639af74..0a1145d 100644
--- a/wallr-common/src/effect.rs
+++ b/wallr-common/src/effect.rs
@@ -73,7 +73,7 @@ pub struct FadeParams {
pub from: f32,
#[serde(default = "default_one")]
pub to: f32,
- #[serde(default)]
+ #[serde(default = "default_easing")]
pub easing: Easing,
}
@@ -95,7 +95,7 @@ pub struct WipeParams {
pub softness: f32,
#[serde(default)]
pub angle: Option,
- #[serde(default)]
+ #[serde(default = "default_easing")]
pub easing: Easing,
}
@@ -124,7 +124,7 @@ pub enum WipeDirection {
pub struct SlideParams {
#[serde(default)]
pub direction: SlideDirection,
- #[serde(default)]
+ #[serde(default = "default_easing")]
pub easing: Easing,
}
@@ -168,7 +168,7 @@ pub struct WaveParams {
/// an angle derives the center from the sweep direction.
#[serde(default)]
pub origin: Origin,
- #[serde(default)]
+ #[serde(default = "default_easing")]
pub easing: Easing,
}
@@ -188,7 +188,7 @@ impl Default for WaveParams {
pub struct GrowParams {
#[serde(default)]
pub origin: Origin,
- #[serde(default)]
+ #[serde(default = "default_easing")]
pub easing: Easing,
}
@@ -205,7 +205,7 @@ impl Default for GrowParams {
pub struct OuterParams {
#[serde(default)]
pub origin: Origin,
- #[serde(default)]
+ #[serde(default = "default_easing")]
pub easing: Easing,
}
@@ -240,6 +240,10 @@ fn default_one() -> f32 {
1.0
}
+fn default_easing() -> Easing {
+ Easing::Bezier
+}
+
fn default_wipe_softness() -> f32 {
0.006
}
diff --git a/wallr-common/src/ipc.rs b/wallr-common/src/ipc.rs
index b027148..dca3a8a 100644
--- a/wallr-common/src/ipc.rs
+++ b/wallr-common/src/ipc.rs
@@ -199,14 +199,36 @@ pub fn validate_command(cmd: &IpcCommand) -> Result<(), String> {
}
fn effect_param_values(effect: &crate::effect::Effect) -> Vec {
- use crate::effect::Effect;
+ use crate::effect::{Effect, Origin};
+
+ fn origin_values(origin: &Origin, values: &mut Vec) {
+ if let Origin::Custom(x, y) = origin {
+ values.push(*x);
+ values.push(*y);
+ }
+ }
+
+ let mut values = Vec::new();
match effect {
- Effect::Fade(p) => vec![p.from, p.to],
- Effect::Wipe(p) => vec![p.softness, p.angle.unwrap_or(0.0)],
- Effect::Slide(_) => vec![],
- Effect::Wave(p) => vec![p.frequency, p.amplitude, p.angle.unwrap_or(0.0)],
- Effect::Grow(_) | Effect::Outer(_) => vec![],
+ Effect::Fade(p) => values.extend([p.from, p.to]),
+ Effect::Wipe(p) => {
+ values.push(p.softness);
+ if let Some(angle) = p.angle {
+ values.push(angle);
+ }
+ }
+ Effect::Slide(_) => {}
+ Effect::Wave(p) => {
+ values.extend([p.frequency, p.amplitude]);
+ if let Some(angle) = p.angle {
+ values.push(angle);
+ }
+ origin_values(&p.origin, &mut values);
+ }
+ Effect::Grow(p) => origin_values(&p.origin, &mut values),
+ Effect::Outer(p) => origin_values(&p.origin, &mut values),
}
+ values
}
#[cfg(test)]
@@ -309,6 +331,31 @@ mod tests {
);
}
+ #[test]
+ fn rejects_non_finite_effect_origins() {
+ for origin in [
+ crate::effect::Origin::Custom(f32::NAN, 0.5),
+ crate::effect::Origin::Custom(0.5, f32::INFINITY),
+ ] {
+ let effect = crate::effect::Effect::Grow(crate::effect::GrowParams {
+ origin,
+ easing: crate::effect::Easing::Linear,
+ });
+ assert!(
+ validate_command(&IpcCommand::Preview {
+ path: "/tmp/w.jpg".to_string(),
+ effect: Some(effect),
+ duration_ms: None,
+ no_theme: true,
+ theme_override: None,
+ monitor: None,
+ scaling_mode: None,
+ })
+ .is_err()
+ );
+ }
+ }
+
#[test]
fn rejects_excessive_seek() {
assert!(
diff --git a/wallr-core/Cargo.toml b/wallr-core/Cargo.toml
index 5afe7cb..fc74e54 100644
--- a/wallr-core/Cargo.toml
+++ b/wallr-core/Cargo.toml
@@ -48,8 +48,8 @@ tracing.workspace = true
# Image processing
image.workspace = true
fast_image_resize.workspace = true
-gif = "0.13"
-zstd = "0.13"
+gif = "0.14"
+zstd = "0.14"
# Graphics
wgpu.workspace = true
diff --git a/wallr-core/src/animated/mod.rs b/wallr-core/src/animated/mod.rs
index f1f2741..08887f3 100644
--- a/wallr-core/src/animated/mod.rs
+++ b/wallr-core/src/animated/mod.rs
@@ -21,6 +21,12 @@ use gif::DisposalMethod;
// baseline after the wallpaper is replaced.
const CACHE_BUDGET: usize = 32 * 1024 * 1024;
const MAX_GIF_WORKING_SET: usize = 512 * 1024 * 1024;
+/// Maximum GIF file size accepted before any pixel work. A wallpaper
+/// animation larger than this is almost certainly malformed or hostile, and
+/// reading it whole would defeat the working-set limits below.
+pub const MAX_GIF_INPUT_BYTES: usize = 256 * 1024 * 1024;
+/// Bound the per-frame metadata vector as well as decoded pixels.
+pub const MAX_GIF_FRAMES: usize = 100_000;
/// A cached frame: raw RGBA8 or zstd-compressed RGBA8. The whole animation
/// uses one representation, chosen at decode time: raw when the full decoded
@@ -124,7 +130,28 @@ impl AnimatedImage {
if !is_gif {
return Ok(None);
}
- let bytes: std::sync::Arc<[u8]> = std::sync::Arc::from(std::fs::read(path)?);
+ let metadata = std::fs::metadata(path)?;
+ anyhow::ensure!(
+ metadata.len() <= MAX_GIF_INPUT_BYTES as u64,
+ "GIF file {} is {} bytes, exceeding the {} MiB input limit",
+ path.display(),
+ metadata.len(),
+ MAX_GIF_INPUT_BYTES / (1024 * 1024)
+ );
+ let mut bytes = Vec::with_capacity(metadata.len() as usize);
+ {
+ use std::io::Read;
+ let file = std::fs::File::open(path)?;
+ file.take((MAX_GIF_INPUT_BYTES + 1) as u64)
+ .read_to_end(&mut bytes)?;
+ }
+ anyhow::ensure!(
+ bytes.len() <= MAX_GIF_INPUT_BYTES,
+ "GIF file {} grew beyond the {} MiB input limit while reading",
+ path.display(),
+ MAX_GIF_INPUT_BYTES / (1024 * 1024)
+ );
+ let bytes: std::sync::Arc<[u8]> = std::sync::Arc::from(bytes);
let Some(info) = scan_gif(&bytes)? else {
return Ok(None);
};
@@ -176,18 +203,39 @@ impl AnimatedImage {
let Some(f) = reader.next_rgba() else {
return false;
};
- let (w, _h) = (self.width as usize, self.height as usize);
+ let (w, h) = (self.width as usize, self.height as usize);
+ let fw = f.width as usize;
+ let fh = f.height as usize;
+ let left = f.left as usize;
+ let top = f.top as usize;
+
+ // The GIF crate decodes a frame's rectangle, but the compositor and
+ // canvas indexing below assume the rectangle is inside the logical
+ // screen. Validate before any slicing: a malformed file must fail
+ // safely instead of panicking the daemon.
+ let Some(right) = left.checked_add(fw) else {
+ return false;
+ };
+ let Some(bottom) = top.checked_add(fh) else {
+ return false;
+ };
+ if right > w || bottom > h || f.rgba.len() != fw.saturating_mul(fh).saturating_mul(4) {
+ return false;
+ }
- if self.opaque {
+ let full_canvas =
+ left == 0 && top == 0 && fw == w && fh == h && f.rgba.len() == self.canvas.len();
+ if self.opaque && full_canvas {
self.canvas.copy_from_slice(&f.rgba);
} else {
+ if self.opaque {
+ // The scan advertised an opaque full-canvas stream, but the
+ // decoder produced something else. Fall back to compositing
+ // for the rest of this animation.
+ self.opaque = false;
+ }
// Transparency compositing: the frame's rect is blended onto the
// persistent canvas, then the disposal method is applied.
- let fw = f.width as usize;
- let fh = f.height as usize;
- let left = f.left as usize;
- let top = f.top as usize;
-
if f.dispose == DisposalMethod::Previous {
let need = fw * fh * 4;
if self.prev_save.len() != need {
@@ -260,10 +308,11 @@ impl AnimatedImage {
}
let mut guard = 0;
while self.next_index <= index {
- if self.next_index < self.cache.len() && self.cache[self.next_index].is_some() {
- self.next_index += 1;
- continue;
- }
+ // Do not skip cached frames without consuming the decoder: the
+ // decoded stream position and `next_index` must stay in lockstep.
+ // Otherwise a later uncached tail frame is stored under the wrong
+ // index after a loop wrap. Re-decoding a cached prefix still uses
+ // the same cache entry (decode_next only inserts when absent).
let before = self.next_index;
if !self.decode_next() {
// End of stream while seeking forward: restart from 0.
@@ -311,7 +360,7 @@ impl AnimatedImage {
let index = index.min(self.delays.len().saturating_sub(1));
self.ensure_upto(index);
match self.cache.get(index) {
- Some(Some(CachedFrame::Raw(raw))) => {
+ Some(Some(CachedFrame::Raw(raw))) if raw.len() == out.len() => {
out.copy_from_slice(raw);
true
}
@@ -376,6 +425,11 @@ fn gif_allocation_sizes(
height: u32,
frame_count: usize,
) -> anyhow::Result<(usize, usize)> {
+ anyhow::ensure!(width > 0 && height > 0, "GIF logical screen is empty");
+ anyhow::ensure!(
+ frame_count <= MAX_GIF_FRAMES,
+ "GIF has {frame_count} frames, exceeding the {MAX_GIF_FRAMES} frame limit"
+ );
let pixels = usize::try_from(u64::from(width) * u64::from(height))?;
let frame_bytes = pixels
.checked_mul(4)
@@ -400,6 +454,10 @@ fn scan_gif(bytes: &[u8]) -> anyhow::Result