From b079b1325f5477b52ea0bf9bcbac30eb1a533b4d Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 14:17:09 +0000 Subject: [PATCH 01/13] feat(nodes): extract Slint overlay into standalone video::slint node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new video source node (video::slint) that renders .slint UI components to RGBA8 frames via the software renderer. The node has no inputs and a single broadcast output, following the same lifecycle as colorbars (Ready → Start → Running). Key design decisions: - All Slint operations run on a single shared std::thread (lazily slint::platform::set_platform() is process-global. - Each node gets a unique NodeId (UUID) and communicates with the shared thread through tagged work items and per-node result channels. - A thread-local RefCell>> is swapped before each definition.create() / component.show() call so every ComponentInstance is associated with its own MinimalSoftwareWindow. - The new 'slint' feature does NOT depend on 'compositor', keeping the two fully decoupled. - Properties can be set at init and updated at runtime via UpdateParams. - Property keyframes cycle at a configurable interval. - frame_count == 0 gives infinite real-time output; frame_count > 0 produces exactly N frames then stops. Sample pipelines updated to use standalone slint nodes wired as compositor inputs instead of embedding slint_overlays in compositor config. Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- Cargo.lock | 3638 ++++++++++++++++- apps/skit/Cargo.toml | 1 + crates/nodes/Cargo.toml | 6 + crates/nodes/src/video/mod.rs | 6 + crates/nodes/src/video/slint.rs | 796 ++++ .../dynamic/video_moq_slint_scoreboard.yml | 119 + .../oneshot/video_slint_scoreboard.yml | 112 + samples/slint/lower_third.slint | 66 + samples/slint/scoreboard.slint | 118 + 9 files changed, 4710 insertions(+), 152 deletions(-) create mode 100644 crates/nodes/src/video/slint.rs create mode 100644 samples/pipelines/dynamic/video_moq_slint_scoreboard.yml create mode 100644 samples/pipelines/oneshot/video_slint_scoreboard.yml create mode 100644 samples/slint/lower_third.slint create mode 100644 samples/slint/scoreboard.slint diff --git a/Cargo.lock b/Cargo.lock index 3166783d..47e16e1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,111 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ab_glyph" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" + +[[package]] +name = "accesskit" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eca13c82f9a5cd813120b2e9b6a5d10532c6e4cd140c295cebd1f770095c8a5" + +[[package]] +name = "accesskit_atspi_common" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb9cc46b7fb6987c4f891f0301b230b29d9e69b4854f060a0cf41fbc407ab77" +dependencies = [ + "accesskit", + "accesskit_consumer", + "atspi-common", + "serde", + "zvariant", +] + +[[package]] +name = "accesskit_consumer" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d880a613f29621c90e801feec40f5dd61d837d7e20bf9b67676d45e7364a36" +dependencies = [ + "accesskit", + "hashbrown 0.16.1", +] + +[[package]] +name = "accesskit_macos" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0ddfc3fe3d457d11cc1c4989105986a03583a1d54d0c25053118944b62e100" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.16.1", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "accesskit_unix" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d552169ef018149966ed139bb0311c6947b3343e9140d1b9f88d69da9528fd" +dependencies = [ + "accesskit", + "accesskit_atspi_common", + "async-channel", + "async-executor", + "async-task", + "atspi", + "futures-lite", + "futures-util", + "serde", + "zbus", +] + +[[package]] +name = "accesskit_windows" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d277279d0a3b0c0021dd110b55aa1fe326b09ee2cbc338df28f847c7daf94e25" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.16.1", + "static_assertions", + "windows 0.61.3", + "windows-core 0.61.2", +] + +[[package]] +name = "accesskit_winit" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db08dff285306264a1de127ea07bb9e7a1ed71bd8593c168d0731caa782516c9" +dependencies = [ + "accesskit", + "accesskit_macos", + "accesskit_unix", + "accesskit_windows", + "raw-window-handle", + "winit", +] + [[package]] name = "addr2line" version = "0.25.1" @@ -69,6 +174,31 @@ version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" +[[package]] +name = "android-activity" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" +dependencies = [ + "android-properties", + "bitflags 2.11.0", + "cc", + "jni 0.22.4", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", + "thiserror 2.0.18", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -195,6 +325,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + [[package]] name = "as-slice" version = "0.2.1" @@ -258,6 +394,62 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix 1.1.4", + "slab", + "windows-sys 0.61.2", +] + [[package]] name = "async-lock" version = "3.4.2" @@ -269,6 +461,53 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix 1.1.4", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-signal" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 1.1.4", + "signal-hook-registry", + "slab", + "windows-sys 0.61.2", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -291,6 +530,12 @@ dependencies = [ "syn", ] +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" version = "0.1.89" @@ -337,6 +582,43 @@ dependencies = [ "syn", ] +[[package]] +name = "atspi" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77886257be21c9cd89a4ae7e64860c6f0eefca799bb79127913052bd0eefb3d" +dependencies = [ + "atspi-common", + "atspi-proxies", +] + +[[package]] +name = "atspi-common" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c5617155740c98003016429ad13fe43ce7a77b007479350a9f8bf95a29f63d" +dependencies = [ + "enumflags2", + "serde", + "static_assertions", + "zbus", + "zbus-lockstep", + "zbus-lockstep-macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "atspi-proxies" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2230e48787ed3eb4088996eab66a32ca20c0b67bbd4fd6cdfe79f04f1f04c9fc" +dependencies = [ + "atspi-common", + "serde", + "zbus", +] + [[package]] name = "audio-core" version = "0.2.1" @@ -385,6 +667,18 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "auto_enums" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65398a2893f41bce5c9259f6e1a4f03fbae40637c1bdc755b4f387f48c613b03" +dependencies = [ + "derive_utils", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -538,7 +832,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -553,6 +847,36 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "serde", + "unty", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.11.0", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.1", + "shlex", + "syn", +] + [[package]] name = "bit-set" version = "0.9.1" @@ -579,6 +903,9 @@ name = "bitflags" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] [[package]] name = "bitmaps" @@ -616,13 +943,45 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", +] + [[package]] name = "block2" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ - "objc2", + "objc2 0.6.4", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "bytes", + "cfg_aliases", ] [[package]] @@ -649,6 +1008,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + [[package]] name = "bytemuck" version = "1.25.0" @@ -697,41 +1062,92 @@ dependencies = [ ] [[package]] -name = "cap-fs-ext" -version = "3.4.5" +name = "calloop" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5528f85b1e134ae811704e41ef80930f56e795923f866813255bc342cc20654" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "cap-primitives", - "cap-std", - "io-lifetimes", - "windows-sys 0.59.0", + "bitflags 2.11.0", + "log", + "polling", + "rustix 0.38.44", + "slab", + "thiserror 1.0.69", ] [[package]] -name = "cap-net-ext" -version = "3.4.5" +name = "calloop" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20a158160765c6a7d0d8c072a53d772e4cb243f38b04bfcf6b4939cfbe7482e7" +checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" dependencies = [ - "cap-primitives", - "cap-std", + "bitflags 2.11.0", + "polling", "rustix 1.1.4", - "smallvec", + "slab", + "tracing", ] [[package]] -name = "cap-primitives" -version = "3.4.5" +name = "calloop-wayland-source" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6cf3aea8a5081171859ef57bc1606b1df6999df4f1110f8eef68b30098d1d3a" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" dependencies = [ - "ambient-authority", - "fs-set-times", - "io-extras", - "io-lifetimes", - "ipnet", - "maybe-owned", + "calloop 0.13.0", + "rustix 0.38.44", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" +dependencies = [ + "calloop 0.14.4", + "rustix 1.1.4", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "cap-fs-ext" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5528f85b1e134ae811704e41ef80930f56e795923f866813255bc342cc20654" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes 2.0.4", + "windows-sys 0.59.0", +] + +[[package]] +name = "cap-net-ext" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20a158160765c6a7d0d8c072a53d772e4cb243f38b04bfcf6b4939cfbe7482e7" +dependencies = [ + "cap-primitives", + "cap-std", + "rustix 1.1.4", + "smallvec", +] + +[[package]] +name = "cap-primitives" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cf3aea8a5081171859ef57bc1606b1df6999df4f1110f8eef68b30098d1d3a" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes 2.0.4", + "ipnet", + "maybe-owned", "rustix 1.1.4", "rustix-linux-procfs", "windows-sys 0.59.0", @@ -756,7 +1172,7 @@ checksum = "b6dc3090992a735d23219de5c204927163d922f42f575a0189b005c62d37549a" dependencies = [ "cap-primitives", "io-extras", - "io-lifetimes", + "io-lifetimes 2.0.4", "rustix 1.1.4", ] @@ -798,6 +1214,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -810,6 +1235,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + [[package]] name = "chacha20" version = "0.10.0" @@ -828,9 +1262,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", + "js-sys", "num-traits", "serde", - "windows-link", + "wasm-bindgen", + "windows-link 0.2.1", ] [[package]] @@ -860,6 +1296,17 @@ dependencies = [ "half", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading 0.8.9", +] + [[package]] name = "clap" version = "4.6.0" @@ -909,6 +1356,15 @@ dependencies = [ "error-code", ] +[[package]] +name = "clru" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197fd99cb113a8d5d9b6376f3aa817f32c1078f2343b714fff7d2ca44fdf67d5" +dependencies = [ + "hashbrown 0.16.1", +] + [[package]] name = "cmake" version = "0.1.58" @@ -1013,6 +1469,27 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "const-field-offset" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91fcde4ca1211b5a94b573083c472ee19e86b19a441913f66e1cc5c41daf0255" +dependencies = [ + "const-field-offset-macro", + "field-offset", +] + +[[package]] +name = "const-field-offset-macro" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5387f5bbc9e9e6c96436ea125afa12614cebf8ac67f49abc08c1e7a891466c90" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "convert_case" version = "0.10.0" @@ -1022,6 +1499,20 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "copypasta" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e6811e17f81fe246ef2bc553f76b6ee6ab41a694845df1d37e52a92b7bbd38a" +dependencies = [ + "clipboard-win", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "smithay-clipboard", + "x11-clipboard", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1048,6 +1539,30 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[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 0.9.4", + "libc", +] + [[package]] name = "core2" version = "0.4.0" @@ -1057,6 +1572,56 @@ dependencies = [ "memchr", ] +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + +[[package]] +name = "countme" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" + +[[package]] +name = "cpp" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bcac3d8234c1fb813358e83d1bb6b0290a3d2b3b5efc6b88bfeaf9d8eec17" +dependencies = [ + "cpp_macros", +] + +[[package]] +name = "cpp_build" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f8638c97fbd79cc6fc80b616e0e74b49bac21014faed590bbc89b7e2676c90" +dependencies = [ + "cc", + "cpp_common", + "lazy_static", + "proc-macro2", + "regex", + "syn", + "unicode-xid", +] + +[[package]] +name = "cpp_common" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25fcfea2ee05889597d35e986c2ad0169694320ae5cc8f6d2640a4bb8a884560" +dependencies = [ + "lazy_static", + "proc-macro2", + "syn", +] + [[package]] name = "cpp_demangle" version = "0.4.5" @@ -1075,6 +1640,21 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "cpp_macros" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d156158fe86e274820f5a53bc9edb0885a6e7113909497aa8d883b69dd171871" +dependencies = [ + "aho-corasick", + "byteorder", + "cpp_common", + "lazy_static", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -1274,6 +1854,12 @@ dependencies = [ "itertools 0.10.5", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -1324,6 +1910,18 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor-lite" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e162d0c2e2068eb736b71e5597eff0b9944e6b973cd9f37b6a288ab9bf20e300" + +[[package]] +name = "cursor-icon" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" + [[package]] name = "darling" version = "0.23.0" @@ -1364,6 +1962,12 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +[[package]] +name = "data-url" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" + [[package]] name = "debugid" version = "0.8.0" @@ -1420,6 +2024,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "derive_utils" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "362f47930db19fe7735f527e6595e4900316b893ebf6d48ad3d31be928d57dd6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dhat" version = "0.3.3" @@ -1468,6 +2083,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + [[package]] name = "dispatch2" version = "0.3.1" @@ -1475,7 +2096,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ "bitflags 2.11.0", - "objc2", + "objc2 0.6.4", ] [[package]] @@ -1489,6 +2110,15 @@ dependencies = [ "syn", ] +[[package]] +name = "dlib" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" +dependencies = [ + "libloading 0.8.9", +] + [[package]] name = "document-features" version = "0.2.12" @@ -1498,6 +2128,58 @@ dependencies = [ "litrs", ] +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" + +[[package]] +name = "drm" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" +dependencies = [ + "bitflags 2.11.0", + "bytemuck", + "drm-ffi", + "drm-fourcc", + "libc", + "rustix 0.38.44", +] + +[[package]] +name = "drm-ffi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51a91c9b32ac4e8105dec255e849e0d66e27d7c34d184364fb93e469db08f690" +dependencies = [ + "drm-sys", + "rustix 1.1.4", +] + +[[package]] +name = "drm-fourcc" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" + +[[package]] +name = "drm-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8e1361066d91f5ffccff060a3c3be9c3ecde15be2959c1937595f7a82a9f8" +dependencies = [ + "libc", + "linux-raw-sys 0.9.4", +] + [[package]] name = "dunce" version = "1.0.5" @@ -1546,12 +2228,39 @@ dependencies = [ "encoding_rs", ] +[[package]] +name = "endi" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" + [[package]] name = "endian-type" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env-libvpx-sys" version = "5.1.3" @@ -1603,6 +2312,15 @@ version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" +[[package]] +name = "euclid" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" +dependencies = [ + "num-traits", +] + [[package]] name = "event-listener" version = "5.4.1" @@ -1610,6 +2328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", + "parking", "pin-project-lite", ] @@ -1674,7 +2393,38 @@ dependencies = [ ] [[package]] -name = "figment" +name = "femtovg" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35695993a8264f5dfa8facc135c003965cea40d83705b49e0f8c3a3b632a2171" +dependencies = [ + "bitflags 2.11.0", + "bytemuck", + "fnv", + "glow", + "image", + "imgref", + "itertools 0.14.0", + "log", + "rgb", + "slotmap", + "ttf-parser 0.25.1", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "figment" version = "0.10.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" @@ -1732,6 +2482,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + [[package]] name = "fnv" version = "1.0.7" @@ -1750,6 +2506,36 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +[[package]] +name = "font-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a654f404bbcbd48ea58c617c2993ee91d1cb63727a37bf2323a4edeed1b8c5" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "font-types" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73829a7b5c91198af28a99159b7ae4afbb252fb906159ff7f189f3a2ceaa3df2" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "fontdb" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" +dependencies = [ + "log", + "slotmap", + "tinyvec", + "ttf-parser 0.25.1", +] + [[package]] name = "fontdue" version = "0.9.3" @@ -1757,7 +2543,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e57e16b3fe8ff4364c0661fdaac543fb38b29ea9bc9c2f45612d90adf931d2b" dependencies = [ "hashbrown 0.15.5", - "ttf-parser", + "ttf-parser 0.21.1", +] + +[[package]] +name = "fontique" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bbc252c93499b6d3635d692f892a637db0dbb130ce9b32bf20b28e0dcc470b" +dependencies = [ + "bytemuck", + "hashbrown 0.16.1", + "icu_locale_core", + "linebender_resource_handle", + "memmap2", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-text", + "objc2-foundation 0.3.2", + "read-fonts 0.35.0", + "roxmltree", + "smallvec", + "windows 0.58.0", + "windows-core 0.58.0", + "yeslogic-fontconfig-sys", ] [[package]] @@ -1766,7 +2575,28 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[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 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1775,6 +2605,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1800,7 +2636,7 @@ version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" dependencies = [ - "io-lifetimes", + "io-lifetimes 2.0.4", "rustix 1.1.4", "windows-sys 0.59.0", ] @@ -1859,6 +2695,19 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.32" @@ -1913,6 +2762,34 @@ dependencies = [ "serde_json", ] +[[package]] +name = "gbm" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce852e998d3ca5e4a97014fb31c940dc5ef344ec7d364984525fd11e8a547e6a" +dependencies = [ + "bitflags 2.11.0", + "drm", + "drm-fourcc", + "gbm-sys", + "libc", +] + +[[package]] +name = "gbm-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13a5f2acc785d8fb6bf6b7ab6bfb0ef5dad4f4d97e8e70bb8e470722312f76f" +dependencies = [ + "libc", +] + +[[package]] +name = "generativity" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5881e4c3c2433fe4905bb19cfd2b5d49d4248274862b68c27c33d9ba4e13f9ec" + [[package]] name = "generic-array" version = "0.14.7" @@ -1923,6 +2800,25 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" +dependencies = [ + "rustix 1.1.4", + "windows-link 0.2.1", +] + +[[package]] +name = "getopts" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" +dependencies = [ + "unicode-width", +] + [[package]] name = "getrandom" version = "0.2.17" @@ -1985,12 +2881,101 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + [[package]] name = "glob" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "glow" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12124de845cacfebedff80e877bb37b5b75c34c5a4c89e47e1cdd67fb6041325" +dependencies = [ + "bitflags 2.11.0", + "cfg_aliases", + "cgl", + "dispatch2", + "glutin_egl_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "libloading 0.8.9", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "once_cell", + "raw-window-handle", + "wayland-sys", + "windows-sys 0.52.0", + "x11-dl", +] + +[[package]] +name = "glutin-winit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85edca7075f8fc728f28cb8fbb111a96c3b89e930574369e3e9c27eb75d3788f" +dependencies = [ + "cfg_aliases", + "glutin", + "raw-window-handle", + "winit", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4680ba6195f424febdc3ba46e7a42a0e58743f2edb115297b86d7f8ecc02d2" +dependencies = [ + "gl_generator", + "windows-sys 0.52.0", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7bb2938045a88b612499fbcba375a77198e01306f52272e692f8c1f3751185" +dependencies = [ + "gl_generator", + "x11-dl", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + [[package]] name = "gpu-allocator" version = "0.28.0" @@ -2002,7 +2987,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.18", - "windows", + "windows 0.62.2", ] [[package]] @@ -2079,12 +3064,31 @@ dependencies = [ "url", ] +[[package]] +name = "harfrust" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c020db12c71d8a12a3fe7607873cade3a01a6287e29d540c8723276221b9d8" +dependencies = [ + "bitflags 2.11.0", + "bytemuck", + "core_maths", + "read-fonts 0.35.0", + "smallvec", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.15.5" @@ -2127,6 +3131,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hermit-abi" version = "0.5.2" @@ -2154,6 +3164,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "htmlparser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48ce8546b993eaf241d69ded33b1be6d205dd9857ec879d9d18bd05d3676e144" + [[package]] name = "http" version = "1.4.0" @@ -2299,63 +3315,339 @@ dependencies = [ ] [[package]] -name = "iana-time-zone" -version = "0.1.65" +name = "i-slint-backend-linuxkms" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +checksum = "6b8827952ecfbbf76c8cb5bc3388ca9124c34f2b4fe5dffcfe57800d2a484885" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", + "bytemuck", + "calloop 0.14.4", + "drm", + "gbm", + "glutin", + "i-slint-common", + "i-slint-core", + "i-slint-renderer-femtovg", + "i-slint-renderer-software", + "input", + "memmap2", + "nix 0.30.1", + "raw-window-handle", + "xkbcommon", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" +name = "i-slint-backend-qt" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +checksum = "ac9d5db3221f453439ec5ad9b6ac3bb8d2b4825b2f8734f0cde4b67d7336c3da" dependencies = [ - "cc", + "const-field-offset", + "cpp", + "cpp_build", + "i-slint-common", + "i-slint-core", + "i-slint-core-macros", + "lyon_path", + "pin-project", + "pin-weak", + "qttypes", + "vtable", ] [[package]] -name = "icu_collections" -version = "2.1.1" +name = "i-slint-backend-selector" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "ce5a7e591a7257096e1f3da1bbb9ad6a140c307d0eee74f008a0b412fdb20dec" dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", + "cfg-if", + "i-slint-backend-linuxkms", + "i-slint-backend-qt", + "i-slint-backend-winit", + "i-slint-common", + "i-slint-core", + "i-slint-core-macros", + "i-slint-renderer-femtovg", ] [[package]] -name = "icu_locale_core" -version = "2.1.1" +name = "i-slint-backend-winit" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "bbbf4789191740f939c9563b8850379122d7b5c1ceb09f9297b50ad53e408787" dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", + "accesskit", + "accesskit_winit", + "block2 0.6.2", + "bytemuck", + "cfg-if", + "cfg_aliases", + "copypasta", + "derive_more", + "futures", + "glutin", + "glutin-winit", + "i-slint-common", + "i-slint-core", + "i-slint-core-macros", + "i-slint-renderer-femtovg", + "i-slint-renderer-skia", + "i-slint-renderer-software", + "imgref", + "lyon_path", + "muda", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", + "objc2-ui-kit 0.3.2", + "pin-weak", + "raw-window-handle", + "rgb", + "scoped-tls-hkt", + "scopeguard", + "softbuffer", + "strum 0.27.2", + "vtable", + "wasm-bindgen", + "web-sys", + "windows 0.62.2", + "winit", + "zbus", ] [[package]] -name = "icu_normalizer" -version = "2.1.1" +name = "i-slint-common" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "e7659797fd28d4df3ed275ff95bf730bdf4a88d253f07e1ee8d0032d70138c3a" dependencies = [ - "icu_collections", - "icu_normalizer_data", + "fontique", + "ttf-parser 0.25.1", +] + +[[package]] +name = "i-slint-compiler" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a6f358d0d5389869d67cd6ab6f5acf98fe31827264a696593e9687213cff682" +dependencies = [ + "annotate-snippets", + "by_address", + "derive_more", + "i-slint-common", + "itertools 0.14.0", + "linked_hash_set", + "lyon_extra", + "lyon_path", + "num_enum", + "proc-macro2", + "quote", + "rowan", + "smol_str 0.3.6", + "strum 0.27.2", + "typed-index-collections", + "url", +] + +[[package]] +name = "i-slint-core" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a95591ff85f8e2ff11c8d26ea8429768c2b77866e0c7e7fd49348f23ad108b5c" +dependencies = [ + "auto_enums", + "bitflags 2.11.0", + "cfg-if", + "chrono", + "clru", + "const-field-offset", + "derive_more", + "euclid", + "htmlparser", + "i-slint-common", + "i-slint-core-macros", + "image", + "lyon_algorithms", + "lyon_extra", + "lyon_geom", + "lyon_path", + "num-traits", + "once_cell", + "parley", + "pin-project", + "pin-weak", + "portable-atomic", + "pulldown-cmark", + "raw-window-handle", + "resvg", + "rgb", + "scoped-tls-hkt", + "scopeguard", + "skrifa 0.37.0", + "slab", + "strum 0.27.2", + "sys-locale", + "thiserror 2.0.18", + "unicode-linebreak", + "unicode-script", + "unicode-segmentation", + "vtable", + "wasm-bindgen", + "web-sys", + "web-time", +] + +[[package]] +name = "i-slint-core-macros" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc5f2f71682787dd5c6299555c0de635009eb269bbc54d6198e0d225b69fae4" +dependencies = [ + "quote", + "serde_json", + "syn", +] + +[[package]] +name = "i-slint-renderer-femtovg" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb6eccda447999bc6222988500b841b64c953988986af182334e7ba9a30f0edd" +dependencies = [ + "cfg-if", + "const-field-offset", + "derive_more", + "femtovg", + "glow", + "i-slint-common", + "i-slint-core", + "i-slint-core-macros", + "imgref", + "lyon_path", + "pin-weak", + "rgb", + "ttf-parser 0.25.1", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "i-slint-renderer-skia" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64546232c0370f291e65fc92a4f4fc777ea78d5f48467873cb968b1de52e9ab" +dependencies = [ + "bytemuck", + "cfg-if", + "cfg_aliases", + "const-field-offset", + "derive_more", + "glow", + "glutin", + "i-slint-common", + "i-slint-core", + "i-slint-core-macros", + "lyon_path", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-metal 0.3.2", + "objc2-quartz-core 0.3.2", + "pin-weak", + "raw-window-handle", + "raw-window-metal", + "read-fonts 0.35.0", + "scoped-tls-hkt", + "skia-safe", + "softbuffer", + "unicode-segmentation", + "vtable", + "windows 0.62.2", + "write-fonts", +] + +[[package]] +name = "i-slint-renderer-software" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a59be6c34935c4f8e41aa67a63518d5c59219c8eeb1d07af420bed8334fa31d7" +dependencies = [ + "bytemuck", + "clru", + "derive_more", + "euclid", + "fontdue", + "i-slint-common", + "i-slint-core", + "integer-sqrt", + "lyon_path", + "num-traits", + "skrifa 0.37.0", + "zeno", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", @@ -2463,7 +3755,7 @@ dependencies = [ "image-webp", "moxcms", "num-traits", - "png", + "png 0.18.1", "zune-core", "zune-jpeg", ] @@ -2478,6 +3770,18 @@ dependencies = [ "quick-error", ] +[[package]] +name = "imagesize" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c" + +[[package]] +name = "imgref" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" + [[package]] name = "indexmap" version = "1.9.3" @@ -2514,7 +3818,7 @@ dependencies = [ "log", "num-format", "once_cell", - "quick-xml", + "quick-xml 0.26.0", "rgb", "str_stack", ] @@ -2525,6 +3829,34 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" +[[package]] +name = "input" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbdc09524a91f9cacd26f16734ff63d7dc650daffadd2b6f84d17a285bd875a9" +dependencies = [ + "bitflags 2.11.0", + "input-sys", + "libc", + "log", + "udev", +] + +[[package]] +name = "input-sys" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd4f5b4d1c00331c5245163aacfe5f20be75b564c7112d45893d4ae038119eb0" + +[[package]] +name = "integer-sqrt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" +dependencies = [ + "num-traits", +] + [[package]] name = "interpolate_name" version = "0.2.4" @@ -2542,10 +3874,21 @@ version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2285ddfe3054097ef4b2fe909ef8c3bcd1ea52a8f0d274416caebeef39f04a65" dependencies = [ - "io-lifetimes", + "io-lifetimes 2.0.4", "windows-sys 0.59.0", ] +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "io-lifetimes" version = "2.0.4" @@ -2574,7 +3917,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ - "hermit-abi", + "hermit-abi 0.5.2", "libc", "windows-sys 0.61.2", ] @@ -2664,19 +4007,68 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-sys 0.3.0", "log", "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link 0.2.1", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", +] + [[package]] name = "jni-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "jobserver" version = "0.1.34" @@ -2712,6 +4104,45 @@ dependencies = [ "signature", ] +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.11.0", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "kurbo" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce9729cc38c18d86123ab736fd2e7151763ba226ac2490ec092d1dd148825e32" +dependencies = [ + "arrayvec", + "euclid", + "smallvec", +] + +[[package]] +name = "kurbo" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7564e90fe3c0d5771e1f0bc95322b21baaeaa0d9213fa6a0b61c99f8b17b3bfb" +dependencies = [ + "arrayvec", + "euclid", + "smallvec", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2759,7 +4190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -2769,7 +4200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" dependencies = [ "cfg-if", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -2790,12 +4221,49 @@ dependencies = [ "redox_syscall 0.7.3", ] +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "linebender_resource_handle" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linked_hash_set" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "linux-raw-sys" version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -2835,6 +4303,47 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "lyon_algorithms" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9815fac08e6fd96733a11dce4f9d15a3f338e96a2e2311ee21e1b738efc2bc0f" +dependencies = [ + "lyon_path", + "num-traits", +] + +[[package]] +name = "lyon_extra" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7755f08423275157ad1680aaecc9ccb7e0cc633da3240fea2d1522935cc15c72" +dependencies = [ + "lyon_path", + "thiserror 2.0.18", +] + +[[package]] +name = "lyon_geom" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4336502e29e32af93cf2dad2214ed6003c17ceb5bd499df77b1de663b9042b92" +dependencies = [ + "arrayvec", + "euclid", + "num-traits", +] + +[[package]] +name = "lyon_path" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c463f9c428b7fc5ec885dcd39ce4aa61e29111d0e33483f6f98c74e89d8621e" +dependencies = [ + "lyon_geom", + "num-traits", +] + [[package]] name = "mach2" version = "0.4.3" @@ -2912,6 +4421,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -3023,6 +4541,25 @@ dependencies = [ "pxfm", ] +[[package]] +name = "muda" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" +dependencies = [ + "crossbeam-channel", + "dpi", + "keyboard-types", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "once_cell", + "png 0.17.16", + "thiserror 2.0.18", + "windows-sys 0.60.2", +] + [[package]] name = "multer" version = "3.1.0" @@ -3099,6 +4636,36 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.11.0", + "jni-sys 0.3.0", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys 0.3.0", +] + [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -3291,42 +4858,225 @@ dependencies = [ name = "num_enum" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "libc", + "objc2 0.5.2", + "objc2-core-data 0.2.2", + "objc2-core-image 0.2.2", + "objc2-foundation 0.2.2", + "objc2-quartz-core 0.2.2", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.11.0", + "block2 0.6.2", + "libc", + "objc2 0.6.4", + "objc2-cloud-kit 0.3.2", + "objc2-core-data 0.3.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image 0.3.2", + "objc2-core-text", + "objc2-core-video", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.11.0", + "dispatch2", + "objc2 0.6.4", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.11.0", + "dispatch2", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" dependencies = [ - "num_enum_derive", - "rustversion", + "objc2 0.6.4", + "objc2-foundation 0.3.2", ] [[package]] -name = "num_enum_derive" -version = "0.7.6" +name = "objc2-core-location" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-contacts", + "objc2-foundation 0.2.2", ] [[package]] -name = "objc2" -version = "0.6.4" +name = "objc2-core-text" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ - "objc2-encode", + "bitflags 2.11.0", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", ] [[package]] -name = "objc2-core-foundation" +name = "objc2-core-video" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" dependencies = [ "bitflags 2.11.0", - "dispatch2", - "objc2", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-io-surface", ] [[package]] @@ -3335,6 +5085,19 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "dispatch", + "libc", + "objc2 0.5.2", +] + [[package]] name = "objc2-foundation" version = "0.3.2" @@ -3342,7 +5105,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.11.0", - "objc2", + "block2 0.6.2", + "objc2 0.6.4", "objc2-core-foundation", ] @@ -3356,6 +5120,41 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.4", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + [[package]] name = "objc2-metal" version = "0.3.2" @@ -3363,9 +5162,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" dependencies = [ "bitflags 2.11.0", - "block2", - "objc2", - "objc2-foundation", + "block2 0.6.2", + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", ] [[package]] @@ -3375,10 +5187,79 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ "bitflags 2.11.0", - "objc2", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-metal 0.3.2", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-cloud-kit 0.2.2", + "objc2-core-data 0.2.2", + "objc2-core-image 0.2.2", + "objc2-core-location", + "objc2-foundation 0.2.2", + "objc2-link-presentation", + "objc2-quartz-core 0.2.2", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.11.0", + "block2 0.6.2", + "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation", - "objc2-metal", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.11.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", ] [[package]] @@ -3422,6 +5303,10 @@ name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +dependencies = [ + "critical-section", + "portable-atomic", +] [[package]] name = "once_cell_polyfill" @@ -3443,7 +5328,7 @@ checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" dependencies = [ "bitflags 2.11.0", "cfg-if", - "foreign-types", + "foreign-types 0.3.2", "libc", "once_cell", "openssl-macros", @@ -3564,6 +5449,16 @@ dependencies = [ "audiopus_sys", ] +[[package]] +name = "orbclient" +version = "0.3.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59aed3b33578edcfa1bc96a321d590d31832b6ad55a26f0313362ce687e9abd6" +dependencies = [ + "libc", + "libredox", +] + [[package]] name = "ordered-float" version = "4.6.0" @@ -3573,6 +5468,31 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" +dependencies = [ + "ttf-parser 0.25.1", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.5" @@ -3595,7 +5515,21 @@ dependencies = [ "petgraph", "redox_syscall 0.5.18", "smallvec", - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "parley" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada5338c3a9794af7342e6f765b6e78740db37378aced034d7bf72c96b94ed94" +dependencies = [ + "fontique", + "harfrust", + "hashbrown 0.16.1", + "linebender_resource_handle", + "skrifa 0.37.0", + "swash", ] [[package]] @@ -3649,6 +5583,12 @@ dependencies = [ "indexmap 2.13.0", ] +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + [[package]] name = "pin-project" version = "1.1.11" @@ -3681,6 +5621,23 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pin-weak" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b330c9d1b92dfe68442ca20b009c717d5f0b1e3cf4965e62f704c3c6e95a1305" + +[[package]] +name = "piper" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "pkg-config" version = "0.3.32" @@ -3693,6 +5650,19 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "png" version = "0.18.1" @@ -3706,6 +5676,20 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.5.2", + "pin-project-lite", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + [[package]] name = "pollster" version = "0.4.0" @@ -3717,6 +5701,9 @@ name = "portable-atomic" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +dependencies = [ + "critical-section", +] [[package]] name = "portable-atomic-util" @@ -3963,6 +5950,25 @@ dependencies = [ "prost 0.14.3", ] +[[package]] +name = "pulldown-cmark" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c3a14896dfa883796f1cb410461aef38810ea05f2b2c33c5aded3649095fdad" +dependencies = [ + "bitflags 2.11.0", + "getopts", + "memchr", + "pulldown-cmark-escape", + "unicase", +] + +[[package]] +name = "pulldown-cmark-escape" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" + [[package]] name = "pulley-interpreter" version = "41.0.4" @@ -4010,6 +6016,17 @@ dependencies = [ "web-transport-trait", ] +[[package]] +name = "qttypes" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7edf5b38c97ad8900ad2a8418ee44b4adceaa866a4a3405e2f1c909871d7ebd" +dependencies = [ + "cpp", + "cpp_build", + "semver", +] + [[package]] name = "quick-error" version = "2.0.1" @@ -4025,6 +6042,25 @@ dependencies = [ "memchr", ] +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quick-xml" +version = "0.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" +dependencies = [ + "memchr", +] + [[package]] name = "quinn" version = "0.11.9" @@ -4221,7 +6257,7 @@ dependencies = [ "parking_lot", "paste", "raw-cpuid", - "strum", + "strum 0.26.3", "to_method", "zerocopy 0.7.35", ] @@ -4283,10 +6319,10 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" dependencies = [ - "objc2", + "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation", - "objc2-quartz-core", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", ] [[package]] @@ -4322,6 +6358,27 @@ dependencies = [ "yasna", ] +[[package]] +name = "read-fonts" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" +dependencies = [ + "bytemuck", + "core_maths", + "font-types 0.10.1", +] + +[[package]] +name = "read-fonts" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5" +dependencies = [ + "bytemuck", + "font-types 0.11.1", +] + [[package]] name = "realfft" version = "3.5.0" @@ -4331,6 +6388,15 @@ dependencies = [ "rustfft", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -4516,6 +6582,23 @@ dependencies = [ "web-sys", ] +[[package]] +name = "resvg" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b563218631706d614e23059436526d005b50ab5f2d506b55a17eb65c5eb83419" +dependencies = [ + "gif", + "image-webp", + "log", + "pico-args", + "rgb", + "svgtypes", + "tiny-skia 0.11.4", + "usvg", + "zune-jpeg", +] + [[package]] name = "rgb" version = "0.8.53" @@ -4539,6 +6622,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rowan" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21" +dependencies = [ + "countme", + "hashbrown 0.14.5", + "rustc-hash 1.1.0", + "text-size", +] + +[[package]] +name = "roxmltree" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb" +dependencies = [ + "memchr", +] + [[package]] name = "rquickjs" version = "0.11.0" @@ -4760,7 +6864,7 @@ checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ "core-foundation 0.10.1", "core-foundation-sys", - "jni", + "jni 0.21.1", "log", "once_cell", "rustls", @@ -4797,6 +6901,24 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "rustybuzz" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" +dependencies = [ + "bitflags 2.11.0", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser 0.25.1", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + [[package]] name = "rustyline" version = "17.0.2" @@ -4891,12 +7013,37 @@ dependencies = [ "syn", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scoped-tls-hkt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9603871ffe5df3ac39cb624790c296dbd47a400d202f56bf3e414045099524d" + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sctk-adwaita" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit 0.19.2", + "tiny-skia 0.11.4", +] + [[package]] name = "security-framework" version = "3.7.0" @@ -5015,6 +7162,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_spanned" version = "0.6.9" @@ -5162,6 +7320,16 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + [[package]] name = "simd_helpers" version = "0.1.0" @@ -5171,6 +7339,21 @@ dependencies = [ "quote", ] +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + [[package]] name = "siphasher" version = "1.0.2" @@ -5187,12 +7370,125 @@ dependencies = [ "typenum", ] +[[package]] +name = "skia-bindings" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6f96e00735f14a781aac8a6870c862b8cc831df6d8e4ad77ab78e11411b9af" +dependencies = [ + "bindgen", + "cc", + "flate2", + "heck", + "pkg-config", + "regex", + "serde_json", + "tar", + "toml 0.9.12+spec-1.1.0", +] + +[[package]] +name = "skia-safe" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a71c01d325d40b1031dee67d251a5e0132e79e2a9ec272149a4f4a0d4b8b3be" +dependencies = [ + "bitflags 2.11.0", + "skia-bindings", + "windows 0.62.2", +] + +[[package]] +name = "skrifa" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c31071dedf532758ecf3fed987cdb4bd9509f900e026ab684b4ecb81ea49841" +dependencies = [ + "bytemuck", + "read-fonts 0.35.0", +] + +[[package]] +name = "skrifa" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" +dependencies = [ + "bytemuck", + "read-fonts 0.37.0", +] + [[package]] name = "slab" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +[[package]] +name = "slint" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25b87d458205e79efb30545cae083aec2ccb1b192c46a55ae6d54403cdacb33" +dependencies = [ + "const-field-offset", + "i-slint-backend-selector", + "i-slint-common", + "i-slint-core", + "i-slint-core-macros", + "i-slint-renderer-software", + "num-traits", + "once_cell", + "pin-weak", + "slint-macros", + "unicode-segmentation", + "vtable", +] + +[[package]] +name = "slint-interpreter" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22df58eef76ecc29e0641bbd34f718b6c84ab49186f099298d6baa94f5493437" +dependencies = [ + "derive_more", + "generativity", + "i-slint-backend-qt", + "i-slint-backend-selector", + "i-slint-backend-winit", + "i-slint-common", + "i-slint-compiler", + "i-slint-core", + "i-slint-core-macros", + "itertools 0.14.0", + "lyon_path", + "once_cell", + "smol_str 0.3.6", + "unicode-segmentation", + "vtable", + "web-sys", +] + +[[package]] +name = "slint-macros" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecc09bbc42c780d5b7ed7d41f7573dfd67343e11cdac27c07b88a8f933958e6" +dependencies = [ + "i-slint-compiler", + "proc-macro2", + "quote", + "spin_on", +] + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" version = "1.15.1" @@ -5202,6 +7498,88 @@ dependencies = [ "serde", ] +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.11.0", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 0.38.44", + "thiserror 1.0.69", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-client-toolkit" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" +dependencies = [ + "bitflags 2.11.0", + "calloop 0.14.4", + "calloop-wayland-source 0.4.1", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 1.1.4", + "thiserror 2.0.18", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-experimental", + "wayland-protocols-misc", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-clipboard" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71704c03f739f7745053bde45fa203a46c58d25bc5c4efba1d9a60e9dba81226" +dependencies = [ + "libc", + "smithay-client-toolkit 0.20.0", + "wayland-backend", +] + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "smol_str" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa7368fcf4852a4c2dd92df0cace6a71f2091ca0a23391ce7f3a31833f1523" +dependencies = [ + "borsh", + "serde_core", +] + [[package]] name = "socket2" version = "0.6.3" @@ -5212,6 +7590,37 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "softbuffer" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" +dependencies = [ + "as-raw-xcb-connection", + "bytemuck", + "fastrand", + "js-sys", + "memmap2", + "ndk", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", + "raw-window-handle", + "redox_syscall 0.5.18", + "rustix 1.1.4", + "tiny-xlib", + "tracing", + "wasm-bindgen", + "wayland-backend", + "wayland-client", + "wayland-sys", + "web-sys", + "windows-sys 0.61.2", + "x11rb", +] + [[package]] name = "spin" version = "0.9.8" @@ -5227,6 +7636,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spin_on" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076e103ed41b9864aa838287efe5f4e3a7a0362dd00671ae62a212e5e4612da2" +dependencies = [ + "pin-utils", +] + [[package]] name = "spirv" version = "0.4.0+sdk-1.4.341.0" @@ -5367,11 +7785,14 @@ dependencies = [ "serde", "serde-saphyr", "serde_json", + "slint", + "slint-interpreter", "smallvec", + "spin_on", "streamkit-core", "symphonia", "tempfile", - "tiny-skia", + "tiny-skia 0.12.0", "tokio", "tokio-util 0.7.18", "tower", @@ -5526,6 +7947,9 @@ name = "strict-num" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] [[package]] name = "strsim" @@ -5539,7 +7963,16 @@ version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros", + "strum_macros 0.26.4", +] + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros 0.27.2", ] [[package]] @@ -5555,12 +7988,45 @@ dependencies = [ "syn", ] +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "subtle" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "svgtypes" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "695b5790b3131dafa99b3bbfd25a216edb3d216dad9ca208d4657bfb8f2abc3d" +dependencies = [ + "kurbo 0.13.0", + "siphasher", +] + +[[package]] +name = "swash" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "842f3cd369c2ba38966204f983eaa5e54a8e84a7d7159ed36ade2b6c335aae64" +dependencies = [ + "skrifa 0.40.0", + "yazi", + "zeno", +] + [[package]] name = "symbolic-common" version = "12.17.2" @@ -5724,6 +8190,18 @@ dependencies = [ "syn", ] +[[package]] +name = "sys-locale" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" +dependencies = [ + "js-sys", + "libc", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "sysinfo" version = "0.38.4" @@ -5735,7 +8213,7 @@ dependencies = [ "ntapi", "objc2-core-foundation", "objc2-io-kit", - "windows", + "windows 0.62.2", ] [[package]] @@ -5769,7 +8247,7 @@ dependencies = [ "cap-fs-ext", "cap-std", "fd-lock", - "io-lifetimes", + "io-lifetimes 2.0.4", "rustix 0.38.44", "windows-sys 0.59.0", "winx", @@ -5814,6 +8292,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "text-size" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" + [[package]] name = "thiserror" version = "1.0.69" @@ -5931,6 +8415,21 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png 0.17.16", + "tiny-skia-path 0.11.4", +] + [[package]] name = "tiny-skia" version = "0.12.0" @@ -5942,8 +8441,19 @@ dependencies = [ "bytemuck", "cfg-if", "log", - "png", - "tiny-skia-path", + "png 0.18.1", + "tiny-skia-path 0.12.0", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", ] [[package]] @@ -5957,6 +8467,19 @@ dependencies = [ "strict-num", ] +[[package]] +name = "tiny-xlib" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0324504befd01cab6e0c994f34b2ffa257849ee019d3fb3b64fb2c858887d89e" +dependencies = [ + "as-raw-xcb-connection", + "ctor-lite", + "libloading 0.8.9", + "pkg-config", + "tracing", +] + [[package]] name = "tinystr" version = "0.8.2" @@ -5964,6 +8487,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", + "serde_core", "zerovec", ] @@ -6490,6 +9014,15 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +dependencies = [ + "core_maths", +] + [[package]] name = "tungstenite" version = "0.28.0" @@ -6526,12 +9059,45 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "typed-index-collections" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "898160f1dfd383b4e92e17f0512a7d62f3c51c44937b23b6ffc3a1614a8eaccd" +dependencies = [ + "bincode", + "serde", +] + [[package]] name = "typenum" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "udev" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4e37e9ea4401fc841ff54b9ddfc9be1079b1e89434c1a6a865dd68980f7e9f" +dependencies = [ + "io-lifetimes 1.0.11", + "libc", + "libudev-sys", + "pkg-config", +] + +[[package]] +name = "uds_windows" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" +dependencies = [ + "memoffset", + "tempfile", + "windows-sys 0.61.2", +] + [[package]] name = "uncased" version = "0.9.10" @@ -6547,18 +9113,60 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" + +[[package]] +name = "unicode-ccc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-script" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" + [[package]] name = "unicode-segmentation" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + [[package]] name = "unicode-width" version = "0.2.2" @@ -6589,6 +9197,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + [[package]] name = "url" version = "2.5.8" @@ -6608,6 +9222,33 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "usvg" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e419dff010bb12512b0ae9e3d2f318dfbdf0167fde7eb05465134d4e8756076f" +dependencies = [ + "base64 0.22.1", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo 0.13.0", + "log", + "pico-args", + "roxmltree", + "rustybuzz", + "simplecss", + "siphasher", + "strict-num", + "svgtypes", + "tiny-skia-path 0.11.4", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", +] + [[package]] name = "utf-8" version = "0.7.6" @@ -6678,6 +9319,29 @@ dependencies = [ "syn", ] +[[package]] +name = "vtable" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "753be81c38dff787d177b5939af1fa16f72f0d0d21a6b7d74ae56e29cd26f2a6" +dependencies = [ + "const-field-offset", + "portable-atomic", + "stable_deref_trait", + "vtable-macro", +] + +[[package]] +name = "vtable-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfcf6171aa2b0f85718ca5888ca32f6edf61d1849f8e4b3786ad890e5b68f68" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -7181,7 +9845,7 @@ dependencies = [ "fs-set-times", "futures", "io-extras", - "io-lifetimes", + "io-lifetimes 2.0.4", "rustix 1.1.4", "system-interface", "thiserror 2.0.18", @@ -7238,6 +9902,141 @@ dependencies = [ "wast 245.0.1", ] +[[package]] +name = "wayland-backend" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" +dependencies = [ + "cc", + "downcast-rs", + "rustix 1.1.4", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" +dependencies = [ + "bitflags 2.11.0", + "rustix 1.1.4", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.11.0", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d" +dependencies = [ + "rustix 1.1.4", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" +dependencies = [ + "bitflags 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-experimental" +version = "20250721.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" +dependencies = [ + "bitflags 2.11.0", + "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 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" +dependencies = [ + "bitflags 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" +dependencies = [ + "bitflags 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" +dependencies = [ + "proc-macro2", + "quick-xml 0.39.2", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + [[package]] name = "web-async" version = "0.1.3" @@ -7430,7 +10229,7 @@ dependencies = [ "ash", "bit-set", "bitflags 2.11.0", - "block2", + "block2 0.6.2", "bytemuck", "cfg-if", "cfg_aliases", @@ -7441,11 +10240,11 @@ dependencies = [ "libloading 0.8.9", "log", "naga", - "objc2", + "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation", - "objc2-metal", - "objc2-quartz-core", + "objc2-foundation 0.3.2", + "objc2-metal 0.3.2", + "objc2-quartz-core 0.3.2", "once_cell", "ordered-float", "parking_lot", @@ -7460,8 +10259,8 @@ dependencies = [ "thiserror 2.0.18", "wgpu-naga-bridge", "wgpu-types", - "windows", - "windows-core", + "windows 0.62.2", + "windows-core 0.62.2", ] [[package]] @@ -7592,16 +10391,48 @@ dependencies = [ "num-traits", ] +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections 0.2.0", + "windows-core 0.61.2", + "windows-future 0.2.1", + "windows-link 0.1.3", + "windows-numerics 0.2.0", +] + [[package]] name = "windows" 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", + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", + "windows-numerics 0.3.1", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", ] [[package]] @@ -7610,7 +10441,33 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-core", + "windows-core 0.62.2", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -7619,11 +10476,22 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading 0.1.0", ] [[package]] @@ -7632,9 +10500,20 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core", - "windows-link", - "windows-threading", + "windows-core 0.62.2", + "windows-link 0.2.1", + "windows-threading 0.2.1", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -7648,6 +10527,17 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-interface" version = "0.59.3" @@ -7659,6 +10549,12 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-link" version = "0.2.1" @@ -7666,33 +10562,80 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-numerics" -version = "0.3.1" +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-core", - "windows-link", + "windows-link 0.2.1", ] [[package]] -name = "windows-registry" -version = "0.6.1" +name = "windows-strings" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-link", - "windows-result", - "windows-strings", + "windows-result 0.2.0", + "windows-targets 0.52.6", ] [[package]] -name = "windows-result" -version = "0.4.1" +name = "windows-strings" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -7701,7 +10644,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -7713,6 +10656,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -7746,7 +10698,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -7764,6 +10716,21 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -7786,7 +10753,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link", + "windows-link 0.2.1", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -7797,13 +10764,22 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows-threading" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -7812,6 +10788,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -7830,6 +10812,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -7848,6 +10836,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -7878,6 +10872,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -7896,6 +10896,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -7914,6 +10920,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -7932,6 +10944,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -7944,6 +10962,58 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winit" +version = "0.30.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d" +dependencies = [ + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.11.0", + "block2 0.5.1", + "bytemuck", + "calloop 0.13.0", + "cfg_aliases", + "concurrent-queue", + "core-foundation 0.9.4", + "core-graphics", + "cursor-icon", + "dpi", + "js-sys", + "libc", + "memmap2", + "ndk", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "objc2-ui-kit 0.2.2", + "orbclient", + "percent-encoding", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", + "rustix 0.38.44", + "sctk-adwaita", + "smithay-client-toolkit 0.19.2", + "smol_str 0.2.2", + "tracing", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.52.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + [[package]] name = "winnow" version = "0.7.15" @@ -8099,12 +11169,67 @@ dependencies = [ "wast 35.0.2", ] +[[package]] +name = "write-fonts" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "886614b5ce857341226aa091f3c285e450683894acaaa7887f366c361efef79d" +dependencies = [ + "font-types 0.10.1", + "indexmap 2.13.0", + "kurbo 0.12.0", + "log", + "read-fonts 0.35.0", +] + [[package]] name = "writeable" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +[[package]] +name = "x11-clipboard" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662d74b3d77e396b8e5beb00b9cad6a9eccf40b2ef68cc858784b14c41d535a3" +dependencies = [ + "libc", + "x11rb", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading 0.8.9", + "once_cell", + "rustix 1.1.4", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" + [[package]] name = "x509-parser" version = "0.18.1" @@ -8133,6 +11258,54 @@ dependencies = [ "rustix 1.1.4", ] +[[package]] +name = "xcursor" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" + +[[package]] +name = "xkbcommon" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a974f48060a14e95705c01f24ad9c3345022f4d97441b8a36beb7ed5c4a02d" +dependencies = [ + "libc", + "memmap2", + "xkeysym", +] + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.11.0", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "xml-rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + [[package]] name = "y4m" version = "0.8.0" @@ -8154,6 +11327,23 @@ dependencies = [ "time", ] +[[package]] +name = "yazi" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" + +[[package]] +name = "yeslogic-fontconfig-sys" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503a066b4c037c440169d995b869046827dbc71263f6e8f3be6d77d4f3229dbd" +dependencies = [ + "dlib", + "once_cell", + "pkg-config", +] + [[package]] name = "yoke" version = "0.8.1" @@ -8177,6 +11367,109 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zbus" +version = "5.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "libc", + "ordered-stream", + "rustix 1.1.4", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "uuid", + "windows-sys 0.61.2", + "winnow 0.7.15", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus-lockstep" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6998de05217a084b7578728a9443d04ea4cd80f2a0839b8d78770b76ccd45863" +dependencies = [ + "zbus_xml", + "zvariant", +] + +[[package]] +name = "zbus-lockstep-macros" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10da05367f3a7b7553c8cdf8fa91aee6b64afebe32b51c95177957efc47ca3a0" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "zbus-lockstep", + "zbus_xml", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" +dependencies = [ + "serde", + "winnow 0.7.15", + "zvariant", +] + +[[package]] +name = "zbus_xml" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "441a0064125265655bccc3a6af6bef56814d9277ac83fce48b1cd7e160b80eac" +dependencies = [ + "quick-xml 0.38.4", + "serde", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zeno" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" + [[package]] name = "zerocopy" version = "0.7.35" @@ -8262,6 +11555,7 @@ version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ + "serde", "yoke", "zerofrom", "zerovec-derive", @@ -8326,3 +11620,43 @@ checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c" dependencies = [ "zune-core", ] + +[[package]] +name = "zvariant" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b" +dependencies = [ + "endi", + "enumflags2", + "serde", + "winnow 0.7.15", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn", + "winnow 0.7.15", +] diff --git a/apps/skit/Cargo.toml b/apps/skit/Cargo.toml index 81efe5c0..de1c0b65 100644 --- a/apps/skit/Cargo.toml +++ b/apps/skit/Cargo.toml @@ -152,6 +152,7 @@ svt_av1 = ["streamkit-nodes/svt_av1"] svt_av1_static = ["streamkit-nodes/svt_av1_static"] dav1d = ["streamkit-nodes/dav1d"] dav1d_static = ["streamkit-nodes/dav1d_static"] +slint = ["streamkit-nodes/slint"] [dev-dependencies] tokio-test = "0.4.5" diff --git a/crates/nodes/Cargo.toml b/crates/nodes/Cargo.toml index 992087f4..afb19a4e 100644 --- a/crates/nodes/Cargo.toml +++ b/crates/nodes/Cargo.toml @@ -91,6 +91,11 @@ wgpu = { version = "29", optional = true, default-features = false, features = [ pollster = { version = "0.4", optional = true } bytemuck = { version = "1.22", optional = true, features = ["derive"] } +# Slint UI rendering (optional, behind `slint` feature) +slint = { version = "1.15", optional = true, default-features = false, features = ["renderer-software", "compat-1-2"] } +slint-interpreter = { version = "1.15", optional = true } +spin_on = { version = "0.1", optional = true } + futures-util = "0.3" [features] @@ -151,6 +156,7 @@ dav1d_static = ["dav1d"] colorbars = ["dep:schemars", "dep:serde_json", "dep:fontdue"] compositor = ["dep:schemars", "dep:serde_json", "dep:image", "dep:tiny-skia", "dep:rayon", "dep:fontdue", "dep:smallvec", "dep:uuid"] gpu = ["compositor", "dep:wgpu", "dep:pollster", "dep:bytemuck"] +slint = ["dep:slint", "dep:slint-interpreter", "dep:spin_on", "dep:schemars", "dep:serde_json", "dep:uuid"] codegen = ["dep:ts-rs"] video = ["vp9", "av1", "colorbars", "compositor"] diff --git a/crates/nodes/src/video/mod.rs b/crates/nodes/src/video/mod.rs index 67cbefe7..41cf0dae 100644 --- a/crates/nodes/src/video/mod.rs +++ b/crates/nodes/src/video/mod.rs @@ -245,6 +245,9 @@ pub mod dav1d; #[cfg(feature = "dav1d")] pub mod dav1d_ffi; +#[cfg(feature = "slint")] +pub mod slint; + #[cfg(any(feature = "colorbars", feature = "compositor"))] pub(crate) mod fonts; @@ -569,4 +572,7 @@ pub fn register_video_nodes(registry: &mut NodeRegistry, constraints: &GlobalNod #[cfg(feature = "dav1d")] dav1d::register_dav1d_nodes(registry); + + #[cfg(feature = "slint")] + slint::register_slint_nodes(registry); } diff --git a/crates/nodes/src/video/slint.rs b/crates/nodes/src/video/slint.rs new file mode 100644 index 00000000..c58e8951 --- /dev/null +++ b/crates/nodes/src/video/slint.rs @@ -0,0 +1,796 @@ +// SPDX-FileCopyrightText: © 2025 StreamKit Contributors +// +// SPDX-License-Identifier: MPL-2.0 + +//! Standalone Slint UI video source node. +//! +//! Compiles a `.slint` file at init time via `slint-interpreter` and renders +//! RGBA8 frames using the software renderer at a configurable resolution and +//! frame rate. The node has no inputs — it is a video source, just like +//! `video::colorbars`. Its output can be wired into the compositor (or any +//! other node that accepts raw video) as a regular layer. +//! +//! ## Threading +//! +//! `slint::platform::set_platform` is process-global, and the types it +//! manages (`MinimalSoftwareWindow`, `ComponentInstance`) are `!Send` +//! (`Rc`-based). To support multiple `SlintNode` instances in one process +//! without UB, **all** Slint operations are funnelled through a single +//! dedicated `std::thread` (lazily spawned via `OnceLock`). Each node +//! communicates with this shared thread through tagged work items and +//! per-node result channels. + +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; +use std::sync::OnceLock; + +use async_trait::async_trait; +use schemars::schema_for; +use schemars::JsonSchema; +use serde::Deserialize; +use slint::platform::software_renderer::{ + MinimalSoftwareWindow, PremultipliedRgbaColor, RepaintBufferType, +}; +use slint::platform::WindowAdapter; +use slint::{ComponentHandle, LogicalSize, SharedString}; +use slint_interpreter::{ComponentDefinition, ComponentInstance, Value}; +use streamkit_core::control::NodeControlMessage; +use streamkit_core::registry::StaticPins; +use streamkit_core::stats::NodeStatsTracker; +use streamkit_core::types::{ + Packet, PacketMetadata, PacketType, PixelFormat, RawVideoFormat, VideoFrame, +}; +use streamkit_core::{ + config_helpers, state_helpers, InputPin, NodeContext, NodeRegistry, OutputPin, PinCardinality, + ProcessorNode, StreamKitError, +}; + +// ── Defaults ──────────────────────────────────────────────────────────────── + +const fn default_width() -> u32 { + 640 +} + +const fn default_height() -> u32 { + 480 +} + +const fn default_fps() -> u32 { + 30 +} + +const fn default_frame_count() -> u32 { + 0 +} + +const fn default_keyframe_interval() -> u32 { + 90 +} + +// ── Configuration ─────────────────────────────────────────────────────────── + +/// Configuration for the standalone Slint UI video source node. +/// +/// Produces RGBA8 frames by rendering a compiled `.slint` component via the +/// software renderer. Properties can be set at init and updated at runtime +/// via `UpdateParams`. +#[derive(Debug, Clone, Deserialize, JsonSchema)] +pub struct SlintConfig { + /// Output frame width in pixels. + #[serde(default = "default_width")] + pub width: u32, + /// Output frame height in pixels. + #[serde(default = "default_height")] + pub height: u32, + /// Output frame rate. + #[serde(default = "default_fps")] + pub fps: u32, + /// Path to the `.slint` file (must start with `samples/slint/`). + pub slint_file: String, + /// Name of the exported component to instantiate. When omitted, the + /// first exported component in the file is used. + #[serde(default)] + pub component: Option, + /// Key-value map of Slint properties to set on the component instance. + /// Strings → `SharedString`, numbers → `f64`, booleans → `bool`. + #[serde(default)] + pub properties: HashMap, + /// Optional list of property snapshots to cycle through over time. + /// Each entry is a partial property map merged on top of `properties`. + #[serde(default)] + pub property_keyframes: Vec>, + /// Number of frames between keyframe switches (default: 90 ≈ 3 s at 30 fps). + #[serde(default = "default_keyframe_interval")] + pub keyframe_interval: u32, + /// Total frames to generate. 0 = infinite (real-time pacing). + #[serde(default = "default_frame_count")] + pub frame_count: u32, +} + +impl Default for SlintConfig { + fn default() -> Self { + Self { + width: default_width(), + height: default_height(), + fps: default_fps(), + slint_file: String::new(), + component: None, + properties: HashMap::new(), + property_keyframes: Vec::new(), + keyframe_interval: default_keyframe_interval(), + frame_count: default_frame_count(), + } + } +} + +impl SlintConfig { + /// Validate configuration parameters. + /// + /// # Errors + /// + /// Returns an error string if dimensions are zero, fps is zero, or the + /// slint file path is invalid. + fn validate(&self) -> Result<(), String> { + if self.width == 0 || self.height == 0 { + return Err("width and height must be > 0".to_string()); + } + if self.fps == 0 { + return Err("fps must be > 0".to_string()); + } + validate_slint_asset_path(&self.slint_file) + } +} + +/// Validates that a Slint asset path is safe to read. +/// +/// # Errors +/// +/// Returns an error string if the path contains traversal sequences or does +/// not start with `samples/slint/`. +fn validate_slint_asset_path(path: &str) -> Result<(), String> { + if path.contains("..") || !path.starts_with("samples/slint/") { + return Err(format!( + "Invalid slint_file: must start with 'samples/slint/' and not contain '..': {path}" + )); + } + Ok(()) +} + +// ── Shared Slint thread ───────────────────────────────────────────────────── +// +// `slint::platform::set_platform` is process-global and the types it exposes +// (`MinimalSoftwareWindow`, `ComponentInstance`) are `!Send` (`Rc`-based). +// To support multiple `SlintNode` instances without UB, all Slint work is +// funnelled through a single dedicated `std::thread`, lazily spawned on the +// first node's init. +// +// Each node gets a unique `NodeId` (UUID) and communicates with the shared +// thread via tagged work items. Results are sent back on a per-node +// `std::sync::mpsc` channel. + +/// Opaque identifier for a node's instance on the shared Slint thread. +type NodeId = uuid::Uuid; + +/// Work item sent from a node's async loop to the shared Slint thread. +enum SlintWorkItem { + /// Register a new node: compile its `.slint` file and create an instance. + /// The `result_tx` is stored by the shared thread for sending render + /// results and the init outcome back. + Register { + node_id: NodeId, + config: SlintConfig, + result_tx: std::sync::mpsc::Sender, + }, + /// Request a single rendered frame for the given node. + Render { node_id: NodeId }, + /// Update the config (properties / keyframes) for subsequent renders. + UpdateConfig { node_id: NodeId, config: SlintConfig }, + /// Unregister a node — drop its instance and result channel. + Unregister { node_id: NodeId }, +} + +/// Result sent from the shared Slint thread back to a specific node. +enum SlintThreadResult { + /// Init succeeded — the node can start rendering. + InitOk, + /// Init failed with an error message. + InitErr(String), + /// A rendered frame. + Frame { rgba_data: Vec }, +} + +/// Handle to the shared Slint thread's work channel. +struct SlintThreadHandle { + work_tx: std::sync::mpsc::Sender, +} + +/// Get (or lazily spawn) the shared Slint thread. +/// +/// # Panics +/// +/// Panics if the OS fails to spawn the dedicated Slint renderer thread +/// (e.g. resource exhaustion). This is unrecoverable — the process cannot +/// render Slint UIs without this thread. +#[allow(clippy::expect_used)] +fn shared_slint_thread() -> &'static SlintThreadHandle { + static HANDLE: OnceLock = OnceLock::new(); + HANDLE.get_or_init(|| { + let (work_tx, work_rx) = std::sync::mpsc::channel::(); + std::thread::Builder::new() + .name("slint-renderer".to_string()) + .spawn(move || slint_thread_main(work_rx)) + .expect("Failed to spawn shared Slint renderer thread"); + SlintThreadHandle { work_tx } + }) +} + +/// Entry point for the shared Slint thread. +/// +/// Processes work items from all `SlintNode` instances. The platform +/// backend is set once on this thread; all `SlintInstance` values live here. +#[allow(clippy::needless_pass_by_value)] // Receiver must be owned by this thread +fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { + /// Per-node state living on the shared thread. + struct NodeState { + instance: SlintInstance, + config: SlintConfig, + result_tx: std::sync::mpsc::Sender, + } + + let mut nodes: HashMap = HashMap::new(); + let mut platform_set = false; + + while let Ok(work) = work_rx.recv() { + match work { + SlintWorkItem::Register { node_id, config, result_tx } => { + match create_slint_instance(&config, &mut platform_set) { + Ok(instance) => { + tracing::info!( + "Created Slint instance '{}' from '{}'", + node_id, + config.slint_file + ); + let _ = result_tx.send(SlintThreadResult::InitOk); + nodes.insert(node_id, NodeState { instance, config, result_tx }); + }, + Err(e) => { + tracing::error!("Failed to create Slint instance '{}': {e}", node_id); + let _ = result_tx.send(SlintThreadResult::InitErr(e.to_string())); + }, + } + }, + SlintWorkItem::Render { node_id } => { + if let Some(state) = nodes.get_mut(&node_id) { + let rgba_data = render_slint_frame(&mut state.instance, &state.config); + // If the result channel is closed the node has been dropped; + // clean up its state on the next Unregister (or here eagerly). + if state.result_tx.send(SlintThreadResult::Frame { rgba_data }).is_err() { + nodes.remove(&node_id); + } + } + }, + SlintWorkItem::UpdateConfig { node_id, config } => { + if let Some(state) = nodes.get_mut(&node_id) { + state.config = config; + } + }, + SlintWorkItem::Unregister { node_id } => { + nodes.remove(&node_id); + }, + } + } +} + +// ── Slint rendering internals ─────────────────────────────────────────────── +// +// These types and functions are adapted from the former +// `compositor/slint_overlay.rs` module. They live on the shared Slint +// thread and are `!Send` by design. + +/// A compiled Slint component instance ready for per-frame rendering. +/// +/// Created once at pipeline init on the shared Slint thread. +/// `!Send` by design — must not leave that thread. +struct SlintInstance { + window: Rc, + component: ComponentInstance, + // Kept alive to prevent the compiled Slint component definition from being dropped. + #[allow(dead_code)] + definition: ComponentDefinition, + buffer: Vec, + width: u32, + /// Frame counter for property keyframe cycling. + frame_counter: u32, +} + +/// Compile a `.slint` file and create a renderable instance. +/// +/// Must be called on the shared Slint thread (`!Send` types). +/// The `platform_set` flag tracks whether `set_platform` has already been +/// called — it must happen exactly once per process. +/// +/// # Errors +/// +/// Returns an error if the `.slint` file cannot be compiled or if no +/// matching component definition is found. +fn create_slint_instance( + config: &SlintConfig, + platform_set: &mut bool, +) -> Result { + let width = config.width; + let height = config.height; + + // Compile the .slint file. + let compiler = slint_interpreter::Compiler::default(); + let result = spin_on::spin_on(compiler.build_from_path(&config.slint_file)); + + // Check for compilation errors. + let diags: Vec<_> = result + .diagnostics() + .filter(|d| d.level() == slint_interpreter::DiagnosticLevel::Error) + .collect(); + if !diags.is_empty() { + let msgs: Vec = diags.iter().map(|d| d.message().to_string()).collect(); + return Err(StreamKitError::Configuration(format!( + "Slint compilation errors in '{}': {}", + config.slint_file, + msgs.join("; ") + ))); + } + + // Get the component definition. + let definition = if let Some(ref name) = config.component { + result.component(name).ok_or_else(|| { + StreamKitError::Configuration(format!( + "Component '{}' not found in '{}'", + name, config.slint_file + )) + })? + } else { + // Use the first exported component. + result.components().next().ok_or_else(|| { + StreamKitError::Configuration(format!( + "No exported components in '{}'", + config.slint_file + )) + })? + }; + + // Create the minimal software window. + // Dimensions are bounded by practical limits, so the u32→f32 precision + // loss above ~16M is irrelevant here. + let window = MinimalSoftwareWindow::new(RepaintBufferType::NewBuffer); + #[allow(clippy::cast_precision_loss)] + window.set_size(LogicalSize::new((width as f32).max(1.0), (height as f32).max(1.0))); + + // Set the Slint platform backend exactly once per process. + // All instances share this thread, so the first call suffices. + if !*platform_set { + let _ = slint::platform::set_platform(Box::new(SlintBackend)); + *platform_set = true; + } + + // Swap in this instance's window so `create_window_adapter()` returns + // the correct one during `definition.create()` and `component.show()`. + let window_adapter = window.clone() as Rc; + CURRENT_WINDOW.with(|cell| *cell.borrow_mut() = Some(window_adapter)); + + // Instantiate the component. + let component = definition.create().map_err(|e| { + StreamKitError::Configuration(format!("Failed to create Slint component instance: {e}")) + })?; + + // Set initial properties. + set_properties(&component, &config.properties); + + // Allocate pixel buffer. + let pixel_count = (width as usize) * (height as usize); + let buffer = vec![PremultipliedRgbaColor::default(); pixel_count]; + + // Show the component so it becomes visible for rendering. + component.show().map_err(|e| { + StreamKitError::Configuration(format!("Failed to show Slint component: {e}")) + })?; + + Ok(SlintInstance { window, component, definition, buffer, width, frame_counter: 0 }) +} + +/// Render a single frame from the Slint instance, returning raw RGBA8 data. +/// +/// Applies property keyframe cycling and pumps Slint animation timers. +fn render_slint_frame(instance: &mut SlintInstance, config: &SlintConfig) -> Vec { + // Build the effective property map: base properties merged with the + // current keyframe (if keyframes are configured). + let effective_props = if config.property_keyframes.is_empty() { + std::borrow::Cow::Borrowed(&config.properties) + } else { + let interval = config.keyframe_interval.max(1); + let idx = (instance.frame_counter / interval) as usize % config.property_keyframes.len(); + let mut merged = config.properties.clone(); + merged.extend(config.property_keyframes[idx].iter().map(|(k, v)| (k.clone(), v.clone()))); + std::borrow::Cow::Owned(merged) + }; + instance.frame_counter = instance.frame_counter.wrapping_add(1); + + // Push property updates into the component instance. + set_properties(&instance.component, &effective_props); + + // Pump Slint's internal animation timers so time-based animations + // (e.g. slide-in transitions) advance on each tick. + slint::platform::update_timers_and_animations(); + + // Render into the pixel buffer. + let width = instance.width; + instance.window.draw_if_needed(|renderer| { + renderer.render(&mut instance.buffer, width as usize); + }); + + // Convert premultiplied buffer to straight-alpha RGBA8. + premultiplied_to_straight_rgba(&instance.buffer) +} + +// ── Private helpers ───────────────────────────────────────────────────────── + +/// Map JSON property values to Slint `Value` and set them on the component. +fn set_properties(component: &ComponentInstance, properties: &HashMap) { + for (key, json_val) in properties { + let slint_val = json_to_slint_value(json_val); + if let Err(e) = component.set_property(key, slint_val) { + tracing::warn!("Failed to set Slint property '{key}': {e}"); + } + } +} + +/// Convert a JSON value to a Slint interpreter `Value`. +fn json_to_slint_value(json: &serde_json::Value) -> Value { + match json { + serde_json::Value::String(s) => Value::String(SharedString::from(s.as_str())), + serde_json::Value::Bool(b) => Value::Bool(*b), + // Slint's Value::Number takes f64. JSON integers arrive as i64; + // the i64→f64 cast may lose precision for values > 2^52, which is + // acceptable for UI property values (scores, counters, etc.). + #[allow(clippy::cast_precision_loss)] + serde_json::Value::Number(n) => n + .as_i64() + .map_or_else(|| Value::Number(n.as_f64().unwrap_or(0.0)), |i| Value::Number(i as f64)), + _ => Value::Void, + } +} + +/// Convert a slice of premultiplied-alpha pixels to straight-alpha RGBA8. +/// +/// The `as u8` casts below are safe: for premultiplied data the invariant +/// `channel <= alpha` holds, so `channel * 255 / alpha <= 255` — always +/// fits in a `u8`. +#[allow(clippy::cast_possible_truncation)] +fn premultiplied_to_straight_rgba(pixels: &[PremultipliedRgbaColor]) -> Vec { + let mut bytes = Vec::with_capacity(pixels.len() * 4); + for px in pixels { + if px.alpha == 0 { + bytes.extend_from_slice(&[0, 0, 0, 0]); + } else if px.alpha == 255 { + bytes.extend_from_slice(&[px.red, px.green, px.blue, 255]); + } else { + // Un-premultiply: channel = premultiplied * 255 / alpha + let a = u16::from(px.alpha); + let r = (u16::from(px.red) * 255 / a) as u8; + let g = (u16::from(px.green) * 255 / a) as u8; + let b = (u16::from(px.blue) * 255 / a) as u8; + bytes.extend_from_slice(&[r, g, b, px.alpha]); + } + } + bytes +} + +// ── Slint platform backend ────────────────────────────────────────────────── + +// Thread-local holding the window adapter that `SlintBackend::create_window_adapter()` +// should return. Before calling `definition.create()` / `component.show()`, +// `create_slint_instance` swaps in the correct per-node window so Slint +// associates the component with the right `MinimalSoftwareWindow`. +thread_local! { + static CURRENT_WINDOW: RefCell>> = const { RefCell::new(None) }; +} + +/// Minimal Slint platform backend. +/// +/// Required by Slint's runtime to know where to render. Set exactly once +/// on the shared Slint thread. Returns whatever window adapter is currently +/// stored in the `CURRENT_WINDOW` thread-local. +struct SlintBackend; + +impl slint::platform::Platform for SlintBackend { + fn create_window_adapter(&self) -> Result, slint::PlatformError> { + CURRENT_WINDOW.with(|cell| { + cell.borrow() + .clone() + .ok_or_else(|| slint::PlatformError::Other("No current Slint window set".into())) + }) + } +} + +// ── Node ──────────────────────────────────────────────────────────────────── + +/// Standalone Slint UI video source node. +/// +/// No input pins. Outputs `PacketType::RawVideo(Rgba8)` on `"out"`. +/// Follows the Ready → Start lifecycle (same as `ColorBarsNode`). +pub struct SlintNode { + config: SlintConfig, +} + +#[async_trait] +impl ProcessorNode for SlintNode { + fn input_pins(&self) -> Vec { + vec![] + } + + fn output_pins(&self) -> Vec { + vec![OutputPin { + name: "out".to_string(), + produces_type: PacketType::RawVideo(RawVideoFormat { + width: None, + height: None, + pixel_format: PixelFormat::Rgba8, + }), + cardinality: PinCardinality::Broadcast, + }] + } + + #[allow(clippy::too_many_lines)] + async fn run(mut self: Box, mut context: NodeContext) -> Result<(), StreamKitError> { + let node_name = context.output_sender.node_name().to_string(); + state_helpers::emit_initializing(&context.state_tx, &node_name); + + // Validate config. + if let Err(e) = self.config.validate() { + return Err(StreamKitError::Configuration(e)); + } + + let width = self.config.width; + let height = self.config.height; + let fps = self.config.fps; + let frame_count = self.config.frame_count; + let duration_us = 1_000_000 / u64::from(fps); + + tracing::info!( + "SlintNode starting: {}x{} @ {} fps, slint_file='{}', frame_count={}", + width, + height, + fps, + self.config.slint_file, + frame_count, + ); + + // Source nodes emit Ready state and wait for Start signal. + state_helpers::emit_ready(&context.state_tx, &node_name); + tracing::info!("SlintNode ready, waiting for start signal"); + + loop { + match context.control_rx.recv().await { + Some(NodeControlMessage::Start) => { + tracing::info!("SlintNode received start signal"); + break; + }, + Some(NodeControlMessage::UpdateParams(_)) => {}, + Some(NodeControlMessage::Shutdown) => { + tracing::info!("SlintNode received shutdown before start"); + return Ok(()); + }, + None => { + tracing::warn!("Control channel closed before start signal received"); + return Ok(()); + }, + } + } + + state_helpers::emit_running(&context.state_tx, &node_name); + + let mut stats_tracker = NodeStatsTracker::new(node_name.clone(), context.stats_tx.clone()); + + // ── Register with the shared Slint thread ─────────────────────── + let node_id = uuid::Uuid::new_v4(); + let thread_handle = shared_slint_thread(); + + let (result_tx, result_rx) = std::sync::mpsc::channel::(); + + if thread_handle + .work_tx + .send(SlintWorkItem::Register { node_id, config: self.config.clone(), result_tx }) + .is_err() + { + return Err(StreamKitError::Runtime("Shared Slint thread is not running".to_string())); + } + + // Wait for init result from the shared thread. + match result_rx.recv() { + Ok(SlintThreadResult::InitOk) => { + tracing::info!("SlintNode '{}' registered on shared thread", node_id); + }, + Ok(SlintThreadResult::InitErr(e)) => { + return Err(StreamKitError::Configuration(format!( + "Slint instance creation failed: {e}" + ))); + }, + Ok(SlintThreadResult::Frame { .. }) => { + return Err(StreamKitError::Runtime( + "Unexpected frame result during init".to_string(), + )); + }, + Err(_) => { + return Err(StreamKitError::Runtime( + "Shared Slint thread channel closed during init".to_string(), + )); + }, + } + + // ── Frame generation loop ─────────────────────────────────────── + // Real-time pacing for dynamic (frame_count == 0) mode. + let mut interval = if frame_count == 0 { + let period = std::time::Duration::from_micros(duration_us); + Some(tokio::time::interval(period)) + } else { + None + }; + + let mut seq: u64 = 0; + + loop { + // Honour finite frame count. + if frame_count > 0 && seq >= u64::from(frame_count) { + tracing::info!("SlintNode finished after {seq} frames"); + break; + } + + // Check cancellation. + if let Some(token) = &context.cancellation_token { + if token.is_cancelled() { + tracing::info!("SlintNode cancelled after {seq} frames"); + break; + } + } + + // Pace in real-time mode. + if let Some(ref mut iv) = interval { + tokio::select! { + _ = iv.tick() => {}, + Some(msg) = context.control_rx.recv() => { + match msg { + NodeControlMessage::Shutdown => { + tracing::info!("SlintNode received shutdown during generation"); + break; + }, + NodeControlMessage::UpdateParams(params) => { + if let Ok(new_config) = serde_json::from_value::(params) { + if new_config.validate().is_ok() { + self.config = new_config.clone(); + let _ = thread_handle.work_tx.send( + SlintWorkItem::UpdateConfig { node_id, config: new_config }, + ); + } + } + }, + NodeControlMessage::Start => {}, + } + continue; + } + } + } + + // In batch mode, still check for shutdown. + if interval.is_none() { + if let Ok(msg) = context.control_rx.try_recv() { + match msg { + NodeControlMessage::Shutdown => { + tracing::info!("SlintNode received shutdown during batch generation"); + break; + }, + NodeControlMessage::UpdateParams(params) => { + if let Ok(new_config) = serde_json::from_value::(params) { + if new_config.validate().is_ok() { + self.config = new_config.clone(); + let _ = + thread_handle.work_tx.send(SlintWorkItem::UpdateConfig { + node_id, + config: new_config, + }); + } + } + }, + NodeControlMessage::Start => {}, + } + } + } + + // Request a frame from the shared thread. + if thread_handle.work_tx.send(SlintWorkItem::Render { node_id }).is_err() { + tracing::error!("Shared Slint thread exited unexpectedly"); + break; + } + + // Wait for the rendered frame. + let rgba_data = match result_rx.recv() { + Ok(SlintThreadResult::Frame { rgba_data }) => rgba_data, + Ok(_) => { + tracing::warn!("Unexpected result from shared Slint thread"); + continue; + }, + Err(_) => { + tracing::error!("Shared Slint thread result channel closed"); + break; + }, + }; + + let timestamp_us = seq * duration_us; + let metadata = Some(PacketMetadata { + timestamp_us: Some(timestamp_us), + duration_us: Some(duration_us), + sequence: Some(seq), + keyframe: Some(true), + }); + + let frame = if let Some(pool) = &context.video_pool { + let mut pooled = pool.get(rgba_data.len()); + pooled.as_mut_slice().copy_from_slice(&rgba_data); + VideoFrame::from_pooled(width, height, PixelFormat::Rgba8, pooled, metadata)? + } else { + VideoFrame::with_metadata(width, height, PixelFormat::Rgba8, rgba_data, metadata)? + }; + + if context.output_sender.send("out", Packet::Video(frame)).await.is_err() { + tracing::debug!("Output channel closed, stopping SlintNode"); + break; + } + + stats_tracker.sent(); + stats_tracker.maybe_send(); + seq += 1; + } + + // Unregister from the shared thread so it can drop our instance. + let _ = thread_handle.work_tx.send(SlintWorkItem::Unregister { node_id }); + + stats_tracker.force_send(); + state_helpers::emit_stopped(&context.state_tx, &node_name, "completed"); + Ok(()) + } +} + +// ── Registration ──────────────────────────────────────────────────────────── + +#[allow(clippy::expect_used, clippy::missing_panics_doc)] +pub fn register_slint_nodes(registry: &mut NodeRegistry) { + let default_node = SlintNode { + config: SlintConfig { + width: default_width(), + height: default_height(), + fps: default_fps(), + slint_file: String::new(), + component: None, + properties: HashMap::new(), + property_keyframes: Vec::new(), + keyframe_interval: default_keyframe_interval(), + frame_count: default_frame_count(), + }, + }; + + registry.register_static_with_description( + "video::slint", + |params| { + let config: SlintConfig = config_helpers::parse_config_optional(params)?; + if let Err(e) = config.validate() { + return Err(StreamKitError::Configuration(e)); + } + Ok(Box::new(SlintNode { config })) + }, + serde_json::to_value(schema_for!(SlintConfig)) + .expect("SlintConfig schema should serialize to JSON"), + StaticPins { inputs: default_node.input_pins(), outputs: default_node.output_pins() }, + vec!["video".to_string(), "generators".to_string()], + false, + "Renders a Slint UI component into RGBA8 video frames. \ + Compiles a .slint file at init and produces frames at the configured \ + resolution and frame rate. Properties can be updated at runtime via UpdateParams.", + ); +} diff --git a/samples/pipelines/dynamic/video_moq_slint_scoreboard.yml b/samples/pipelines/dynamic/video_moq_slint_scoreboard.yml new file mode 100644 index 00000000..97589c76 --- /dev/null +++ b/samples/pipelines/dynamic/video_moq_slint_scoreboard.yml @@ -0,0 +1,119 @@ +# SPDX-FileCopyrightText: © 2025 StreamKit Contributors +# +# SPDX-License-Identifier: MPL-2.0 + +# Demonstrates Slint overlays (scoreboard + lower third) composited onto +# colorbars and streamed via MoQ, with runtime property updates. +# +# Each Slint overlay is a standalone video::slint source node whose output +# is wired into the compositor as a regular video layer. +# +# Requires: cargo build --features slint +# +# After starting the pipeline, update properties at runtime: +# +# curl -X POST http://localhost:4545/api/v1/sessions//nodes/scoreboard/update \ +# -H 'Content-Type: application/json' \ +# -d '{ +# "properties": { +# "home_score": 4, +# "clock_start": 2147, +# "period": "2ND" +# } +# }' + +name: Video Slint Scoreboard + Lower Third (MoQ) +description: Composites colorbars with Slint scoreboard and lower-third overlays, streams via MoQ with runtime property updates +mode: dynamic +client: + gateway_path: /moq/video + watch: + broadcast: output + audio: false + video: true + +nodes: + colorbars_bg: + kind: video::colorbars + params: + width: 1280 + height: 720 + fps: 30 + pixel_format: rgba8 + draw_time: true + + scoreboard: + kind: video::slint + params: + width: 420 + height: 80 + fps: 30 + slint_file: samples/slint/scoreboard.slint + properties: + home_team: "EAGLES" + away_team: "HAWKS" + home_score: 3 + away_score: 1 + clock_start: 754 + period: "2ND" + + lower_third: + kind: video::slint + params: + width: 350 + height: 70 + fps: 30 + slint_file: samples/slint/lower_third.slint + properties: + name: "Alex Johnson" + title: "Forward · #17" + visible: true + + compositor: + kind: video::compositor + params: + width: 1280 + height: 720 + num_inputs: 3 + layers: + in_0: + opacity: 1.0 + z_index: 0 + in_1: + rect: + x: 430 + y: 20 + width: 420 + height: 80 + opacity: 1.0 + z_index: 10 + in_2: + rect: + x: 50 + y: 600 + width: 350 + height: 70 + opacity: 1.0 + z_index: 11 + needs: + - colorbars_bg + - scoreboard + - lower_third + + pixel_convert: + kind: video::pixel_convert + params: + output_format: nv12 + needs: compositor + + vp9_encoder: + kind: video::vp9::encoder + needs: pixel_convert + + moq_peer: + kind: transport::moq::peer + params: + gateway_path: /moq/video + output_broadcast: output + allow_reconnect: true + needs: vp9_encoder diff --git a/samples/pipelines/oneshot/video_slint_scoreboard.yml b/samples/pipelines/oneshot/video_slint_scoreboard.yml new file mode 100644 index 00000000..5dca4b22 --- /dev/null +++ b/samples/pipelines/oneshot/video_slint_scoreboard.yml @@ -0,0 +1,112 @@ +# SPDX-FileCopyrightText: © 2025 StreamKit Contributors +# +# SPDX-License-Identifier: MPL-2.0 + +# Demonstrates a Slint scoreboard composited onto colorbars. +# +# The scoreboard is a standalone video::slint source node that renders +# RGBA8 frames via the slint-interpreter software renderer. Its output +# is wired into the compositor as a regular video layer — no special +# integration in the compositor itself. +# +# Requires: cargo build --features slint +# +# Base properties set the initial state; the clock ticks automatically +# once per second from `clock_start`. `property_keyframes` cycles the +# score every ~3 s so the output is not 100 % static. +# For runtime updates see the dynamic/video_moq_slint_scoreboard.yml pipeline. + +name: Video Slint Scoreboard (Oneshot) +description: Composites colorbars with a Slint scoreboard overlay, encodes to VP9, and streams a WebM via http_output +mode: oneshot +client: + input: + type: none + output: + type: video + +nodes: + colorbars_bg: + kind: video::colorbars + params: + width: 1280 + height: 720 + fps: 30 + frame_count: 300 + pixel_format: rgba8 + draw_time: true + draw_time_use_pts: true + + scoreboard: + kind: video::slint + params: + width: 420 + height: 80 + fps: 30 + frame_count: 300 + slint_file: samples/slint/scoreboard.slint + properties: + home_team: "EAGLES" + away_team: "HAWKS" + home_score: 3 + away_score: 1 + clock_start: 754 + period: "2ND" + keyframe_interval: 90 + property_keyframes: + - home_score: 3 + away_score: 1 + - home_score: 3 + away_score: 2 + - home_score: 4 + away_score: 2 + + compositor: + kind: video::compositor + params: + width: 1280 + height: 720 + num_inputs: 2 + layers: + in_0: + opacity: 1.0 + z_index: 0 + in_1: + rect: + x: 430 + y: 20 + width: 420 + height: 80 + opacity: 1.0 + z_index: 10 + needs: + - colorbars_bg + - scoreboard + + pixel_convert: + kind: video::pixel_convert + params: + output_format: nv12 + needs: compositor + + vp9_encoder: + kind: video::vp9::encoder + needs: pixel_convert + + webm_muxer: + kind: containers::webm::muxer + params: + video_width: 1280 + video_height: 720 + streaming_mode: live + needs: vp9_encoder + + pacer: + kind: core::pacer + needs: webm_muxer + + http_output: + kind: streamkit::http_output + params: + content_type: 'video/webm; codecs="vp9"' + needs: pacer diff --git a/samples/slint/lower_third.slint b/samples/slint/lower_third.slint new file mode 100644 index 00000000..d109df5e --- /dev/null +++ b/samples/slint/lower_third.slint @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: © 2025 StreamKit Contributors +// +// SPDX-License-Identifier: MPL-2.0 + +// Broadcast lower-third overlay with a slide-in animation. +// +// Set `visible` to `true` to slide in, `false` to slide out. +// Properties can be updated at runtime via UpdateParams JSON: +// name, title, visible + +export component LowerThird inherits Window { + in property name: "Player Name"; + in property title: "Position"; + in property visible: true; + + width: 350px; + height: 70px; + clip: true; + background: transparent; + + // Content container that slides in/out. + Rectangle { + x: root.visible ? 0px : -360px; + y: 0px; + width: 350px; + height: 70px; + animate x { duration: 400ms; easing: ease-out; } + + // Accent bar (left edge) + Rectangle { + x: 0px; + y: 0px; + width: 5px; + height: 70px; + background: #e63946; + } + + // Background panel + Rectangle { + x: 5px; + y: 0px; + width: 345px; + height: 70px; + background: #1d3557e6; + + VerticalLayout { + padding-left: 14px; + padding-top: 10px; + padding-bottom: 10px; + spacing: 4px; + + Text { + text: root.name; + color: #ffffff; + font-size: 20px; + font-weight: 700; + } + Text { + text: root.title; + color: #a8dadc; + font-size: 14px; + } + } + } + } +} diff --git a/samples/slint/scoreboard.slint b/samples/slint/scoreboard.slint new file mode 100644 index 00000000..d1939709 --- /dev/null +++ b/samples/slint/scoreboard.slint @@ -0,0 +1,118 @@ +// SPDX-FileCopyrightText: © 2025 StreamKit Contributors +// +// SPDX-License-Identifier: MPL-2.0 + +// Sports scoreboard overlay for the StreamKit compositor. +// +// Properties can be updated at runtime via UpdateParams JSON: +// home_team, away_team, home_score, away_score, clock_start, period +// +// The clock ticks automatically once per second from `clock_start` +// (total seconds). Set `clock_running` to false to freeze it. + +export component Scoreboard inherits Window { + in property home_team: "HOME"; + in property away_team: "AWAY"; + in property home_score: 0; + in property away_score: 0; + /// Starting time in total seconds (e.g. 754 = "12:34"). + in property clock_start: 0; + in property clock_running: true; + in property period: "1ST"; + + // Internal elapsed seconds counter driven by the Timer below. + property elapsed: 0; + property total_seconds: root.clock_start + root.elapsed; + property minutes: Math.floor(root.total_seconds / 60); + property secs: Math.mod(root.total_seconds, 60); + + // Format as MM:SS — Slint doesn't have zero-pad, so we build it + // with a ternary for the leading zero on each part. + property clock_display: + (root.minutes < 10 ? "0" : "") + root.minutes + + ":" + + (root.secs < 10 ? "0" : "") + root.secs; + + width: 420px; + height: 80px; + // Transparent window background so only the rounded rectangle is + // visible when composited onto the video frame. + background: transparent; + + // 1-second tick timer for the match clock. + Timer { + interval: 1s; + running: root.clock_running; + triggered() => { + root.elapsed += 1; + } + } + + Rectangle { + background: #1a1a2ecc; + border-radius: 8px; + width: 100%; + height: 100%; + + HorizontalLayout { + padding: 12px; + spacing: 8px; + alignment: center; + + // Home team + VerticalLayout { + alignment: center; + Text { + text: root.home_team; + color: #e0e0e0; + font-size: 14px; + horizontal-alignment: center; + } + Text { + text: root.home_score; + color: #ffffff; + font-size: 28px; + font-weight: 700; + horizontal-alignment: center; + } + } + + // Separator / clock + VerticalLayout { + alignment: center; + min-width: 80px; + Text { + text: root.clock_display; + color: #ffcc00; + font-size: 18px; + font-weight: 700; + horizontal-alignment: center; + } + Text { + text: root.period; + color: #aaaaaa; + font-size: 12px; + horizontal-alignment: center; + } + } + + // Away team + VerticalLayout { + alignment: center; + Text { + text: root.away_team; + color: #e0e0e0; + font-size: 14px; + horizontal-alignment: center; + } + Text { + text: root.away_score; + color: #ffffff; + font-size: 28px; + font-weight: 700; + horizontal-alignment: center; + } + } + } + } +} From 34ba4f821dd43a6e7b422fa38d14f84dcb1d66c5 Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 14:43:14 +0000 Subject: [PATCH 02/13] fix(nodes/slint): use tokio::sync::mpsc for result channel and add serde default to slint_file - Switch result channel from std::sync::mpsc to tokio::sync::mpsc so the async run() method uses .recv().await instead of blocking the tokio worker thread. The Slint thread side uses blocking_send(). - Add #[serde(default)] to SlintConfig.slint_file so partial UpdateParams JSON (e.g. only properties) deserializes correctly instead of silently failing. Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- crates/nodes/src/video/slint.rs | 35 ++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/crates/nodes/src/video/slint.rs b/crates/nodes/src/video/slint.rs index c58e8951..553ad951 100644 --- a/crates/nodes/src/video/slint.rs +++ b/crates/nodes/src/video/slint.rs @@ -87,6 +87,7 @@ pub struct SlintConfig { #[serde(default = "default_fps")] pub fps: u32, /// Path to the `.slint` file (must start with `samples/slint/`). + #[serde(default)] pub slint_file: String, /// Name of the exported component to instantiate. When omitted, the /// first exported component in the file is used. @@ -167,7 +168,9 @@ fn validate_slint_asset_path(path: &str) -> Result<(), String> { // // Each node gets a unique `NodeId` (UUID) and communicates with the shared // thread via tagged work items. Results are sent back on a per-node -// `std::sync::mpsc` channel. +// `tokio::sync::mpsc` channel (using `blocking_send` on the Slint thread +// so the async `run()` method can `.recv().await` without blocking the +// tokio worker thread). /// Opaque identifier for a node's instance on the shared Slint thread. type NodeId = uuid::Uuid; @@ -180,7 +183,7 @@ enum SlintWorkItem { Register { node_id: NodeId, config: SlintConfig, - result_tx: std::sync::mpsc::Sender, + result_tx: tokio::sync::mpsc::Sender, }, /// Request a single rendered frame for the given node. Render { node_id: NodeId }, @@ -235,7 +238,7 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { struct NodeState { instance: SlintInstance, config: SlintConfig, - result_tx: std::sync::mpsc::Sender, + result_tx: tokio::sync::mpsc::Sender, } let mut nodes: HashMap = HashMap::new(); @@ -251,12 +254,12 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { node_id, config.slint_file ); - let _ = result_tx.send(SlintThreadResult::InitOk); + let _ = result_tx.blocking_send(SlintThreadResult::InitOk); nodes.insert(node_id, NodeState { instance, config, result_tx }); }, Err(e) => { tracing::error!("Failed to create Slint instance '{}': {e}", node_id); - let _ = result_tx.send(SlintThreadResult::InitErr(e.to_string())); + let _ = result_tx.blocking_send(SlintThreadResult::InitErr(e.to_string())); }, } }, @@ -265,7 +268,7 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { let rgba_data = render_slint_frame(&mut state.instance, &state.config); // If the result channel is closed the node has been dropped; // clean up its state on the next Unregister (or here eagerly). - if state.result_tx.send(SlintThreadResult::Frame { rgba_data }).is_err() { + if state.result_tx.blocking_send(SlintThreadResult::Frame { rgba_data }).is_err() { nodes.remove(&node_id); } } @@ -593,7 +596,7 @@ impl ProcessorNode for SlintNode { let node_id = uuid::Uuid::new_v4(); let thread_handle = shared_slint_thread(); - let (result_tx, result_rx) = std::sync::mpsc::channel::(); + let (result_tx, mut result_rx) = tokio::sync::mpsc::channel::(2); if thread_handle .work_tx @@ -604,21 +607,21 @@ impl ProcessorNode for SlintNode { } // Wait for init result from the shared thread. - match result_rx.recv() { - Ok(SlintThreadResult::InitOk) => { + match result_rx.recv().await { + Some(SlintThreadResult::InitOk) => { tracing::info!("SlintNode '{}' registered on shared thread", node_id); }, - Ok(SlintThreadResult::InitErr(e)) => { + Some(SlintThreadResult::InitErr(e)) => { return Err(StreamKitError::Configuration(format!( "Slint instance creation failed: {e}" ))); }, - Ok(SlintThreadResult::Frame { .. }) => { + Some(SlintThreadResult::Frame { .. }) => { return Err(StreamKitError::Runtime( "Unexpected frame result during init".to_string(), )); }, - Err(_) => { + None => { return Err(StreamKitError::Runtime( "Shared Slint thread channel closed during init".to_string(), )); @@ -710,13 +713,13 @@ impl ProcessorNode for SlintNode { } // Wait for the rendered frame. - let rgba_data = match result_rx.recv() { - Ok(SlintThreadResult::Frame { rgba_data }) => rgba_data, - Ok(_) => { + let rgba_data = match result_rx.recv().await { + Some(SlintThreadResult::Frame { rgba_data }) => rgba_data, + Some(_) => { tracing::warn!("Unexpected result from shared Slint thread"); continue; }, - Err(_) => { + None => { tracing::error!("Shared Slint thread result channel closed"); break; }, From 2010fe07f7ec5943ae322dd45fcacea556340f28 Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 14:43:24 +0000 Subject: [PATCH 03/13] style: rustfmt Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- crates/nodes/src/video/slint.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/nodes/src/video/slint.rs b/crates/nodes/src/video/slint.rs index 553ad951..38ea6152 100644 --- a/crates/nodes/src/video/slint.rs +++ b/crates/nodes/src/video/slint.rs @@ -268,7 +268,11 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { let rgba_data = render_slint_frame(&mut state.instance, &state.config); // If the result channel is closed the node has been dropped; // clean up its state on the next Unregister (or here eagerly). - if state.result_tx.blocking_send(SlintThreadResult::Frame { rgba_data }).is_err() { + if state + .result_tx + .blocking_send(SlintThreadResult::Frame { rgba_data }) + .is_err() + { nodes.remove(&node_id); } } From b6b3e87548b897431d11db306f67a5d1ca683031 Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 14:50:46 +0000 Subject: [PATCH 04/13] fix(nodes/slint): merge only runtime fields in UpdateParams instead of replacing whole config Partial UpdateParams JSON (e.g. {"properties": {"score": 5}}) would silently fail because the deserialized SlintConfig had an empty slint_file which failed validate(). Now UpdateParams merges only the runtime-changeable fields (properties, property_keyframes, keyframe_interval) into the existing config, preserving immutable init-time fields. Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- crates/nodes/src/video/slint.rs | 41 ++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/crates/nodes/src/video/slint.rs b/crates/nodes/src/video/slint.rs index 38ea6152..eb01b588 100644 --- a/crates/nodes/src/video/slint.rs +++ b/crates/nodes/src/video/slint.rs @@ -141,6 +141,20 @@ impl SlintConfig { } validate_slint_asset_path(&self.slint_file) } + + /// Merge runtime-changeable fields from an `UpdateParams` payload into + /// this config. + /// + /// Only `properties`, `property_keyframes`, and `keyframe_interval` are + /// updated. Immutable init-time fields (`slint_file`, `component`, + /// `width`, `height`, `fps`, `frame_count`) are preserved from the + /// original config so that partial JSON payloads (e.g. + /// `{"properties": {"score": 5}}`) work without re-validating the path. + fn merge_update(&mut self, update: &Self) { + self.properties.clone_from(&update.properties); + self.property_keyframes.clone_from(&update.property_keyframes); + self.keyframe_interval = update.keyframe_interval; + } } /// Validates that a Slint asset path is safe to read. @@ -669,13 +683,11 @@ impl ProcessorNode for SlintNode { break; }, NodeControlMessage::UpdateParams(params) => { - if let Ok(new_config) = serde_json::from_value::(params) { - if new_config.validate().is_ok() { - self.config = new_config.clone(); - let _ = thread_handle.work_tx.send( - SlintWorkItem::UpdateConfig { node_id, config: new_config }, - ); - } + if let Ok(update) = serde_json::from_value::(params) { + self.config.merge_update(&update); + let _ = thread_handle.work_tx.send( + SlintWorkItem::UpdateConfig { node_id, config: self.config.clone() }, + ); } }, NodeControlMessage::Start => {}, @@ -694,15 +706,12 @@ impl ProcessorNode for SlintNode { break; }, NodeControlMessage::UpdateParams(params) => { - if let Ok(new_config) = serde_json::from_value::(params) { - if new_config.validate().is_ok() { - self.config = new_config.clone(); - let _ = - thread_handle.work_tx.send(SlintWorkItem::UpdateConfig { - node_id, - config: new_config, - }); - } + if let Ok(update) = serde_json::from_value::(params) { + self.config.merge_update(&update); + let _ = thread_handle.work_tx.send(SlintWorkItem::UpdateConfig { + node_id, + config: self.config.clone(), + }); } }, NodeControlMessage::Start => {}, From 95a5844b1299818c255594742b5b1bbc40078850 Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 14:58:50 +0000 Subject: [PATCH 05/13] fix(nodes/slint): merge properties via extend instead of replacing in UpdateParams Partial UpdateParams JSON (e.g. {"properties": {"home_score": 4}}) was replacing the entire properties map, dropping unmentioned keys. Now uses extend() to merge only the provided keys. property_keyframes and keyframe_interval are treated as init-time config and left unchanged by merge_update, since serde defaults make it impossible to distinguish absent fields from user-provided empty values. Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- crates/nodes/src/video/slint.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/crates/nodes/src/video/slint.rs b/crates/nodes/src/video/slint.rs index eb01b588..151751c3 100644 --- a/crates/nodes/src/video/slint.rs +++ b/crates/nodes/src/video/slint.rs @@ -142,18 +142,17 @@ impl SlintConfig { validate_slint_asset_path(&self.slint_file) } - /// Merge runtime-changeable fields from an `UpdateParams` payload into - /// this config. + /// Merge runtime property changes from an `UpdateParams` payload. /// - /// Only `properties`, `property_keyframes`, and `keyframe_interval` are - /// updated. Immutable init-time fields (`slint_file`, `component`, - /// `width`, `height`, `fps`, `frame_count`) are preserved from the - /// original config so that partial JSON payloads (e.g. - /// `{"properties": {"score": 5}}`) work without re-validating the path. + /// Only `properties` values are merged (via `extend`) so that a partial + /// JSON like `{"properties": {"home_score": 4}}` updates the named keys + /// without dropping unmentioned ones. Init-time fields (`slint_file`, + /// `component`, `width`, `height`, `fps`, `frame_count`, + /// `property_keyframes`, `keyframe_interval`) are left unchanged because + /// serde defaults make it impossible to distinguish "user sent empty" from + /// "field was absent in the JSON". fn merge_update(&mut self, update: &Self) { - self.properties.clone_from(&update.properties); - self.property_keyframes.clone_from(&update.property_keyframes); - self.keyframe_interval = update.keyframe_interval; + self.properties.extend(update.properties.iter().map(|(k, v)| (k.clone(), v.clone()))); } } From fdc908d82790616cfa844e51dbb87184106b68f9 Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 15:06:21 +0000 Subject: [PATCH 06/13] feat(samples): replace oneshot scoreboard with static watermark overlay The scoreboard's Slint Timer is wall-clock-based and doesn't advance meaningfully in batch mode (frame_count > 0) where frames render faster than real-time. Replace the oneshot demo with a static watermark badge that works correctly in both batch and real-time modes. The scoreboard remains available in the dynamic pipeline (video_moq_slint_scoreboard.yml) where frame_count: 0 ensures real-time pacing and timers work as expected. Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- ...oreboard.yml => video_slint_watermark.yml} | 48 ++++++--------- samples/slint/watermark.slint | 59 +++++++++++++++++++ 2 files changed, 76 insertions(+), 31 deletions(-) rename samples/pipelines/oneshot/{video_slint_scoreboard.yml => video_slint_watermark.yml} (57%) create mode 100644 samples/slint/watermark.slint diff --git a/samples/pipelines/oneshot/video_slint_scoreboard.yml b/samples/pipelines/oneshot/video_slint_watermark.yml similarity index 57% rename from samples/pipelines/oneshot/video_slint_scoreboard.yml rename to samples/pipelines/oneshot/video_slint_watermark.yml index 5dca4b22..fb26869c 100644 --- a/samples/pipelines/oneshot/video_slint_scoreboard.yml +++ b/samples/pipelines/oneshot/video_slint_watermark.yml @@ -2,22 +2,20 @@ # # SPDX-License-Identifier: MPL-2.0 -# Demonstrates a Slint scoreboard composited onto colorbars. +# Demonstrates a Slint watermark composited onto colorbars. # -# The scoreboard is a standalone video::slint source node that renders +# The watermark is a standalone video::slint source node that renders # RGBA8 frames via the slint-interpreter software renderer. Its output # is wired into the compositor as a regular video layer — no special # integration in the compositor itself. # # Requires: cargo build --features slint # -# Base properties set the initial state; the clock ticks automatically -# once per second from `clock_start`. `property_keyframes` cycles the -# score every ~3 s so the output is not 100 % static. -# For runtime updates see the dynamic/video_moq_slint_scoreboard.yml pipeline. +# For runtime property updates see the dynamic/video_moq_slint_scoreboard.yml +# pipeline which uses the scoreboard overlay in real-time mode. -name: Video Slint Scoreboard (Oneshot) -description: Composites colorbars with a Slint scoreboard overlay, encodes to VP9, and streams a WebM via http_output +name: Video Slint Watermark (Oneshot) +description: Composites colorbars with a Slint watermark overlay, encodes to VP9, and streams a WebM via http_output mode: oneshot client: input: @@ -37,29 +35,17 @@ nodes: draw_time: true draw_time_use_pts: true - scoreboard: + watermark: kind: video::slint params: - width: 420 - height: 80 + width: 200 + height: 50 fps: 30 frame_count: 300 - slint_file: samples/slint/scoreboard.slint + slint_file: samples/slint/watermark.slint properties: - home_team: "EAGLES" - away_team: "HAWKS" - home_score: 3 - away_score: 1 - clock_start: 754 - period: "2ND" - keyframe_interval: 90 - property_keyframes: - - home_score: 3 - away_score: 1 - - home_score: 3 - away_score: 2 - - home_score: 4 - away_score: 2 + channel: "StreamKit" + tagline: "LIVE" compositor: kind: video::compositor @@ -73,15 +59,15 @@ nodes: z_index: 0 in_1: rect: - x: 430 + x: 1060 y: 20 - width: 420 - height: 80 - opacity: 1.0 + width: 200 + height: 50 + opacity: 0.9 z_index: 10 needs: - colorbars_bg - - scoreboard + - watermark pixel_convert: kind: video::pixel_convert diff --git a/samples/slint/watermark.slint b/samples/slint/watermark.slint new file mode 100644 index 00000000..76330d19 --- /dev/null +++ b/samples/slint/watermark.slint @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: © 2025 StreamKit Contributors +// +// SPDX-License-Identifier: MPL-2.0 + +// Semi-transparent channel watermark / bug overlay. +// +// A simple branded badge suitable for compositing into a corner of the +// video frame. All text is property-driven and can be updated at runtime +// via UpdateParams JSON: channel, tagline. + +export component Watermark inherits Window { + in property channel: "StreamKit"; + in property tagline: "Live"; + + width: 200px; + height: 50px; + background: transparent; + + Rectangle { + width: 100%; + height: 100%; + border-radius: 6px; + background: #000000aa; + + HorizontalLayout { + padding-left: 12px; + padding-right: 12px; + spacing: 8px; + alignment: center; + + // Accent dot (live indicator) + Rectangle { + width: 10px; + height: 10px; + border-radius: 5px; + background: #e63946; + vertical-alignment: center; + } + + VerticalLayout { + alignment: center; + spacing: 1px; + + Text { + text: root.channel; + color: #ffffff; + font-size: 16px; + font-weight: 700; + } + Text { + text: root.tagline; + color: #a0a0a0; + font-size: 11px; + letter-spacing: 1.5px; + } + } + } + } +} From b1860ef68300984eff4463f08f8b62b90a76b964 Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 15:31:55 +0000 Subject: [PATCH 07/13] fix(nodes/slint): call request_redraw() before draw_if_needed() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without an explicit request_redraw(), MinimalSoftwareWindow's draw_if_needed() only invokes the render closure when the window is marked dirty. For static UIs (no property changes, no active timers) the window stops being dirty after the initial show(), causing draw_if_needed() to skip rendering and leave the pixel buffer zeroed (fully transparent). This made overlays like the watermark invisible. Calling request_redraw() before every draw_if_needed() guarantees a full repaint each frame. With RepaintBufferType::NewBuffer there is no wasted incremental-diff cost — the renderer always paints the entire scene anyway. Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- crates/nodes/src/video/slint.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/nodes/src/video/slint.rs b/crates/nodes/src/video/slint.rs index 151751c3..b2739a64 100644 --- a/crates/nodes/src/video/slint.rs +++ b/crates/nodes/src/video/slint.rs @@ -440,6 +440,13 @@ fn render_slint_frame(instance: &mut SlintInstance, config: &SlintConfig) -> Vec // (e.g. slide-in transitions) advance on each tick. slint::platform::update_timers_and_animations(); + // Force a full redraw every frame. With `RepaintBufferType::NewBuffer` + // the renderer always paints the entire scene, so there is no wasted + // incremental-diff cost. Without this call, `draw_if_needed` would + // skip rendering once the window is no longer dirty (e.g. static UIs + // with no property changes), leaving the pixel buffer zeroed. + instance.window.request_redraw(); + // Render into the pixel buffer. let width = instance.width; instance.window.draw_if_needed(|renderer| { From cbe58688f658a2549d14192ccfd5c4e2efcd2b7d Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 15:33:36 +0000 Subject: [PATCH 08/13] perf(nodes/slint): cache rendered frame buffer between unchanged frames Static UIs and frames between keyframe boundaries now reuse the previously rendered RGBA8 buffer instead of re-rendering through the Slint software renderer and premultiplied-to-straight conversion on every frame. Re-rendering is triggered only when: - The node is first registered (dirty = true) - An UpdateConfig work item arrives (runtime property change) - The keyframe index crosses a boundary The frame counter still advances on cached frames so keyframe boundaries are detected at the correct time. Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- crates/nodes/src/video/slint.rs | 49 +++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/crates/nodes/src/video/slint.rs b/crates/nodes/src/video/slint.rs index b2739a64..f2a66d50 100644 --- a/crates/nodes/src/video/slint.rs +++ b/crates/nodes/src/video/slint.rs @@ -252,6 +252,13 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { instance: SlintInstance, config: SlintConfig, result_tx: tokio::sync::mpsc::Sender, + /// Cached straight-alpha RGBA8 output from the last render. + /// Re-used when properties have not changed between frames. + cached_frame: Option>, + /// Keyframe index that produced `cached_frame`. + cached_keyframe_idx: Option, + /// Set by `UpdateConfig` to force a re-render on the next frame. + dirty: bool, } let mut nodes: HashMap = HashMap::new(); @@ -268,7 +275,14 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { config.slint_file ); let _ = result_tx.blocking_send(SlintThreadResult::InitOk); - nodes.insert(node_id, NodeState { instance, config, result_tx }); + nodes.insert(node_id, NodeState { + instance, + config, + result_tx, + cached_frame: None, + cached_keyframe_idx: None, + dirty: true, + }); }, Err(e) => { tracing::error!("Failed to create Slint instance '{}': {e}", node_id); @@ -278,7 +292,37 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { }, SlintWorkItem::Render { node_id } => { if let Some(state) = nodes.get_mut(&node_id) { - let rgba_data = render_slint_frame(&mut state.instance, &state.config); + // Determine the current keyframe index (if keyframes are configured). + let kf_idx = if state.config.property_keyframes.is_empty() { + None + } else { + let interval = state.config.keyframe_interval.max(1); + Some( + (state.instance.frame_counter / interval) as usize + % state.config.property_keyframes.len(), + ) + }; + + // Re-render only when properties have actually changed: + // config update (dirty flag) or keyframe boundary. + let need_render = + state.dirty || state.cached_keyframe_idx != kf_idx || state.cached_frame.is_none(); + + let rgba_data = if need_render { + let data = render_slint_frame(&mut state.instance, &state.config); + state.cached_frame = Some(data.clone()); + state.cached_keyframe_idx = kf_idx; + state.dirty = false; + data + } else { + // Advance frame counter even when reusing the cache so + // keyframe boundaries are detected at the right time. + state.instance.frame_counter = + state.instance.frame_counter.wrapping_add(1); + // SAFETY: need_render is false only when cached_frame is Some. + state.cached_frame.clone().unwrap_or_default() + }; + // If the result channel is closed the node has been dropped; // clean up its state on the next Unregister (or here eagerly). if state @@ -293,6 +337,7 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { SlintWorkItem::UpdateConfig { node_id, config } => { if let Some(state) = nodes.get_mut(&node_id) { state.config = config; + state.dirty = true; } }, SlintWorkItem::Unregister { node_id } => { From 992df4f1b4d0e2f3f1891f35edf84aac524b80d3 Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 15:33:53 +0000 Subject: [PATCH 09/13] fix(samples/slint): fix watermark compilation error and cache rendered frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove invalid 'vertical-alignment' property from Rectangle in watermark.slint — this caused Slint compilation to fail silently, producing no frames at all (the actual root cause of the invisible watermark). - Cache rendered RGBA8 buffer on the shared Slint thread. Static UIs and frames between keyframe boundaries now reuse the previously rendered buffer instead of re-rendering on every frame. Re-rendering triggers only on: first frame, UpdateConfig, or keyframe boundary. The frame counter still advances on cached frames so keyframe boundaries are detected at the correct time. Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- samples/slint/watermark.slint | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/slint/watermark.slint b/samples/slint/watermark.slint index 76330d19..8ef4a509 100644 --- a/samples/slint/watermark.slint +++ b/samples/slint/watermark.slint @@ -34,7 +34,6 @@ export component Watermark inherits Window { height: 10px; border-radius: 5px; background: #e63946; - vertical-alignment: center; } VerticalLayout { From f3f67239ac505f62a4c115eb2bf02e76a620ae3f Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 15:34:28 +0000 Subject: [PATCH 10/13] style(nodes/slint): fix formatting from pre-commit hook Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- crates/nodes/src/video/slint.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/crates/nodes/src/video/slint.rs b/crates/nodes/src/video/slint.rs index f2a66d50..c5d7c025 100644 --- a/crates/nodes/src/video/slint.rs +++ b/crates/nodes/src/video/slint.rs @@ -275,14 +275,17 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { config.slint_file ); let _ = result_tx.blocking_send(SlintThreadResult::InitOk); - nodes.insert(node_id, NodeState { - instance, - config, - result_tx, - cached_frame: None, - cached_keyframe_idx: None, - dirty: true, - }); + nodes.insert( + node_id, + NodeState { + instance, + config, + result_tx, + cached_frame: None, + cached_keyframe_idx: None, + dirty: true, + }, + ); }, Err(e) => { tracing::error!("Failed to create Slint instance '{}': {e}", node_id); @@ -305,8 +308,9 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { // Re-render only when properties have actually changed: // config update (dirty flag) or keyframe boundary. - let need_render = - state.dirty || state.cached_keyframe_idx != kf_idx || state.cached_frame.is_none(); + let need_render = state.dirty + || state.cached_keyframe_idx != kf_idx + || state.cached_frame.is_none(); let rgba_data = if need_render { let data = render_slint_frame(&mut state.instance, &state.config); @@ -317,8 +321,7 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { } else { // Advance frame counter even when reusing the cache so // keyframe boundaries are detected at the right time. - state.instance.frame_counter = - state.instance.frame_counter.wrapping_add(1); + state.instance.frame_counter = state.instance.frame_counter.wrapping_add(1); // SAFETY: need_render is false only when cached_frame is Some. state.cached_frame.clone().unwrap_or_default() }; From 7c4a89d58cc5b9f3ba69dd03ae431e0a528ff7c7 Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 15:43:53 +0000 Subject: [PATCH 11/13] fix(samples/slint): polish watermark layout and alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Wrap accent dot in a VerticalLayout with alignment:center so it is vertically centred within the badge row (previously top-aligned). - Shrink badge to 180×44 px for a tighter, cleaner look. - Slightly increase border-radius and padding for better proportions. - Use semi-bold LIVE tagline with higher-contrast white-70% colour. - Update pipeline YAML to match new badge dimensions (x=1080). Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- .../oneshot/video_slint_watermark.yml | 10 ++-- samples/slint/watermark.slint | 46 ++++++++++--------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/samples/pipelines/oneshot/video_slint_watermark.yml b/samples/pipelines/oneshot/video_slint_watermark.yml index fb26869c..3866343a 100644 --- a/samples/pipelines/oneshot/video_slint_watermark.yml +++ b/samples/pipelines/oneshot/video_slint_watermark.yml @@ -38,8 +38,8 @@ nodes: watermark: kind: video::slint params: - width: 200 - height: 50 + width: 180 + height: 44 fps: 30 frame_count: 300 slint_file: samples/slint/watermark.slint @@ -59,10 +59,10 @@ nodes: z_index: 0 in_1: rect: - x: 1060 + x: 1080 y: 20 - width: 200 - height: 50 + width: 180 + height: 44 opacity: 0.9 z_index: 10 needs: diff --git a/samples/slint/watermark.slint b/samples/slint/watermark.slint index 8ef4a509..948a1c60 100644 --- a/samples/slint/watermark.slint +++ b/samples/slint/watermark.slint @@ -10,47 +10,51 @@ export component Watermark inherits Window { in property channel: "StreamKit"; - in property tagline: "Live"; + in property tagline: "LIVE"; - width: 200px; - height: 50px; + width: 180px; + height: 44px; background: transparent; Rectangle { width: 100%; height: 100%; - border-radius: 6px; - background: #000000aa; + border-radius: 8px; + background: #00000099; HorizontalLayout { - padding-left: 12px; - padding-right: 12px; - spacing: 8px; - alignment: center; - - // Accent dot (live indicator) - Rectangle { - width: 10px; - height: 10px; - border-radius: 5px; - background: #e63946; + padding-left: 14px; + padding-right: 14px; + spacing: 10px; + + // Centre the accent dot vertically within the row. + VerticalLayout { + alignment: center; + + Rectangle { + width: 8px; + height: 8px; + border-radius: 4px; + background: #e63946; + } } VerticalLayout { alignment: center; - spacing: 1px; + spacing: 2px; Text { text: root.channel; color: #ffffff; - font-size: 16px; + font-size: 14px; font-weight: 700; } Text { text: root.tagline; - color: #a0a0a0; - font-size: 11px; - letter-spacing: 1.5px; + color: #ffffffb3; + font-size: 10px; + font-weight: 600; + letter-spacing: 2px; } } } From 125a4dc35598b9ac106bbda6122772e8728074c5 Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 15:58:09 +0000 Subject: [PATCH 12/13] =?UTF-8?q?fix(nodes/slint):=20address=20review=20fe?= =?UTF-8?q?edback=20=E2=80=94=20caching,=20blocking,=20platform=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Critical fixes: - Always call update_timers_and_animations() unconditionally in the Render handler so Slint Timer/animation state advances even when frames are served from cache. - Add static_ui config flag (default false) to opt into frame caching for truly static UIs; dynamic UIs always re-render every frame. - Replace blocking_send with try_send on the result channel to avoid head-of-line blocking on the shared Slint thread when one node's consumer is slow. Suggestions: - Propagate set_platform() error instead of silently discarding it. - Clear CURRENT_WINDOW thread-local after component.show() to prevent stale Rc references. - Replace spin_on (busy-wait) with pollster::block_on for .slint compilation; yields to the OS instead of burning CPU. - Document merge_update limitation in dynamic pipeline YAML comments. Nits: - Add #[serde(default)] at struct level on SlintConfig (matches ColorBarsConfig pattern). - Simplify registration to use SlintConfig::default(). - Change SAFETY comment to Invariant: (SAFETY is for unsafe blocks). Watermark pipeline updated with static_ui: true. Signed-off-by: StreamKit Devin --- Cargo.lock | 1 - crates/nodes/Cargo.toml | 3 +- crates/nodes/src/video/slint.rs | 141 ++++++++++-------- .../dynamic/video_moq_slint_scoreboard.yml | 6 + .../oneshot/video_slint_watermark.yml | 1 + 5 files changed, 90 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47e16e1d..180d4d91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7788,7 +7788,6 @@ dependencies = [ "slint", "slint-interpreter", "smallvec", - "spin_on", "streamkit-core", "symphonia", "tempfile", diff --git a/crates/nodes/Cargo.toml b/crates/nodes/Cargo.toml index afb19a4e..f23a17fd 100644 --- a/crates/nodes/Cargo.toml +++ b/crates/nodes/Cargo.toml @@ -94,7 +94,6 @@ bytemuck = { version = "1.22", optional = true, features = ["derive"] } # Slint UI rendering (optional, behind `slint` feature) slint = { version = "1.15", optional = true, default-features = false, features = ["renderer-software", "compat-1-2"] } slint-interpreter = { version = "1.15", optional = true } -spin_on = { version = "0.1", optional = true } futures-util = "0.3" @@ -156,7 +155,7 @@ dav1d_static = ["dav1d"] colorbars = ["dep:schemars", "dep:serde_json", "dep:fontdue"] compositor = ["dep:schemars", "dep:serde_json", "dep:image", "dep:tiny-skia", "dep:rayon", "dep:fontdue", "dep:smallvec", "dep:uuid"] gpu = ["compositor", "dep:wgpu", "dep:pollster", "dep:bytemuck"] -slint = ["dep:slint", "dep:slint-interpreter", "dep:spin_on", "dep:schemars", "dep:serde_json", "dep:uuid"] +slint = ["dep:slint", "dep:slint-interpreter", "dep:pollster", "dep:schemars", "dep:serde_json", "dep:uuid"] codegen = ["dep:ts-rs"] video = ["vp9", "av1", "colorbars", "compositor"] diff --git a/crates/nodes/src/video/slint.rs b/crates/nodes/src/video/slint.rs index c5d7c025..95e62fc7 100644 --- a/crates/nodes/src/video/slint.rs +++ b/crates/nodes/src/video/slint.rs @@ -68,6 +68,10 @@ const fn default_keyframe_interval() -> u32 { 90 } +const fn default_static_ui() -> bool { + false +} + // ── Configuration ─────────────────────────────────────────────────────────── /// Configuration for the standalone Slint UI video source node. @@ -76,6 +80,7 @@ const fn default_keyframe_interval() -> u32 { /// software renderer. Properties can be set at init and updated at runtime /// via `UpdateParams`. #[derive(Debug, Clone, Deserialize, JsonSchema)] +#[serde(default)] pub struct SlintConfig { /// Output frame width in pixels. #[serde(default = "default_width")] @@ -107,6 +112,13 @@ pub struct SlintConfig { /// Total frames to generate. 0 = infinite (real-time pacing). #[serde(default = "default_frame_count")] pub frame_count: u32, + /// When `true`, the rendered frame is cached and reused until properties + /// change (via `UpdateParams` or keyframe cycling). Suitable for overlays + /// with no Slint-internal `Timer` or `animate` directives. When `false` + /// (the default), every frame is re-rendered so that Slint timers and + /// animations advance correctly. + #[serde(default = "default_static_ui")] + pub static_ui: bool, } impl Default for SlintConfig { @@ -121,6 +133,7 @@ impl Default for SlintConfig { property_keyframes: Vec::new(), keyframe_interval: default_keyframe_interval(), frame_count: default_frame_count(), + static_ui: default_static_ui(), } } } @@ -181,9 +194,11 @@ fn validate_slint_asset_path(path: &str) -> Result<(), String> { // // Each node gets a unique `NodeId` (UUID) and communicates with the shared // thread via tagged work items. Results are sent back on a per-node -// `tokio::sync::mpsc` channel (using `blocking_send` on the Slint thread -// so the async `run()` method can `.recv().await` without blocking the -// tokio worker thread). +// `tokio::sync::mpsc` channel so the async `run()` method can +// `.recv().await` without blocking the tokio worker thread. +// Frame results use `try_send` to avoid head-of-line blocking: if one +// node's consumer is slow, frames are dropped instead of stalling the +// shared thread for all other nodes. /// Opaque identifier for a node's instance on the shared Slint thread. type NodeId = uuid::Uuid; @@ -295,45 +310,62 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { }, SlintWorkItem::Render { node_id } => { if let Some(state) = nodes.get_mut(&node_id) { - // Determine the current keyframe index (if keyframes are configured). - let kf_idx = if state.config.property_keyframes.is_empty() { - None - } else { - let interval = state.config.keyframe_interval.max(1); - Some( - (state.instance.frame_counter / interval) as usize - % state.config.property_keyframes.len(), - ) - }; - - // Re-render only when properties have actually changed: - // config update (dirty flag) or keyframe boundary. - let need_render = state.dirty - || state.cached_keyframe_idx != kf_idx - || state.cached_frame.is_none(); - - let rgba_data = if need_render { - let data = render_slint_frame(&mut state.instance, &state.config); - state.cached_frame = Some(data.clone()); - state.cached_keyframe_idx = kf_idx; - state.dirty = false; - data + // Always pump Slint timers/animations (process-global) so + // that Timer callbacks and CSS-like transitions advance + // even when the frame is served from cache. + slint::platform::update_timers_and_animations(); + + let rgba_data = if state.config.static_ui { + // ── Static UI path: cache the rendered frame ──────── + let kf_idx = if state.config.property_keyframes.is_empty() { + None + } else { + let interval = state.config.keyframe_interval.max(1); + Some( + (state.instance.frame_counter / interval) as usize + % state.config.property_keyframes.len(), + ) + }; + + let need_render = state.dirty + || state.cached_keyframe_idx != kf_idx + || state.cached_frame.is_none(); + + if need_render { + let data = + render_slint_frame(&mut state.instance, &state.config); + state.cached_frame = Some(data.clone()); + state.cached_keyframe_idx = kf_idx; + state.dirty = false; + data + } else { + // Advance frame counter so keyframe boundaries + // are detected at the right time. + state.instance.frame_counter = + state.instance.frame_counter.wrapping_add(1); + // Invariant: need_render is false only when + // cached_frame is Some. + state.cached_frame.clone().unwrap_or_default() + } } else { - // Advance frame counter even when reusing the cache so - // keyframe boundaries are detected at the right time. - state.instance.frame_counter = state.instance.frame_counter.wrapping_add(1); - // SAFETY: need_render is false only when cached_frame is Some. - state.cached_frame.clone().unwrap_or_default() + // ── Dynamic UI path: always re-render ─────────────── + render_slint_frame(&mut state.instance, &state.config) }; - // If the result channel is closed the node has been dropped; - // clean up its state on the next Unregister (or here eagerly). - if state - .result_tx - .blocking_send(SlintThreadResult::Frame { rgba_data }) - .is_err() - { - nodes.remove(&node_id); + // Use try_send to avoid head-of-line blocking: if this + // node's consumer is slow, drop the frame rather than + // stalling the shared thread for all other nodes. + match state.result_tx.try_send(SlintThreadResult::Frame { rgba_data }) { + Ok(()) => {}, + Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => { + tracing::debug!( + "SlintNode '{}' result channel full, dropping frame", + node_id + ); + }, + Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => { + nodes.remove(&node_id); + }, } } }, @@ -391,7 +423,7 @@ fn create_slint_instance( // Compile the .slint file. let compiler = slint_interpreter::Compiler::default(); - let result = spin_on::spin_on(compiler.build_from_path(&config.slint_file)); + let result = pollster::block_on(compiler.build_from_path(&config.slint_file)); // Check for compilation errors. let diags: Vec<_> = result @@ -435,7 +467,9 @@ fn create_slint_instance( // Set the Slint platform backend exactly once per process. // All instances share this thread, so the first call suffices. if !*platform_set { - let _ = slint::platform::set_platform(Box::new(SlintBackend)); + slint::platform::set_platform(Box::new(SlintBackend)).map_err(|e| { + StreamKitError::Runtime(format!("Failed to set Slint platform: {e}")) + })?; *platform_set = true; } @@ -461,12 +495,17 @@ fn create_slint_instance( StreamKitError::Configuration(format!("Failed to show Slint component: {e}")) })?; + // Clear the thread-local so a stale reference isn't returned by an + // unexpected `create_window_adapter()` call during rendering. + CURRENT_WINDOW.with(|cell| *cell.borrow_mut() = None); + Ok(SlintInstance { window, component, definition, buffer, width, frame_counter: 0 }) } /// Render a single frame from the Slint instance, returning raw RGBA8 data. /// -/// Applies property keyframe cycling and pumps Slint animation timers. +/// Applies property keyframe cycling. Timer/animation pumping is handled +/// by the caller (`slint_thread_main`) so it runs unconditionally. fn render_slint_frame(instance: &mut SlintInstance, config: &SlintConfig) -> Vec { // Build the effective property map: base properties merged with the // current keyframe (if keyframes are configured). @@ -484,10 +523,6 @@ fn render_slint_frame(instance: &mut SlintInstance, config: &SlintConfig) -> Vec // Push property updates into the component instance. set_properties(&instance.component, &effective_props); - // Pump Slint's internal animation timers so time-based animations - // (e.g. slide-in transitions) advance on each tick. - slint::platform::update_timers_and_animations(); - // Force a full redraw every frame. With `RepaintBufferType::NewBuffer` // the renderer always paints the entire scene, so there is no wasted // incremental-diff cost. Without this call, `draw_if_needed` would @@ -831,19 +866,7 @@ impl ProcessorNode for SlintNode { #[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn register_slint_nodes(registry: &mut NodeRegistry) { - let default_node = SlintNode { - config: SlintConfig { - width: default_width(), - height: default_height(), - fps: default_fps(), - slint_file: String::new(), - component: None, - properties: HashMap::new(), - property_keyframes: Vec::new(), - keyframe_interval: default_keyframe_interval(), - frame_count: default_frame_count(), - }, - }; + let default_node = SlintNode { config: SlintConfig::default() }; registry.register_static_with_description( "video::slint", diff --git a/samples/pipelines/dynamic/video_moq_slint_scoreboard.yml b/samples/pipelines/dynamic/video_moq_slint_scoreboard.yml index 97589c76..967534aa 100644 --- a/samples/pipelines/dynamic/video_moq_slint_scoreboard.yml +++ b/samples/pipelines/dynamic/video_moq_slint_scoreboard.yml @@ -21,6 +21,12 @@ # "period": "2ND" # } # }' +# +# NOTE: Only `properties` are mergeable at runtime via UpdateParams. +# Init-time fields (slint_file, width, height, fps, frame_count, +# keyframe_interval, property_keyframes, static_ui) are ignored in +# UpdateParams because serde defaults make it impossible to distinguish +# "user sent empty" from "field was absent". name: Video Slint Scoreboard + Lower Third (MoQ) description: Composites colorbars with Slint scoreboard and lower-third overlays, streams via MoQ with runtime property updates diff --git a/samples/pipelines/oneshot/video_slint_watermark.yml b/samples/pipelines/oneshot/video_slint_watermark.yml index 3866343a..5ad772c8 100644 --- a/samples/pipelines/oneshot/video_slint_watermark.yml +++ b/samples/pipelines/oneshot/video_slint_watermark.yml @@ -43,6 +43,7 @@ nodes: fps: 30 frame_count: 300 slint_file: samples/slint/watermark.slint + static_ui: true properties: channel: "StreamKit" tagline: "LIVE" From f17ce21bdeb4a927330ba1aa1373316a0199755d Mon Sep 17 00:00:00 2001 From: StreamKit Devin Date: Thu, 2 Apr 2026 15:58:24 +0000 Subject: [PATCH 13/13] style(nodes/slint): fix formatting from pre-commit hook Signed-off-by: StreamKit Devin Co-Authored-By: Claudio Costa --- crates/nodes/src/video/slint.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/nodes/src/video/slint.rs b/crates/nodes/src/video/slint.rs index 95e62fc7..732f9c23 100644 --- a/crates/nodes/src/video/slint.rs +++ b/crates/nodes/src/video/slint.rs @@ -332,8 +332,7 @@ fn slint_thread_main(work_rx: std::sync::mpsc::Receiver) { || state.cached_frame.is_none(); if need_render { - let data = - render_slint_frame(&mut state.instance, &state.config); + let data = render_slint_frame(&mut state.instance, &state.config); state.cached_frame = Some(data.clone()); state.cached_keyframe_idx = kf_idx; state.dirty = false; @@ -467,9 +466,8 @@ fn create_slint_instance( // Set the Slint platform backend exactly once per process. // All instances share this thread, so the first call suffices. if !*platform_set { - slint::platform::set_platform(Box::new(SlintBackend)).map_err(|e| { - StreamKitError::Runtime(format!("Failed to set Slint platform: {e}")) - })?; + slint::platform::set_platform(Box::new(SlintBackend)) + .map_err(|e| StreamKitError::Runtime(format!("Failed to set Slint platform: {e}")))?; *platform_set = true; }