From e9784e3db6f72843b2e993a0aaccb0cf22cbbf91 Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Tue, 7 Jul 2026 16:31:40 -0400 Subject: [PATCH 01/46] feat(linux): integrate GTK4 WebKitGTK6 stack --- .github/workflows/bench.yml | 4 +- .github/workflows/check-generated-files.yml | 2 +- .../workflows/covector-version-or-publish.yml | 4 +- .github/workflows/docker.yml | 4 +- .github/workflows/lint-rust.yml | 3 +- .github/workflows/publish-cli-js.yml | 2 +- .github/workflows/publish-cli-rs.yml | 2 +- .github/workflows/test-android.yml | 2 +- .github/workflows/test-cli-js.yml | 2 +- .github/workflows/test-cli-rs.yml | 3 +- .github/workflows/test-core.yml | 3 +- .github/workflows/udeps.yml | 5 +- Cargo.lock | 3887 +++++------ Cargo.toml | 5 + .../linux/appimage/linuxdeploy-plugin-gtk.sh | 3 +- .../src/bundle/linux/appimage/linuxdeploy.rs | 4 +- crates/tauri-cli/src/info/env_system.rs | 10 +- crates/tauri-cli/src/interface/rust.rs | 172 +- .../tauri-cli/src/interface/rust/manifest.rs | 54 +- crates/tauri-runtime-wry/Cargo.toml | 4 +- crates/tauri-runtime-wry/src/lib.rs | 16 +- crates/tauri-runtime-wry/src/monitor/linux.rs | 4 +- .../src/undecorated_resizing.rs | 160 +- crates/tauri-runtime-wry/src/webview.rs | 2 +- crates/tauri-runtime/Cargo.toml | 4 +- crates/tauri-runtime/src/webview.rs | 4 +- crates/tauri-runtime/src/window.rs | 4 +- crates/tauri/Cargo.toml | 8 +- crates/tauri/src/app.rs | 2 +- crates/tauri/src/ipc/channel.rs | 2 +- crates/tauri/src/lib.rs | 12 +- crates/tauri/src/plugin.rs | 2 +- crates/tauri/src/test/mock_runtime.rs | 2 +- crates/tauri/src/webview/mod.rs | 14 +- crates/tauri/src/webview/webview_window.rs | 12 +- crates/tauri/src/window/mod.rs | 2 +- ports/muda/.changes/config.json | 52 + ports/muda/.changes/gtk4.md | 5 + ports/muda/.changes/readme.md | 29 + ports/muda/.github/workflows/audit.yml | 33 + ports/muda/.github/workflows/clippy-fmt.yml | 48 + .../.github/workflows/covector-status.yml | 20 + .../workflows/covector-version-or-publish.yml | 59 + ports/muda/.github/workflows/test.yml | 49 + ports/muda/.gitignore | 6 + ports/muda/CHANGELOG.md | 348 + ports/muda/Cargo.lock | 3928 ++++++++++++ ports/muda/Cargo.toml | 88 + ports/muda/LICENSE-APACHE | 201 + ports/muda/LICENSE-MIT | 21 + ports/muda/LICENSE.spdx | 19 + ports/muda/README.md | 142 + ports/muda/examples/gtk.rs | 97 + ports/muda/examples/icon.png | Bin 0 -> 1481 bytes ports/muda/examples/tao.rs | 282 + .../windows-common-controls-v6/.gitignore | 2 + .../windows-common-controls-v6/Cargo.toml | 18 + .../app.exe.manifest | 15 + .../windows-common-controls-v6/build.rs | 4 + .../windows-common-controls-v6/manifest.rc | 2 + .../windows-common-controls-v6/src/main.rs | 242 + ports/muda/examples/winit.rs | 299 + ports/muda/examples/wry.rs | 391 ++ ports/muda/renovate.json | 4 + ports/muda/rustfmt.toml | 12 + ports/muda/src/about_metadata.rs | 258 + ports/muda/src/accelerator.rs | 871 +++ ports/muda/src/builders/check.rs | 94 + ports/muda/src/builders/icon.rs | 116 + ports/muda/src/builders/mod.rs | 16 + ports/muda/src/builders/normal.rs | 87 + ports/muda/src/builders/submenu.rs | 94 + ports/muda/src/error.rs | 52 + ports/muda/src/icon.rs | 313 + ports/muda/src/items/check.rs | 150 + ports/muda/src/items/compat.rs | 63 + ports/muda/src/items/icon.rs | 210 + ports/muda/src/items/mod.rs | 90 + ports/muda/src/items/normal.rs | 126 + ports/muda/src/items/predefined.rs | 343 + ports/muda/src/items/submenu.rs | 328 + ports/muda/src/lib.rs | 551 ++ ports/muda/src/menu.rs | 521 ++ ports/muda/src/menu_id.rs | 85 + .../src/platform_impl/gtk/about_dialog.rs | 103 + .../muda/src/platform_impl/gtk/accelerator.rs | 58 + ports/muda/src/platform_impl/gtk/icon.rs | 53 + ports/muda/src/platform_impl/gtk/mnemonic.rs | 72 + ports/muda/src/platform_impl/gtk/mod.rs | 1473 +++++ .../src/platform_impl/macos/accelerator.rs | 76 + ports/muda/src/platform_impl/macos/icon.rs | 64 + ports/muda/src/platform_impl/macos/mod.rs | 1283 ++++ ports/muda/src/platform_impl/macos/util.rs | 16 + ports/muda/src/platform_impl/mod.rs | 119 + .../src/platform_impl/windows/accelerator.rs | 221 + .../platform_impl/windows/dark_menu_bar.rs | 346 + ports/muda/src/platform_impl/windows/icon.rs | 201 + ports/muda/src/platform_impl/windows/mod.rs | 1399 ++++ ports/muda/src/platform_impl/windows/util.rs | 169 + ports/muda/src/util.rs | 29 + ports/tray-icon/.changes/config.json | 52 + ports/tray-icon/.changes/nis-hidden.md | 5 + .../.changes/perf-macos-avoid-allocating.md | 5 + ports/tray-icon/.changes/readme.md | 29 + ports/tray-icon/.changes/set-cb-size.md | 5 + ports/tray-icon/.github/workflows/audit.yml | 33 + .../.github/workflows/clippy-fmt.yml | 48 + .../.github/workflows/covector-status.yml | 20 + .../workflows/covector-version-or-publish.yml | 58 + ports/tray-icon/.github/workflows/test.yml | 42 + ports/tray-icon/.gitignore | 6 + ports/tray-icon/CHANGELOG.md | 340 + ports/tray-icon/Cargo.lock | 5674 +++++++++++++++++ ports/tray-icon/Cargo.toml | 102 + ports/tray-icon/LICENSE-APACHE | 201 + ports/tray-icon/LICENSE-MIT | 21 + ports/tray-icon/LICENSE.spdx | 19 + ports/tray-icon/README.md | 132 + ports/tray-icon/examples/egui.rs | 128 + ports/tray-icon/examples/icon.png | Bin 0 -> 1481 bytes ports/tray-icon/examples/tao.rs | 116 + ports/tray-icon/examples/winit.rs | 153 + ports/tray-icon/renovate.json | 10 + ports/tray-icon/rustfmt.toml | 12 + ports/tray-icon/src/counter.rs | 17 + ports/tray-icon/src/error.rs | 30 + ports/tray-icon/src/icon.rs | 187 + ports/tray-icon/src/lib.rs | 742 +++ ports/tray-icon/src/platform_impl/gtk/icon.rs | 38 + ports/tray-icon/src/platform_impl/gtk/mod.rs | 159 + .../tray-icon/src/platform_impl/linux/icon.rs | 62 + .../tray-icon/src/platform_impl/linux/menu.rs | 53 + .../tray-icon/src/platform_impl/linux/mod.rs | 124 + .../tray-icon/src/platform_impl/linux/tray.rs | 112 + .../tray-icon/src/platform_impl/macos/icon.rs | 35 + .../tray-icon/src/platform_impl/macos/mod.rs | 612 ++ ports/tray-icon/src/platform_impl/mod.rs | 26 + .../src/platform_impl/windows/icon.rs | 158 + .../src/platform_impl/windows/mod.rs | 658 ++ .../src/platform_impl/windows/util.rs | 55 + ports/tray-icon/src/tray_icon_id.rs | 92 + 141 files changed, 29151 insertions(+), 2111 deletions(-) create mode 100644 ports/muda/.changes/config.json create mode 100644 ports/muda/.changes/gtk4.md create mode 100644 ports/muda/.changes/readme.md create mode 100644 ports/muda/.github/workflows/audit.yml create mode 100644 ports/muda/.github/workflows/clippy-fmt.yml create mode 100644 ports/muda/.github/workflows/covector-status.yml create mode 100644 ports/muda/.github/workflows/covector-version-or-publish.yml create mode 100644 ports/muda/.github/workflows/test.yml create mode 100644 ports/muda/.gitignore create mode 100644 ports/muda/CHANGELOG.md create mode 100644 ports/muda/Cargo.lock create mode 100644 ports/muda/Cargo.toml create mode 100644 ports/muda/LICENSE-APACHE create mode 100644 ports/muda/LICENSE-MIT create mode 100644 ports/muda/LICENSE.spdx create mode 100644 ports/muda/README.md create mode 100644 ports/muda/examples/gtk.rs create mode 100644 ports/muda/examples/icon.png create mode 100644 ports/muda/examples/tao.rs create mode 100644 ports/muda/examples/windows-common-controls-v6/.gitignore create mode 100644 ports/muda/examples/windows-common-controls-v6/Cargo.toml create mode 100644 ports/muda/examples/windows-common-controls-v6/app.exe.manifest create mode 100644 ports/muda/examples/windows-common-controls-v6/build.rs create mode 100644 ports/muda/examples/windows-common-controls-v6/manifest.rc create mode 100644 ports/muda/examples/windows-common-controls-v6/src/main.rs create mode 100644 ports/muda/examples/winit.rs create mode 100644 ports/muda/examples/wry.rs create mode 100644 ports/muda/renovate.json create mode 100644 ports/muda/rustfmt.toml create mode 100644 ports/muda/src/about_metadata.rs create mode 100644 ports/muda/src/accelerator.rs create mode 100644 ports/muda/src/builders/check.rs create mode 100644 ports/muda/src/builders/icon.rs create mode 100644 ports/muda/src/builders/mod.rs create mode 100644 ports/muda/src/builders/normal.rs create mode 100644 ports/muda/src/builders/submenu.rs create mode 100644 ports/muda/src/error.rs create mode 100644 ports/muda/src/icon.rs create mode 100644 ports/muda/src/items/check.rs create mode 100644 ports/muda/src/items/compat.rs create mode 100644 ports/muda/src/items/icon.rs create mode 100644 ports/muda/src/items/mod.rs create mode 100644 ports/muda/src/items/normal.rs create mode 100644 ports/muda/src/items/predefined.rs create mode 100644 ports/muda/src/items/submenu.rs create mode 100644 ports/muda/src/lib.rs create mode 100644 ports/muda/src/menu.rs create mode 100644 ports/muda/src/menu_id.rs create mode 100644 ports/muda/src/platform_impl/gtk/about_dialog.rs create mode 100644 ports/muda/src/platform_impl/gtk/accelerator.rs create mode 100644 ports/muda/src/platform_impl/gtk/icon.rs create mode 100644 ports/muda/src/platform_impl/gtk/mnemonic.rs create mode 100644 ports/muda/src/platform_impl/gtk/mod.rs create mode 100644 ports/muda/src/platform_impl/macos/accelerator.rs create mode 100644 ports/muda/src/platform_impl/macos/icon.rs create mode 100644 ports/muda/src/platform_impl/macos/mod.rs create mode 100644 ports/muda/src/platform_impl/macos/util.rs create mode 100644 ports/muda/src/platform_impl/mod.rs create mode 100644 ports/muda/src/platform_impl/windows/accelerator.rs create mode 100644 ports/muda/src/platform_impl/windows/dark_menu_bar.rs create mode 100644 ports/muda/src/platform_impl/windows/icon.rs create mode 100644 ports/muda/src/platform_impl/windows/mod.rs create mode 100644 ports/muda/src/platform_impl/windows/util.rs create mode 100644 ports/muda/src/util.rs create mode 100644 ports/tray-icon/.changes/config.json create mode 100644 ports/tray-icon/.changes/nis-hidden.md create mode 100644 ports/tray-icon/.changes/perf-macos-avoid-allocating.md create mode 100644 ports/tray-icon/.changes/readme.md create mode 100644 ports/tray-icon/.changes/set-cb-size.md create mode 100644 ports/tray-icon/.github/workflows/audit.yml create mode 100644 ports/tray-icon/.github/workflows/clippy-fmt.yml create mode 100644 ports/tray-icon/.github/workflows/covector-status.yml create mode 100644 ports/tray-icon/.github/workflows/covector-version-or-publish.yml create mode 100644 ports/tray-icon/.github/workflows/test.yml create mode 100644 ports/tray-icon/.gitignore create mode 100644 ports/tray-icon/CHANGELOG.md create mode 100644 ports/tray-icon/Cargo.lock create mode 100644 ports/tray-icon/Cargo.toml create mode 100644 ports/tray-icon/LICENSE-APACHE create mode 100644 ports/tray-icon/LICENSE-MIT create mode 100644 ports/tray-icon/LICENSE.spdx create mode 100644 ports/tray-icon/README.md create mode 100644 ports/tray-icon/examples/egui.rs create mode 100644 ports/tray-icon/examples/icon.png create mode 100644 ports/tray-icon/examples/tao.rs create mode 100644 ports/tray-icon/examples/winit.rs create mode 100644 ports/tray-icon/renovate.json create mode 100644 ports/tray-icon/rustfmt.toml create mode 100644 ports/tray-icon/src/counter.rs create mode 100644 ports/tray-icon/src/error.rs create mode 100644 ports/tray-icon/src/icon.rs create mode 100644 ports/tray-icon/src/lib.rs create mode 100644 ports/tray-icon/src/platform_impl/gtk/icon.rs create mode 100644 ports/tray-icon/src/platform_impl/gtk/mod.rs create mode 100644 ports/tray-icon/src/platform_impl/linux/icon.rs create mode 100644 ports/tray-icon/src/platform_impl/linux/menu.rs create mode 100644 ports/tray-icon/src/platform_impl/linux/mod.rs create mode 100644 ports/tray-icon/src/platform_impl/linux/tray.rs create mode 100644 ports/tray-icon/src/platform_impl/macos/icon.rs create mode 100644 ports/tray-icon/src/platform_impl/macos/mod.rs create mode 100644 ports/tray-icon/src/platform_impl/mod.rs create mode 100644 ports/tray-icon/src/platform_impl/windows/icon.rs create mode 100644 ports/tray-icon/src/platform_impl/windows/mod.rs create mode 100644 ports/tray-icon/src/platform_impl/windows/util.rs create mode 100644 ports/tray-icon/src/tray_icon_id.rs diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 62fc97221fb9..8a151c64a1e8 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -50,12 +50,12 @@ jobs: components: rust-src targets: ${{ matrix.platform.target }} - - name: install webkit2gtk and xvfb (ubuntu only) + - name: install WebKitGTK and xvfb (ubuntu only) if: contains(matrix.platform.target, 'gnu') run: | sudo apt-get update sudo apt-get install -y --no-install-recommends \ - webkit2gtk-4.1 libayatana-appindicator3-dev \ + libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev \ xvfb \ at-spi2-core diff --git a/.github/workflows/check-generated-files.yml b/.github/workflows/check-generated-files.yml index fb1e59866d2f..8be89c93f959 100644 --- a/.github/workflows/check-generated-files.yml +++ b/.github/workflows/check-generated-files.yml @@ -73,7 +73,7 @@ jobs: - name: install Linux dependencies run: | sudo apt-get update - sudo apt-get install -y libgtk-3-dev + sudo apt-get install -y libgtk-4-dev - uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/covector-version-or-publish.yml b/.github/workflows/covector-version-or-publish.yml index 170bc3ef31b0..ca100e0f6e01 100644 --- a/.github/workflows/covector-version-or-publish.yml +++ b/.github/workflows/covector-version-or-publish.yml @@ -36,7 +36,7 @@ jobs: if: matrix.platform == 'ubuntu-latest' run: | sudo apt-get update - sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev libfuse2 librsvg2-dev + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev libfuse2 librsvg2-dev - uses: Swatinem/rust-cache@v2 @@ -88,7 +88,7 @@ jobs: - name: install Linux dependencies run: | sudo apt-get update - sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev librsvg2-dev + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev librsvg2-dev - name: covector version or publish (publish when no change files present) uses: jbolda/covector/packages/action@covector-v0 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ca9b2623640f..d0e2db6fcab1 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -25,7 +25,7 @@ jobs: - name: install Linux dependencies run: | sudo apt-get update - sudo apt-get install -y libgtk-3-dev + sudo apt-get install -y libgtk-4-dev - name: install cross run: cargo install cross --git https://github.com/cross-rs/cross @@ -108,7 +108,7 @@ jobs: - name: install dependencies run: | sudo apt-get update - sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev - name: Test run: | diff --git a/.github/workflows/lint-rust.yml b/.github/workflows/lint-rust.yml index a538d66cd9be..54c50ec9287e 100644 --- a/.github/workflows/lint-rust.yml +++ b/.github/workflows/lint-rust.yml @@ -12,6 +12,7 @@ on: paths: - '.github/workflows/lint-rust.yml' - 'crates/**' + - 'ports/**' - 'Cargo.toml' - 'Cargo.lock' @@ -39,7 +40,7 @@ jobs: run: | sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update - sudo apt-get install -y libgtk-3-dev webkit2gtk-4.1 libayatana-appindicator3-dev + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev - uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/publish-cli-js.yml b/.github/workflows/publish-cli-js.yml index d5960789d2a2..d4299309a1de 100644 --- a/.github/workflows/publish-cli-js.yml +++ b/.github/workflows/publish-cli-js.yml @@ -209,7 +209,7 @@ jobs: if: ${{ endsWith(matrix.target, 'gnu') }} run: | sudo apt-get update - sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev librsvg2-dev + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev librsvg2-dev - name: Setup and run tests (gnu) if: ${{ endsWith(matrix.target, 'gnu') }} diff --git a/.github/workflows/publish-cli-rs.yml b/.github/workflows/publish-cli-rs.yml index e40a2ddd42d4..582c6902ae0f 100644 --- a/.github/workflows/publish-cli-rs.yml +++ b/.github/workflows/publish-cli-rs.yml @@ -62,7 +62,7 @@ jobs: if: ${{ !matrix.config.cross && startsWith(matrix.config.os, 'ubuntu') }} run: | sudo apt-get update - sudo apt-get install -y libgtk-3-dev + sudo apt-get install -y libgtk-4-dev - name: Install cross if: ${{ matrix.config.cross }} diff --git a/.github/workflows/test-android.yml b/.github/workflows/test-android.yml index 5790e5dafcf9..b81632f4dc8b 100644 --- a/.github/workflows/test-android.yml +++ b/.github/workflows/test-android.yml @@ -40,7 +40,7 @@ jobs: if: matrix.platform == 'ubuntu-latest' run: | sudo apt-get update - sudo apt-get install -y libgtk-3-dev webkit2gtk-4.1 + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev - run: npm i -g --force corepack - name: setup node diff --git a/.github/workflows/test-cli-js.yml b/.github/workflows/test-cli-js.yml index 212a915551f2..5630d4481990 100644 --- a/.github/workflows/test-cli-js.yml +++ b/.github/workflows/test-cli-js.yml @@ -49,7 +49,7 @@ jobs: if: matrix.platform == 'ubuntu-latest' run: | sudo apt-get update - sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev librsvg2-dev + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev librsvg2-dev - uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/test-cli-rs.yml b/.github/workflows/test-cli-rs.yml index 532eb568f6dd..6fecb3ef1020 100644 --- a/.github/workflows/test-cli-rs.yml +++ b/.github/workflows/test-cli-rs.yml @@ -14,6 +14,7 @@ on: - 'crates/tauri-utils/**' - 'crates/tauri-bundler/**' - 'crates/tauri-cli/**' + - 'ports/**' - 'Cargo.toml' - 'Cargo.lock' @@ -55,7 +56,7 @@ jobs: run: | sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update - sudo apt-get install -y libgtk-3-dev webkit2gtk-4.1 libayatana-appindicator3-dev librsvg2-dev + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev librsvg2-dev - uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/test-core.yml b/.github/workflows/test-core.yml index 8550f7695a58..77e98195b767 100644 --- a/.github/workflows/test-core.yml +++ b/.github/workflows/test-core.yml @@ -12,6 +12,7 @@ on: paths: - '.github/workflows/test-core.yml' - 'crates/**' + - 'ports/**' - 'Cargo.toml' - 'Cargo.lock' - '!crates/tauri/scripts/**' @@ -89,7 +90,7 @@ jobs: run: | sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update - sudo apt-get install -y webkit2gtk-4.1 libxdo-dev libayatana-appindicator3-dev + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev libxdo-dev - uses: Swatinem/rust-cache@v2 with: diff --git a/.github/workflows/udeps.yml b/.github/workflows/udeps.yml index 155f09eb4333..e20c743228e7 100644 --- a/.github/workflows/udeps.yml +++ b/.github/workflows/udeps.yml @@ -49,6 +49,7 @@ jobs: - 'crates/tauri-runtime/**' wry: - 'crates/tauri-runtime-wry/**' + - 'ports/**' utils: - 'crates/tauri-utils/**' bundler: @@ -133,7 +134,7 @@ jobs: - name: install dependencies run: | sudo apt-get update - sudo apt-get install -y libgtk-3-dev + sudo apt-get install -y libgtk-4-dev - uses: Swatinem/rust-cache@v2 @@ -148,7 +149,7 @@ jobs: - name: Install required packages run: | sudo apt-get update - sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev - name: Run udeps run: cargo udeps --manifest-path ${{ matrix.path }}/Cargo.toml --all-targets --all-features diff --git a/Cargo.lock b/Cargo.lock index 8f2823918ae4..1b37afd49811 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,20 +17,11 @@ dependencies = [ "tauri-utils", ] -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aead" @@ -38,7 +29,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "crypto-common 0.1.6", + "crypto-common 0.1.7", "generic-array", ] @@ -50,7 +41,7 @@ checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", - "cpufeatures 0.2.16", + "cpufeatures 0.2.17", ] [[package]] @@ -82,19 +73,19 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.17", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom 0.3.4", "once_cell", "serde", "version_check", @@ -103,9 +94,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -119,12 +110,6 @@ dependencies = [ "as-slice", ] -[[package]] -name = "aligned-vec" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" - [[package]] name = "aligned-vec" version = "0.6.4" @@ -142,9 +127,9 @@ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" [[package]] name = "alloc-stdlib" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" dependencies = [ "alloc-no-stdlib", ] @@ -155,12 +140,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_log-sys" version = "0.3.2" @@ -169,12 +148,12 @@ checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" [[package]] name = "android_logger" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f39be698127218cca460cb624878c9aa4e2b47dba3b277963d2bf00bad263b" +checksum = "dbb4e440d04be07da1f1bf44fb4495ebd58669372fe0cffa6e48595ac5bd88a3" dependencies = [ "android_log-sys", - "env_filter", + "env_filter 0.1.4", "log", ] @@ -187,11 +166,20 @@ dependencies = [ "libc", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "anstream" -version = "0.6.18" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -204,36 +192,37 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", - "windows-sys 0.59.0", + "once_cell_polyfill", + "windows-sys 0.61.2", ] [[package]] @@ -282,15 +271,15 @@ dependencies = [ "bitflags 2.13.0", "bytes", "chrono", - "clap", + "clap 4.6.1", "cryptographic-message-syntax", - "der", + "der 0.7.10", "dialoguer 0.11.0", "difference", "digest 0.10.7", "dirs 5.0.1", "elliptic-curve", - "env_logger 0.11.6", + "env_logger", "figment", "filetime", "glob", @@ -323,14 +312,14 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "sha2 0.10.8", + "sha2 0.10.9", "signature", "simple-file-manifest", "spake2", "spki", "subtle", "tempfile", - "thiserror 2.0.12", + "thiserror 2.0.18", "tokio", "tungstenite 0.24.0", "uuid", @@ -358,7 +347,7 @@ dependencies = [ "scroll", "serde", "serde-xml-rs", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -382,9 +371,9 @@ dependencies = [ "serde", "serde-xml-rs", "sha1 0.10.6", - "sha2 0.10.8", + "sha2 0.10.9", "signature", - "thiserror 2.0.12", + "thiserror 2.0.18", "url", "x509-certificate", "xml-rs", @@ -399,13 +388,22 @@ checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69" [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arc-swap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" +dependencies = [ + "rustversion", +] + [[package]] name = "arg_enum_proc_macro" version = "0.3.4" @@ -414,7 +412,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -425,7 +423,7 @@ checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" dependencies = [ "base64ct", "blake2", - "cpufeatures 0.2.16", + "cpufeatures 0.2.17", "password-hash", "zeroize", ] @@ -438,9 +436,9 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "as-slice" @@ -474,7 +472,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "synstructure", ] @@ -486,48 +484,37 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] -name = "async-trait" -version = "0.1.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "atk" -version = "0.18.2" +name = "async-channel" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ - "atk-sys", - "glib", - "libc", + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", ] [[package]] -name = "atk-sys" -version = "0.18.2" +name = "async-trait" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] name = "atomic" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" dependencies = [ "bytemuck", ] @@ -538,11 +525,22 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "av-scenechange" @@ -559,21 +557,21 @@ dependencies = [ "num-traits", "pastey", "rayon", - "thiserror 2.0.12", + "thiserror 2.0.18", "v_frame", "y4m", ] [[package]] name = "av1-grain" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" dependencies = [ "anyhow", "arrayvec", "log", - "nom 7.1.3", + "nom 8.0.0", "num-rational", "v_frame", ] @@ -589,9 +587,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.4" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ "axum-core", "base64 0.22.1", @@ -609,8 +607,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -626,9 +623,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", @@ -637,28 +634,12 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", "tracing", ] -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object 0.36.7", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base16ct" version = "0.2.0" @@ -685,15 +666,15 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bcder" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627747a6774aab38beb35990d88309481378558875a41da1a4b2e373c906ef0" +checksum = "b593e5aeaf7992d388c08a9831c921cd703718064b3e50ba8e6d666d6cf86ca7" dependencies = [ "bytes", "smallvec", @@ -746,9 +727,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bit_field" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" [[package]] name = "bitfield" @@ -794,9 +775,9 @@ dependencies = [ [[package]] name = "bitvec" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" dependencies = [ "funty", "radium", @@ -850,22 +831,13 @@ 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 0.6.4", + "objc2", ] [[package]] @@ -886,32 +858,33 @@ checksum = "dc0b364ead1874514c8c2855ab558056ebfeb775653e7ae45ff72f28f8f3166c" [[package]] name = "borsh" -version = "1.5.7" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +checksum = "2f3f6da4992df95bbcd9af42a6c7dcb994498fc9048230405f3b36ff7cd3f145" dependencies = [ "borsh-derive", + "bytes", "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "1.5.7" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +checksum = "3ae8fb4fb5740e4b2c4884ff95f5f32f5e8479db1e8fd8eb49ddbe09eb09bb7c" dependencies = [ "once_cell", - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "brotli" -version = "8.0.0" +version = "8.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf19e729cdbd51af9a397fb9ef8ac8378007b797f8273cfbfdf45dcaa316167b" +checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -920,29 +893,38 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.0" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bstr" -version = "1.11.3" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" dependencies = [ "memchr", - "serde", + "serde_core", ] [[package]] name = "buffer-redux" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e8acf87c5b9f5897cd3ebb9a327f420e0cae9dd4e5c1d2e36f2c84c571a58f1" +checksum = "431a9cc8d7efa49bc326729264537f5e60affce816c66edf434350778c9f4f54" dependencies = [ "memchr", ] @@ -955,17 +937,18 @@ checksum = "5c0e531d93d39c34eef561e929e8a7f86d77a5af08aac4f6d6e39976c51858e9" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "byte-unit" -version = "5.1.6" +version = "5.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cd29c3c585209b0cbc7309bfe3ed7efd8c84c21b7af29c8bfae908f8777174" +checksum = "4a813de7f2bbedb7dce265b64f1cf5908ebe4d56281ece8d847e98113788b9b0" dependencies = [ "rust_decimal", + "schemars 1.2.1", "serde", "utf8-width", ] @@ -994,9 +977,9 @@ dependencies = [ [[package]] name = "bytecount" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "bytemuck" @@ -1018,18 +1001,18 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" dependencies = [ "serde", ] [[package]] name = "bytesize" -version = "1.3.0" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" +checksum = "2e93abca9e28e0a1b9877922aacb20576e05d4679ffa78c3d6dc22a26a216659" [[package]] name = "bzip2" @@ -1043,34 +1026,31 @@ dependencies = [ [[package]] name = "bzip2-sys" -version = "0.1.11+1.0.8" +version = "0.1.13+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" dependencies = [ "cc", - "libc", "pkg-config", ] [[package]] name = "cairo-rs" -version = "0.18.5" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +checksum = "5cc8d9aa793480744cd9a0524fef1a2e197d9eaa0f739cde19d16aba530dcb95" dependencies = [ "bitflags 2.13.0", "cairo-sys-rs", "glib", "libc", - "once_cell", - "thiserror 1.0.69", ] [[package]] name = "cairo-sys-rs" -version = "0.18.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +checksum = "f8b4985713047f5faee02b8db6a6ef32bbb50269ff53c1aee716d1d195b76d54" dependencies = [ "glib-sys", "libc", @@ -1089,11 +1069,11 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.9" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -1103,7 +1083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caa0060b6b7e1c0f14312c8ccebf28f5713b3045ffaae033a180622122a361dc" dependencies = [ "colored 2.2.0", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "deunicode", "duct", "dunce", @@ -1111,7 +1091,7 @@ dependencies = [ "english-numbers", "freedesktop_entry_parser", "handlebars", - "heck 0.5.0", + "heck", "home", "ignore", "java-properties", @@ -1125,36 +1105,36 @@ dependencies = [ "regex", "serde", "serde_json", - "textwrap", - "thiserror 2.0.12", - "toml 1.0.6+spec-1.1.0", + "textwrap 0.16.2", + "thiserror 2.0.18", + "toml 1.1.0+spec-1.1.0", "ureq", "which", - "windows 0.61.1", + "windows", "x509-certificate", ] [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] [[package]] name = "cargo_metadata" -version = "0.19.0" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc309ed89476c8957c50fb818f56fe894db857866c3e163335faa91dc34eb85" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] @@ -1165,7 +1145,7 @@ checksum = "aa61aec073ec94791433ddf3df2323ff9d1711557c2a0eefb0f99cb4f8dca520" dependencies = [ "semver", "serde", - "toml 1.0.6+spec-1.1.0", + "toml 1.1.0+spec-1.1.0", ] [[package]] @@ -1179,9 +1159,9 @@ dependencies = [ [[package]] name = "castaway" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" dependencies = [ "rustversion", ] @@ -1197,9 +1177,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.51" +version = "1.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" dependencies = [ "find-msvc-tools", "jobserver", @@ -1235,9 +1215,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.8" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +checksum = "fb693542bcafa528e198be0ebd9d3632ca5b7c93dbe7237460e199910835997c" dependencies = [ "smallvec", "target-lexicon", @@ -1245,9 +1225,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -1268,17 +1248,16 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-link 0.1.1", + "windows-link 0.2.1", ] [[package]] @@ -1287,15 +1266,30 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common 0.1.6", + "crypto-common 0.1.7", "inout", ] [[package]] name = "clap" -version = "4.5.26" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim 0.8.0", + "textwrap 0.11.0", + "unicode-width 0.1.14", + "vec_map", +] + +[[package]] +name = "clap" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -1303,42 +1297,42 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.26" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.1", ] [[package]] name = "clap_complete" -version = "4.5.42" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0" +checksum = "db8b397918185f0161ff3d6fcaa9e4bfc09b8367caf6e1d4a2848e5477ed027b" dependencies = [ - "clap", + "clap 4.6.1", ] [[package]] name = "clap_derive" -version = "4.5.24" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "cmac" @@ -1359,9 +1353,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "colored" @@ -1412,16 +1406,25 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console" -version = "0.15.10" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width", + "unicode-width 0.2.2", "windows-sys 0.59.0", ] @@ -1433,7 +1436,7 @@ checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" dependencies = [ "encode_unicode", "libc", - "unicode-width", + "unicode-width 0.2.2", "windows-sys 0.61.2", ] @@ -1461,9 +1464,12 @@ checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" [[package]] name = "const_panic" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2459fc9262a1aa204eb4b5764ad4f189caec88aea9634389c0a25f8be7f6265e" +checksum = "e262cdaac42494e3ae34c43969f9cdeb7da178bdb4b66fa6a1ea2edb4c8ae652" +dependencies = [ + "typewit", +] [[package]] name = "convert_case" @@ -1511,9 +1517,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -1525,19 +1531,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core-graphics" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" -dependencies = [ - "bitflags 2.13.0", - "core-foundation 0.10.0", - "core-graphics-types", - "foreign-types 0.5.0", - "libc", -] - [[package]] name = "core-graphics" version = "0.25.0" @@ -1545,7 +1538,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ "bitflags 2.13.0", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "core-graphics-types", "foreign-types 0.5.0", "libc", @@ -1558,15 +1551,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ "bitflags 2.13.0", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "libc", ] [[package]] name = "core_maths" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b02505ccb8c50b0aa21ace0fc08c3e53adebd4e58caa18a36152803c7709a3" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" dependencies = [ "libm", ] @@ -1597,9 +1590,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -1630,18 +1623,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1658,15 +1651,15 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-bigint" @@ -1682,9 +1675,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -1729,7 +1722,7 @@ version = "0.29.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" dependencies = [ - "cssparser-macros", + "cssparser-macros 0.6.1", "dtoa-short", "itoa", "matches", @@ -1746,7 +1739,20 @@ version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" dependencies = [ - "cssparser-macros", + "cssparser-macros 0.6.1", + "dtoa-short", + "itoa", + "phf 0.13.1", + "smallvec", +] + +[[package]] +name = "cssparser" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98" +dependencies = [ + "cssparser-macros 0.7.0", "dtoa-short", "itoa", "phf 0.13.1", @@ -1760,7 +1766,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[package]] +name = "cssparser-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a2a99df6e410a8ff4245aa2006499ea662245f967cc7c0a38c83ef8eb44dbf" +dependencies = [ + "quote", + "syn 2.0.118", ] [[package]] @@ -1771,9 +1787,9 @@ checksum = "49fb0c6640b4507ebd99ff67677009e381ba5eee1d14df78de4a3d16eb123c39" [[package]] name = "ctor" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a" +checksum = "fb22e947478ccf9dc44d8922042c677a63fbb88f2cb468521d1145816e5087cb" [[package]] name = "ctr" @@ -1786,12 +1802,13 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.5" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" dependencies = [ + "dispatch2", "nix", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1801,7 +1818,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures 0.2.16", + "cpufeatures 0.2.17", "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto 0.2.9", @@ -1819,42 +1836,76 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", ] [[package]] name = "darling" -version = "0.20.10" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim", - "syn 2.0.117", + "strsim 0.11.1", + "syn 2.0.118", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.118", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.118", ] [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "darling_core", + "darling_core 0.23.0", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1865,9 +1916,9 @@ checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" [[package]] name = "data-url" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" [[package]] name = "dbl" @@ -1880,44 +1931,105 @@ dependencies = [ [[package]] name = "dbus" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b3aa68d7e7abee336255bd7248ea965cc393f3e70411135a6f6a4b651345d4" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" dependencies = [ "libc", "libdbus-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] -name = "der" -version = "0.7.9" +name = "dbus-codegen" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "a49da9fdfbe872d4841d56605dc42efa5e6ca3291299b87f44e1cde91a28617c" dependencies = [ - "const-oid 0.9.6", - "pem-rfc7468", - "zeroize", + "clap 2.34.0", + "dbus", + "xml-rs", ] [[package]] -name = "deranged" -version = "0.5.8" +name = "dbus-tree" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "f456e698ae8e54575e19ddb1f9b7bce2298568524f215496b248eb9498b4f508" dependencies = [ - "serde_core", + "dbus", ] [[package]] -name = "derive_arbitrary" -version = "1.4.1" +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" dependencies = [ + "defmt-parser", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.18", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid 0.9.6", + "pem-rfc7468 0.7.0", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "pem-rfc7468 1.0.0", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] @@ -1935,10 +2047,10 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ - "darling", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1948,20 +2060,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "derive_more" -version = "0.99.18" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1975,11 +2087,11 @@ dependencies = [ [[package]] name = "derive_more" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ - "derive_more-impl 2.0.1", + "derive_more-impl 2.1.1", ] [[package]] @@ -1990,19 +2102,20 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "unicode-xid", ] [[package]] name = "derive_more-impl" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "rustc_version", + "syn 2.0.118", ] [[package]] @@ -2016,9 +2129,9 @@ dependencies = [ [[package]] name = "deunicode" -version = "1.6.0" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" [[package]] name = "dialoguer" @@ -2026,7 +2139,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" dependencies = [ - "console 0.15.10", + "console 0.15.11", "shell-words", "tempfile", "thiserror 1.0.69", @@ -2065,7 +2178,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "const-oid 0.9.6", - "crypto-common 0.1.6", + "crypto-common 0.1.7", "subtle", ] @@ -2118,7 +2231,7 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users 0.5.0", + "redox_users 0.5.2", "windows-sys 0.61.2", ] @@ -2129,27 +2242,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ "bitflags 2.13.0", - "block2 0.6.2", + "block2", "libc", - "objc2 0.6.4", + "objc2", ] [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[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 = "dlopen2" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" dependencies = [ "dlopen2_derive", "libc", @@ -2159,13 +2281,13 @@ dependencies = [ [[package]] name = "dlopen2_derive" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2180,14 +2302,35 @@ dependencies = [ "html5ever 0.38.0", "precomputed-hash", "selectors 0.36.1", - "tendril 0.5.0", + "tendril 0.5.1", ] +[[package]] +name = "dom_query" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac5fca71e65e94cc718a6e2af65d6e0f9c6027751c2aa562fbb5087fda639bc" +dependencies = [ + "bit-set", + "cssparser 0.37.0", + "foldhash 0.2.0", + "html5ever 0.39.0", + "precomputed-hash", + "selectors 0.38.0", + "tendril 0.5.1", +] + +[[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.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" dependencies = [ "serde", ] @@ -2209,16 +2352,16 @@ dependencies = [ "num-traits", "pkcs8", "rfc6979", - "sha2 0.10.8", + "sha2 0.10.9", "signature", "zeroize", ] [[package]] name = "dtoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" [[package]] name = "dtoa-short" @@ -2249,9 +2392,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "eax" @@ -2272,7 +2415,7 @@ version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der", + "der 0.7.10", "digest 0.10.7", "elliptic-curve", "rfc6979", @@ -2292,14 +2435,14 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519", "serde", - "sha2 0.10.8", + "sha2 0.10.9", "subtle", "zeroize", ] @@ -2317,9 +2460,9 @@ dependencies = [ [[package]] name = "either" -version = "1.13.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" [[package]] name = "elf" @@ -2340,7 +2483,7 @@ dependencies = [ "generic-array", "group", "hkdf", - "pem-rfc7468", + "pem-rfc7468 0.7.0", "pkcs8", "rand_core 0.6.4", "sec1", @@ -2359,14 +2502,14 @@ dependencies = [ [[package]] name = "embed-resource" -version = "3.0.9" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31a88c8d26de40ed18fe748c547845aa39de1db3afd958f8cb91579f3644bcb" +checksum = "fbfdaacccebec3b28e4866b8973543c7647797db5ada1bdab552e48fe665fbbd" dependencies = [ "cc", "memchr", "rustc_version", - "toml 1.0.6+spec-1.1.0", + "toml 1.1.0+spec-1.1.0", "vswhom", "winreg", ] @@ -2417,30 +2560,24 @@ checksum = "ba7795da175654fe16979af73f81f26a8ea27638d8d9823d317016888a63dc4c" dependencies = [ "num-traits", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "env_filter" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" dependencies = [ "log", "regex", ] [[package]] -name = "env_home" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" - -[[package]] -name = "env_logger" -version = "0.8.4" +name = "env_filter" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" dependencies = [ "log", "regex", @@ -2448,14 +2585,14 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.6" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" dependencies = [ "anstream", "anstyle", - "env_filter", - "humantime", + "env_filter 2.0.0", + "jiff", "log", ] @@ -2476,20 +2613,20 @@ checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" dependencies = [ "serde", "serde_core", @@ -2498,12 +2635,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2515,6 +2652,27 @@ dependencies = [ "num-traits", ] +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "exr" version = "1.74.0" @@ -2532,9 +2690,9 @@ dependencies = [ [[package]] name = "fancy-regex" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8" +checksum = "e1e1dacd0d2082dfcf1351c4bdd566bbe89a2b263235a2b50058f1e130a47277" dependencies = [ "bit-set", "regex-automata", @@ -2543,9 +2701,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "fax" @@ -2573,9 +2731,9 @@ dependencies = [ [[package]] name = "ff" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ "rand_core 0.6.4", "subtle", @@ -2612,7 +2770,7 @@ dependencies = [ "atomic", "pear", "serde", - "toml 0.8.20", + "toml 0.8.23", "uncased", "version_check", ] @@ -2628,31 +2786,29 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.25" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" dependencies = [ "cfg-if", "libc", - "libredox", - "windows-sys 0.59.0", ] [[package]] name = "find-msvc-tools" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", - "libz-rs-sys", "miniz_oxide", + "zlib-rs", ] [[package]] @@ -2692,9 +2848,9 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "fontconfig-parser" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" dependencies = [ "roxmltree 0.20.0", ] @@ -2740,7 +2896,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2766,9 +2922,9 @@ dependencies = [ [[package]] name = "fraction" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f158e3ff0a1b334408dc9fb811cd99b446986f4d8b741bb08f9df1604085ae7" +checksum = "e076045bb43dac435333ed5f04caf35c7463631d0dae2deb2638d94dd0a5b872" dependencies = [ "lazy_static", "num", @@ -2811,9 +2967,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -2826,9 +2982,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -2836,15 +2992,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -2853,44 +3009,44 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-timer" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -2900,7 +3056,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -2913,39 +3068,23 @@ dependencies = [ "byteorder", ] -[[package]] -name = "gdk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" -dependencies = [ - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - [[package]] name = "gdk-pixbuf" -version = "0.18.5" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +checksum = "25f420376dbee041b2db374ce4573892a36222bb3f6c0c43e24f0d67eae9b646" dependencies = [ "gdk-pixbuf-sys", "gio", "glib", "libc", - "once_cell", ] [[package]] name = "gdk-pixbuf-sys" -version = "0.18.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +checksum = "48f31b37b1fc4b48b54f6b91b7ef04c18e00b4585d98359dd7b998774bbd91fb" dependencies = [ "gio-sys", "glib-sys", @@ -2955,10 +3094,25 @@ dependencies = [ ] [[package]] -name = "gdk-sys" -version = "0.18.2" +name = "gdk4" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d81e2a6c6ecba2aab60633a98df1868b03fa0bfdce8105edc27c1bccf71f0e39" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk4-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk4-sys" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +checksum = "3d8f608d8d7d229975c4d0d026f5d3071598c4ddab3c5262b0a31840fec78d13" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -2972,44 +3126,55 @@ dependencies = [ ] [[package]] -name = "gdkwayland-sys" -version = "0.18.2" +name = "gdk4-wayland" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +checksum = "32d95828dadc0357dee236cc6a5712808bd894d3217159982592ce24f2b8aaf7" +dependencies = [ + "gdk4", + "gdk4-wayland-sys", + "gio", + "glib", + "libc", + "wayland-backend", + "wayland-client", + "wayland-protocols", +] + +[[package]] +name = "gdk4-wayland-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653cafb8715f2ac1c56edaf8060d9360ae3acbe3c6fb61b676a2917d42b668cf" dependencies = [ - "gdk-sys", "glib-sys", - "gobject-sys", "libc", - "pkg-config", "system-deps", ] [[package]] -name = "gdkx11" -version = "0.18.2" +name = "gdk4-x11" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" +checksum = "9d892b4cf5a07e90e1390e93cd792975746c68b59f790a2de9e96ce77211ea9a" dependencies = [ - "gdk", - "gdkx11-sys", + "gdk4", + "gdk4-x11-sys", "gio", "glib", "libc", - "x11", ] [[package]] -name = "gdkx11-sys" -version = "0.18.2" +name = "gdk4-x11-sys" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" +checksum = "24d41f2e28f62378b081288914325d73bddbb6ccbbadb41aa6392afc71d27002" dependencies = [ - "gdk-sys", + "gdk4-sys", "glib-sys", "libc", "system-deps", - "x11", ] [[package]] @@ -3036,14 +3201,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -3075,6 +3240,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getset" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cf442baaabe4213ce7d1239afc26c039180b6456da2cededa316ae2c8a77a77" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "ghash" version = "0.5.1" @@ -3095,17 +3271,11 @@ dependencies = [ "weezl", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "gio" -version = "0.18.4" +version = "0.22.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +checksum = "8b3e1f669909c326b9413bde5a742097b8c90a7d78f45326db13668984769ded" dependencies = [ "futures-channel", "futures-core", @@ -3114,30 +3284,28 @@ dependencies = [ "gio-sys", "glib", "libc", - "once_cell", "pin-project-lite", "smallvec", - "thiserror 1.0.69", ] [[package]] name = "gio-sys" -version = "0.18.1" +version = "0.22.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +checksum = "353fdc7da7cd16da916104b1e0e4e7de380ec9c8aaa20d4d742d66310ab4b0d5" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", - "winapi", + "windows-sys 0.61.2", ] [[package]] name = "glib" -version = "0.18.5" +version = "0.22.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +checksum = "ddbcf514bd1881fc1b960e4e52b4e82873f4da3bceddbd58d42827b508888100" dependencies = [ "bitflags 2.13.0", "futures-channel", @@ -3151,30 +3319,26 @@ dependencies = [ "gobject-sys", "libc", "memchr", - "once_cell", "smallvec", - "thiserror 1.0.69", ] [[package]] name = "glib-macros" -version = "0.18.5" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +checksum = "506d23499707c7142898429757e8d9a3871d965239a2cb66dfa05052be6d6f19" dependencies = [ - "heck 0.4.1", - "proc-macro-crate 2.0.0", - "proc-macro-error", + "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "glib-sys" -version = "0.18.1" +version = "0.22.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +checksum = "030967459f9f676851872c6304adea7825c6d462ec9b72554c733cf0c5952233" dependencies = [ "libc", "system-deps", @@ -3182,15 +3346,15 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "globset" -version = "0.4.15" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" dependencies = [ "aho-corasick", "bstr", @@ -3201,9 +3365,9 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.18.0" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +checksum = "22a861859b887a79cf461359c192c97a57d8fb0229dd291232e57aa11f6fa72c" dependencies = [ "glib-sys", "libc", @@ -3221,6 +3385,27 @@ dependencies = [ "scroll", ] +[[package]] +name = "graphene-rs" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb856b9c558971c3f13ab692358926da710b046932a4e087aedcc35b040d7dff" +dependencies = [ + "glib", + "graphene-sys", +] + +[[package]] +name = "graphene-sys" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ffdfde88f3570d3705e0d8a2433e036d387a1f2930bbf47eafcb5f569fd04" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + [[package]] name = "group" version = "0.13.0" @@ -3233,62 +3418,93 @@ dependencies = [ ] [[package]] -name = "gtk" -version = "0.18.2" +name = "gsk4" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +checksum = "b867be1c5f14dcb8f552c0eff6e9a9b1da5f8b43943e8efc3a63c889d84952ff" dependencies = [ - "atk", "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", + "gdk4", "glib", - "gtk-sys", - "gtk3-macros", + "graphene-rs", + "gsk4-sys", "libc", "pango", - "pkg-config", ] [[package]] -name = "gtk-sys" -version = "0.18.2" +name = "gsk4-sys" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +checksum = "5b7c7eb2e681ee896646cfb8872b431f24d09f53ba9283289d9b10caa6707088" dependencies = [ - "atk-sys", "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", + "gdk4-sys", "glib-sys", "gobject-sys", + "graphene-sys", "libc", "pango-sys", "system-deps", ] [[package]] -name = "gtk3-macros" -version = "0.18.2" +name = "gtk4" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +checksum = "98a0a0466484f64b07b5b8184d43fa46be78eb0b8e04ae4e179af31d770b76d9" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk-pixbuf", + "gdk4", + "gio", + "glib", + "graphene-rs", + "gsk4", + "gtk4-macros", + "gtk4-sys", + "libc", + "pango", +] + +[[package]] +name = "gtk4-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac7179400a36a04de039c24206bb841c5596992b907b43b23ee8d5bdc40d00e" +dependencies = [ + "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[package]] +name = "gtk4-sys" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f954786af0b1984425c4446b77f5ff6594346181316be3f850caab1c6f01" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk4-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "graphene-sys", + "gsk4-sys", + "libc", + "pango-sys", + "system-deps", ] [[package]] name = "h2" -version = "0.4.7" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" dependencies = [ "atomic-waker", "bytes", @@ -3305,19 +3521,20 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] name = "handlebars" -version = "6.3.0" +version = "6.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6b224b95c1e668ac0270325ad563b2eef1469fbbb8959bc7c692c844b813d9" +checksum = "f26569a2763497b7bd3fbd19374b774ea6038c5293678771259cd534d49740ff" dependencies = [ "derive_builder", "log", @@ -3326,7 +3543,7 @@ dependencies = [ "pest_derive", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -3344,7 +3561,7 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", ] [[package]] @@ -3369,15 +3586,18 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "heck" -version = "0.5.0" +name = "hermit-abi" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] [[package]] name = "hex" @@ -3405,11 +3625,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3434,14 +3654,23 @@ dependencies = [ "markup5ever 0.38.0", ] +[[package]] +name = "html5ever" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" +dependencies = [ + "log", + "markup5ever 0.39.0", +] + [[package]] name = "http" -version = "1.3.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -3457,12 +3686,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", + "futures-core", "http", "http-body", "pin-project-lite", @@ -3476,9 +3705,9 @@ checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -3486,12 +3715,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "hybrid-array" version = "0.4.13" @@ -3503,9 +3726,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.8.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", @@ -3518,7 +3741,6 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -3526,21 +3748,19 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "futures-util", "http", "hyper", "hyper-util", "rustls", - "rustls-native-certs 0.8.3", - "rustls-pki-types", + "rustls-native-certs 0.8.4", "tokio", "tokio-rustls", "tower-service", - "webpki-roots 0.26.11", + "webpki-roots", ] [[package]] @@ -3561,14 +3781,13 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -3577,7 +3796,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", + "socket2", "tokio", "tower-service", "tracing", @@ -3585,16 +3804,17 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core 0.62.2", ] [[package]] @@ -3618,12 +3838,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -3631,9 +3852,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -3644,9 +3865,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -3658,15 +3879,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -3678,15 +3899,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -3725,9 +3946,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", @@ -3735,9 +3956,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.23" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +checksum = "fe112b004901c62c2faa11f4f75e9864e0cc5af8da71c9115d184a3aa888749f" dependencies = [ "crossbeam-deque", "globset", @@ -3854,9 +4075,9 @@ checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" [[package]] name = "inotify" -version = "0.11.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" +checksum = "dd854a95a4ac672fed8c054136039fd32c22cf039ff09ead7280afe920486483" dependencies = [ "bitflags 2.13.0", "inotify-sys", @@ -3865,18 +4086,18 @@ dependencies = [ [[package]] name = "inotify-sys" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d" dependencies = [ "libc", ] [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "block-padding", "generic-array", @@ -3884,14 +4105,14 @@ dependencies = [ [[package]] name = "insta" -version = "1.42.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513e4067e16e69ed1db5ab56048ed65db32d10ba5fc1217f5393f8f17d8b5a5" +checksum = "86f0f8fee8c926415c58d6ae43a08523a26faccb2323f5e6b644fe7dd4ef6b82" dependencies = [ - "console 0.15.10", - "linked-hash-map", + "console 0.16.4", "once_cell", "similar", + "tempfile", ] [[package]] @@ -3902,39 +4123,29 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "ipnet" -version = "2.10.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" - -[[package]] -name = "iri-string" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" -dependencies = [ - "memchr", - "serde", -] +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "is_executable" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a1b5bad6f9072935961dfbf1cced2f3d129963d091b6f69f007fe04e758ae2" +checksum = "82cb6a9f675da968c63b6208c641b9dca58fc0133ae53375736b1767b0cab8bd" dependencies = [ - "winapi", + "windows-sys 0.61.2", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "iter-read" @@ -3971,9 +4182,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "java-properties" @@ -3987,21 +4198,21 @@ dependencies = [ ] [[package]] -name = "javascriptcore-rs" -version = "1.1.2" +name = "javascriptcore6" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +checksum = "8d8d4f64d976c6dc6068723b6ef7838acf954d56b675f376c826f7e773362ddb" dependencies = [ - "bitflags 1.3.2", "glib", - "javascriptcore-rs-sys", + "javascriptcore6-sys", + "libc", ] [[package]] -name = "javascriptcore-rs-sys" -version = "1.1.1" +name = "javascriptcore6-sys" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +checksum = "f2b9787581c8949a7061c9b8593c4d1faf4b0fe5e5643c6c7793df20dbe39cf6" dependencies = [ "glib-sys", "gobject-sys", @@ -4009,6 +4220,31 @@ dependencies = [ "system-deps", ] +[[package]] +name = "jiff" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccfe6121cbe750cf81efa362d85c0bde7ea298ec43092d3a193baca59cdbd634" +dependencies = [ + "defmt", + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e165e897f662d428f3cd3828a919dbe067c2d42bb1031eede74ef9d27ecdedd2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "jni" version = "0.21.1" @@ -4018,33 +4254,86 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-sys 0.3.1", "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 2.0.118", +] + [[package]] name = "jni-sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[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 2.0.118", +] [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.102" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ "cfg-if", "futures-util", @@ -4060,7 +4349,7 @@ dependencies = [ "jsonptr", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -4108,7 +4397,7 @@ dependencies = [ "jsonrpsee-core", "pin-project", "soketto", - "thiserror 2.0.12", + "thiserror 2.0.18", "tokio", "tokio-util", "tracing", @@ -4135,7 +4424,7 @@ dependencies = [ "rustc-hash", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.18", "tokio", "tokio-stream", "tower", @@ -4161,7 +4450,7 @@ dependencies = [ "serde", "serde_json", "soketto", - "thiserror 2.0.12", + "thiserror 2.0.18", "tokio", "tokio-stream", "tokio-util", @@ -4178,7 +4467,7 @@ dependencies = [ "http", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -4197,11 +4486,11 @@ dependencies = [ [[package]] name = "jsonschema" -version = "0.46.2" +version = "0.46.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50180452e7808015fe083eae3efcf1ec98b89b45dd8cc204f7b4a6b7b81ea675" +checksum = "f0a699d3e77675e6aa4bfffe3b907c8b5f7ed3241f9965bffb25475ad4b08d05" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "bytecount", "data-encoding", "email_address", @@ -4210,18 +4499,27 @@ dependencies = [ "getrandom 0.3.4", "idna", "itoa", + "jsonschema-regex", "num-cmp", "num-traits", "percent-encoding", "referencing", "regex", - "regex-syntax", "serde", "serde_json", "unicode-general-category", "uuid-simd", ] +[[package]] +name = "jsonschema-regex" +version = "0.46.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbd1086b01b9349fd4ef9a07433965af64c8ce8159abe633a189e4ff817bd13" +dependencies = [ + "regex-syntax", +] + [[package]] name = "k256" version = "0.13.4" @@ -4232,7 +4530,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "once_cell", - "sha2 0.10.8", + "sha2 0.10.9", "signature", ] @@ -4242,7 +4540,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures 0.2.16", + "cpufeatures 0.2.17", ] [[package]] @@ -4258,9 +4556,9 @@ dependencies = [ [[package]] name = "konst" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4381b9b00c55f251f2ebe9473aef7c117e96828def1a7cb3bd3f0f903c6894e9" +checksum = "97feab15b395d1860944abe6a8dd8ed9f8eadfae01750fada8427abda531d887" dependencies = [ "const_panic", "konst_kernel", @@ -4278,9 +4576,9 @@ dependencies = [ [[package]] name = "kqueue" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" +checksum = "273c0752728918e0ac4976f2b275b6fefb9ecd400585dec929419f3844cd87b5" dependencies = [ "kqueue-sys", "libc", @@ -4288,14 +4586,26 @@ dependencies = [ [[package]] name = "kqueue-sys" -version = "1.0.4" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.13.0", "libc", ] +[[package]] +name = "ksni" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4934310bdd016e55725482b8d35ac0c16fd058c1b955d8959aa2d953b918c85b" +dependencies = [ + "dbus", + "dbus-codegen", + "dbus-tree", + "thiserror 1.0.69", +] + [[package]] name = "kuchikiki" version = "0.8.8-speedreader" @@ -4331,39 +4641,15 @@ dependencies = [ [[package]] name = "lebe" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" - -[[package]] -name = "libappindicator" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" -dependencies = [ - "glib", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.9.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" -dependencies = [ - "gtk-sys", - "libloading 0.7.4", - "once_cell", -] +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libc" -version = "0.2.178" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libdbus-sys" @@ -4376,9 +4662,9 @@ dependencies = [ [[package]] name = "libfuzzer-sys" -version = "0.4.8" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa" +checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2" dependencies = [ "arbitrary", "cc", @@ -4386,12 +4672,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "winapi", + "windows-link 0.2.1", ] [[package]] @@ -4406,66 +4692,24 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.11" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.13.0", - "libc", - "redox_syscall", -] - -[[package]] -name = "libxdo" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00333b8756a3d28e78def82067a377de7fa61b24909000aeaa2b446a948d14db" -dependencies = [ - "libxdo-sys", -] - -[[package]] -name = "libxdo-sys" -version = "0.11.0" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db23b9e7e2b7831bbd8aac0bbeeeb7b68cbebc162b227e7052e8e55829a09212" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" dependencies = [ "libc", - "x11", ] -[[package]] -name = "libz-rs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a" -dependencies = [ - "zlib-rs", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[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" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" @@ -4475,37 +4719,29 @@ checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "local-ip-address" -version = "0.6.3" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3669cf5561f8d27e8fc84cc15e58350e70f557d4d65f70e3154e54cd2f8e1782" +checksum = "aa08fb2b1ec3ea84575e94b489d06d4ce0cbf052d12acd515838f50e3c3d63e3" dependencies = [ "libc", "neli", - "thiserror 1.0.69", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" -version = "0.4.29" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" dependencies = [ "value-bag", ] @@ -4564,8 +4800,8 @@ dependencies = [ "log", "phf 0.11.3", "phf_codegen 0.11.3", - "string_cache 0.8.7", - "string_cache_codegen 0.5.2", + "string_cache 0.8.9", + "string_cache_codegen 0.5.4", "tendril 0.4.3", ] @@ -4576,7 +4812,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" dependencies = [ "log", - "tendril 0.5.0", + "tendril 0.5.1", + "web_atoms", +] + +[[package]] +name = "markup5ever" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" +dependencies = [ + "log", + "tendril 0.5.1", "web_atoms", ] @@ -4588,7 +4835,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -4688,7 +4935,7 @@ checksum = "bd2209fff77f705b00c737016a48e73733d7fbccb8b007194db148f03561fb70" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -4711,9 +4958,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", "simd-adler32", @@ -4721,14 +4968,14 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", ] [[package]] @@ -4743,31 +4990,29 @@ dependencies = [ [[package]] name = "muda" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae8844f63b5b118e334e205585b8c5c17b984121dbdb179d44aeb087ffad3cb" +version = "0.19.3" dependencies = [ + "arc-swap", "crossbeam-channel", "dpi", - "gtk", + "gtk4", "keyboard-types", - "libxdo", - "objc2 0.6.4", + "objc2", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation", "once_cell", "png 0.18.1", "serde", - "thiserror 2.0.12", + "thiserror 2.0.18", "windows-sys 0.61.2", ] [[package]] name = "napi" -version = "3.9.4" +version = "3.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41bda2ac390efb5e8d22025d925ccc3f3807d8c1bea6d19b36127247c4b8f83" +checksum = "0c71997d6f7ad4a756966e452426848ac27d3b37a295302d63afbbcce0270f93" dependencies = [ "bitflags 2.13.0", "ctor", @@ -4786,29 +5031,29 @@ checksum = "c9c366d2c8c60b86fa632df75f745509b52f9128f91a6bad4c796e44abb505e1" [[package]] name = "napi-derive" -version = "3.5.7" +version = "3.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61d66f70256ad5aef58659966064471d0ad90e2897bc36a5a5e0389c85aabc1e" +checksum = "d4ba572deef53e2c386759a8c2014175a62679d74ff83adc205c8bc0e0285727" dependencies = [ "convert_case 0.11.0", "ctor", "napi-derive-backend", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "napi-derive-backend" -version = "5.0.5" +version = "5.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b4b08f15eed7a2a20c3f4c6314013fc3ac890a3afa9892b594485299ebdb2d" +checksum = "ddd961eb2aa8965e3f29722d754f3a86907eb1984e2fbcbe3fe87b9a02d6bfba" dependencies = [ "convert_case 0.11.0", "proc-macro2", "quote", "semver", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -4822,17 +5067,17 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.12" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ "libc", "log", "openssl", - "openssl-probe 0.1.5", + "openssl-probe 0.2.1", "openssl-sys", "schannel", - "security-framework 2.11.1", + "security-framework 3.7.0", "security-framework-sys", "tempfile", ] @@ -4844,7 +5089,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ "bitflags 2.13.0", - "jni-sys", + "jni-sys 0.3.1", "log", "ndk-sys", "num_enum", @@ -4858,32 +5103,36 @@ version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "jni-sys", + "jni-sys 0.3.1", ] [[package]] name = "neli" -version = "0.6.4" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43" +checksum = "22f9786d56d972959e1408b6a93be6af13b9c1392036c5c1fafa08a1b0c6ee87" dependencies = [ + "bitflags 2.13.0", "byteorder", + "derive_builder", + "getset", "libc", "log", "neli-proc-macros", + "parking_lot", ] [[package]] name = "neli-proc-macros" -version = "0.1.3" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" +checksum = "05d8d08c6e98f20a62417478ebf7be8e1425ec9acecc6f63e22da633f6b71609" dependencies = [ "either", "proc-macro2", "quote", "serde", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] @@ -4894,9 +5143,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nix" -version = "0.29.0" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ "bitflags 2.13.0", "cfg-if", @@ -4989,9 +5238,12 @@ dependencies = [ [[package]] name = "notify-types" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" +checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" +dependencies = [ + "bitflags 2.13.0", +] [[package]] name = "num" @@ -5009,9 +5261,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ "num-integer", "num-traits", @@ -5063,7 +5315,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -5088,9 +5340,9 @@ dependencies = [ [[package]] name = "num-modular" -version = "0.6.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" +checksum = "fc41a1374056e9672221567958a66c16be12d0e2c1b408761e14d901c237d5e0" [[package]] name = "num-order" @@ -5124,23 +5376,24 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -5152,22 +5405,6 @@ dependencies = [ "libc", ] -[[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" @@ -5180,78 +5417,92 @@ dependencies = [ [[package]] name = "objc2-app-kit" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ "bitflags 2.13.0", - "block2 0.6.2", - "objc2 0.6.4", + "block2", + "objc2", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation", ] [[package]] name = "objc2-cloud-kit" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c1948a9be5f469deadbd6bcb86ad7ff9e47b4f632380139722f7d9840c0d42c" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ "bitflags 2.13.0", - "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2", + "objc2-foundation", ] [[package]] name = "objc2-core-data" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f860f8e841f6d32f754836f51e6bc7777cd7e7053cf18528233f6811d3eceb4" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" dependencies = [ - "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2", + "objc2-foundation", ] [[package]] name = "objc2-core-foundation" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.13.0", - "objc2 0.6.4", + "dispatch2", + "objc2", ] [[package]] name = "objc2-core-graphics" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ "bitflags 2.13.0", - "objc2 0.6.4", + "dispatch2", + "objc2", "objc2-core-foundation", "objc2-io-surface", ] [[package]] name = "objc2-core-image" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ffa6bea72bf42c78b0b34e89c0bafac877d5f80bf91e159a5d96ea7f693ca56" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" dependencies = [ - "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2", + "objc2-foundation", ] [[package]] name = "objc2-core-location" -version = "0.3.0" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d31f4c5b5192304996badc466aeadffe1411d73a9bbd3b18b6b2ee9d048b07bd" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ - "objc2 0.6.4", - "objc2-foundation 0.3.0", + "bitflags 2.13.0", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", ] [[package]] @@ -5271,118 +5522,83 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.2.2" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.13.0", - "block2 0.5.1", + "block2", "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-foundation" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" -dependencies = [ - "bitflags 2.13.0", - "block2 0.6.2", - "objc2 0.6.4", + "objc2", "objc2-core-foundation", ] [[package]] name = "objc2-io-surface" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ "bitflags 2.13.0", - "objc2 0.6.4", + "objc2", "objc2-core-foundation", ] -[[package]] -name = "objc2-metal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" -dependencies = [ - "bitflags 2.13.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.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.13.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - [[package]] name = "objc2-quartz-core" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb3794501bb1bee12f08dcad8c61f2a5875791ad1c6f47faa71a0f033f20071" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ "bitflags 2.13.0", - "objc2 0.6.4", + "objc2", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation", ] [[package]] name = "objc2-ui-kit" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777a571be14a42a3990d4ebedaeb8b54cd17377ec21b92e8200ac03797b3bee1" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ "bitflags 2.13.0", - "block2 0.6.2", - "objc2 0.6.4", + "block2", + "objc2", "objc2-cloud-kit", "objc2-core-data", "objc2-core-foundation", "objc2-core-graphics", "objc2-core-image", "objc2-core-location", - "objc2-foundation 0.3.0", - "objc2-quartz-core 0.3.0", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", "objc2-user-notifications", ] [[package]] name = "objc2-user-notifications" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670fe793adbf3b5e93686d48a05a7ed7ee53dfa65d106ced4805fae8969059b2" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" dependencies = [ - "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2", + "objc2-foundation", ] [[package]] name = "objc2-web-kit" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b717127e4014b0f9f3e8bba3d3f2acec81f1bde01f656823036e823ed2c94dce" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ "bitflags 2.13.0", - "block2 0.6.2", - "objc2 0.6.4", + "block2", + "objc2", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation", ] [[package]] @@ -5435,6 +5651,12 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "opaque-debug" version = "0.3.1" @@ -5443,15 +5665,14 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.78" +version = "0.10.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" dependencies = [ "bitflags 2.13.0", "cfg-if", "foreign-types 0.3.2", "libc", - "once_cell", "openssl-macros", "openssl-sys", ] @@ -5464,35 +5685,35 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-probe" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-src" -version = "300.4.1+3.4.0" +version = "300.6.1+3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" +checksum = "46eb8fb9fb3b61ce1c0f8a026c4c1a0714d3a9e138e7fbde78753ce2babc3846" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.114" +version = "0.9.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", @@ -5518,13 +5739,18 @@ dependencies = [ [[package]] name = "os_info" -version = "3.9.2" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e6520c8cc998c5741ee68ec1dc369fc47e5f0ea5320018ecf2a1ccd6328f48b" +checksum = "9cf20a545b305cf1da722b236b5155c9bb35f1d5ceb28c048bd96ca842f41b5b" dependencies = [ + "android_system_properties", "log", + "nix", + "objc2", + "objc2-foundation", + "objc2-ui-kit", "serde", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5539,15 +5765,15 @@ dependencies = [ [[package]] name = "outref" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] name = "owo-colors" -version = "4.1.0" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56" +checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" [[package]] name = "oxc-miette" @@ -5558,10 +5784,10 @@ dependencies = [ "cfg-if", "owo-colors", "oxc-miette-derive", - "textwrap", - "thiserror 2.0.12", + "textwrap 0.16.2", + "thiserror 2.0.18", "unicode-segmentation", - "unicode-width", + "unicode-width 0.2.2", ] [[package]] @@ -5572,7 +5798,7 @@ checksum = "b237422b014f8f8fff75bb9379e697d13f8d57551a22c88bebb39f073c1bf696" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -5613,7 +5839,7 @@ dependencies = [ "phf 0.13.1", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -5746,7 +5972,7 @@ dependencies = [ "cbc", "cipher", "des", - "getrandom 0.2.15", + "getrandom 0.2.17", "hmac", "lazy_static", "rc2", @@ -5763,19 +5989,19 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] name = "p384" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] @@ -5789,27 +6015,25 @@ dependencies = [ "elliptic-curve", "primeorder", "rand_core 0.6.4", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] name = "pango" -version = "0.18.3" +version = "0.22.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +checksum = "5d800d8d0de2ad5d0fb046f5344dbaba14a003cf3dd27cc21d85893d35ea316c" dependencies = [ "gio", "glib", - "libc", - "once_cell", "pango-sys", ] [[package]] name = "pango-sys" -version = "0.18.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +checksum = "bbd111a20ca90fedf03e09c59783c679c00900f1d8491cca5399f5e33609d5d6" dependencies = [ "glib-sys", "gobject-sys", @@ -5817,11 +6041,17 @@ dependencies = [ "system-deps", ] +[[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.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -5829,15 +6059,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -5905,17 +6135,17 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "pem" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ "base64 0.22.1", - "serde", + "serde_core", ] [[package]] @@ -5927,6 +6157,15 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pem-rfc7468" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -5935,20 +6174,19 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.7.15" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +checksum = "47627dd7305c6a2d6c8c6bcd24c5a4c17dbbf425f4f9c5313e724b38fc9782e9" dependencies = [ "memchr", - "thiserror 2.0.12", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.15" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" +checksum = "4b4254325ecad416ab689e27ba51da03ba01a9632bc6e108f5fe7c3c4ad29d58" dependencies = [ "pest", "pest_generator", @@ -5956,26 +6194,24 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.15" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" +checksum = "6c4c0e91ead7a8f7acecbca6f003fc2e8282b1dbe2dd9c9d2f16aba42995e0a7" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "pest_meta" -version = "2.7.15" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" +checksum = "f9744bc48116fee06334924bb5f2bad41eed5e89bd26e29b0b799f9a3f82c210" dependencies = [ - "once_cell", "pest", - "sha2 0.10.8", ] [[package]] @@ -6034,7 +6270,7 @@ dependencies = [ "rsa", "sha1 0.10.6", "sha1-checked", - "sha2 0.10.8", + "sha2 0.10.9", "sha3", "signature", "smallvec", @@ -6200,7 +6436,7 @@ dependencies = [ "phf_shared 0.13.1", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6213,7 +6449,7 @@ dependencies = [ "phf_shared 0.14.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6240,7 +6476,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher 1.0.1", + "siphasher 1.0.3", ] [[package]] @@ -6249,7 +6485,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ - "siphasher 1.0.1", + "siphasher 1.0.3", ] [[package]] @@ -6258,7 +6494,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6fd9027e2d9319be6349febd1db4e8d02aa544921200c9b777720ac34a3aa89" dependencies = [ - "siphasher 1.0.1", + "siphasher 1.0.3", ] [[package]] @@ -6269,35 +6505,29 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project" -version = "1.1.8" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.8" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkcs1" @@ -6305,7 +6535,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der", + "der 0.7.10", "pkcs8", "spki", ] @@ -6316,15 +6546,15 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der", + "der 0.7.10", "spki", ] [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plain" @@ -6334,13 +6564,13 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "plist" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" +checksum = "7da1d65da6dd5d1e44199ac0f58712d241c0f439f80adea8924d832384087f85" dependencies = [ "base64 0.22.1", "indexmap 2.11.4", - "quick-xml", + "quick-xml 0.41.0", "serde", "time", ] @@ -6387,16 +6617,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", - "cpufeatures 0.2.16", + "cpufeatures 0.2.17", "opaque-debug", "universal-hash", ] +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] @@ -6409,9 +6654,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] @@ -6423,74 +6668,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] -name = "pretty_assertions" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" -dependencies = [ - "diff", - "yansi", -] - -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" -dependencies = [ - "toml_edit 0.20.7", -] - -[[package]] -name = "proc-macro-crate" -version = "3.2.0" +name = "pretty_assertions" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ - "toml_edit 0.22.24", + "diff", + "yansi", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "primeorder" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", + "elliptic-curve", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "proc-macro-crate" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "proc-macro2", - "quote", - "version_check", + "toml_edit 0.25.6+spec-1.1.0", ] [[package]] @@ -6516,43 +6718,42 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "version_check", "yansi", ] [[package]] name = "profiling" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" dependencies = [ "profiling-procmacros", ] [[package]] name = "profiling-procmacros" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "proptest" -version = "1.6.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ "bit-set", "bit-vec", "bitflags 2.13.0", - "lazy_static", "num-traits", - "rand 0.8.6", - "rand_chacha 0.3.1", + "rand 0.9.4", + "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", "rusty-fork", @@ -6609,33 +6810,42 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.32.0" +version = "0.39.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", ] [[package]] name = "quickcheck" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +checksum = "95c589f335db0f6aaa168a7cd27b1fc6920f5e1470c804f814d9cd6e62a0f70b" dependencies = [ - "env_logger 0.8.4", + "env_logger", "log", - "rand 0.8.6", + "rand 0.10.2", ] [[package]] name = "quickcheck_macros" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9" +checksum = "a9a28b8493dd664c8b171dd944da82d933f7d456b829bfb236738e1fe06c5ba4" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] @@ -6651,8 +6861,8 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.1", - "thiserror 2.0.12", + "socket2", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -6660,20 +6870,21 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.15" +version = "0.11.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" dependencies = [ "bytes", - "getrandom 0.3.4", + "getrandom 0.4.3", "lru-slab", - "rand 0.9.4", + "rand 0.10.2", + "rand_pcg 0.10.2", "ring", "rustc-hash", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.12", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -6681,16 +6892,16 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.1", + "socket2", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -6731,7 +6942,7 @@ dependencies = [ "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", - "rand_pcg", + "rand_pcg 0.2.1", ] [[package]] @@ -6752,7 +6963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -6793,7 +7004,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -6811,14 +7022,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] @@ -6847,13 +7058,22 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + [[package]] name = "rand_xorshift" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.9.5", ] [[package]] @@ -6891,7 +7111,7 @@ dependencies = [ "proc-macro2", "quote", "rayon", - "syn 2.0.117", + "syn 2.0.118", "uuid", ] @@ -6901,7 +7121,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" dependencies = [ - "aligned-vec 0.6.4", + "aligned-vec", "arbitrary", "arg_enum_proc_macro", "arrayvec", @@ -6925,7 +7145,7 @@ dependencies = [ "rand 0.9.4", "rand_chacha 0.9.0", "simd_helpers", - "thiserror 2.0.12", + "thiserror 2.0.18", "v_frame", "wasm-bindgen", ] @@ -6982,9 +7202,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags 2.13.0", ] @@ -6995,49 +7215,49 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.17", "libredox", "thiserror 1.0.69", ] [[package]] name = "redox_users" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.17", "libredox", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "ref-cast" -version = "1.0.23" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.23" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "referencing" -version = "0.46.9" +version = "0.46.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77954d81b2e1c5e8ab889f9f597a92f852ab073255de9e37ee3fb443efd57051" +checksum = "0fbf332a2f81899f6836f22c03da73dae8a664c32e3016b84692c23cddadc95d" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "fluent-uri", "getrandom 0.3.4", "hashbrown 0.16.1", @@ -7050,9 +7270,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -7062,9 +7282,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -7073,9 +7293,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rend" @@ -7110,7 +7330,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-native-certs 0.8.3", + "rustls-native-certs 0.8.4", "rustls-pki-types", "serde", "serde_json", @@ -7125,14 +7345,14 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 1.0.5", + "webpki-roots", ] [[package]] name = "reqwest" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64 0.22.1", "bytes", @@ -7152,7 +7372,7 @@ dependencies = [ "pin-project-lite", "rustls", "rustls-pki-types", - "rustls-platform-verifier", + "rustls-platform-verifier 0.7.0", "serde", "serde_json", "sync_wrapper", @@ -7232,7 +7452,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -7299,20 +7519,20 @@ dependencies = [ [[package]] name = "rpassword" -version = "7.4.0" +version = "7.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d4c8b64f049c6721ec8ccec37ddfc3d641c4a7fca57e8f2a89de509c73df39" +checksum = "2da316a15f47e3d053de9cb2c439650bd8fa4aaeb9365f2e5f27f492ff73c196" dependencies = [ "libc", "rtoolbox", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "rpm" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1630639f4dbc1c71ad7b704cda2171584c80735c502efae94804d02763fc6f7d" +checksum = "422ffe5b31ea4c7c76a361dc29b986e11fb6987313453088e1fd95f34ecc1ba6" dependencies = [ "bitflags 2.13.0", "bzip2", @@ -7332,8 +7552,8 @@ dependencies = [ "num-traits", "pgp", "sha1 0.10.6", - "sha2 0.10.8", - "thiserror 2.0.12", + "sha2 0.10.9", + "thiserror 2.0.18", "xz2", "zstd", ] @@ -7360,19 +7580,19 @@ dependencies = [ [[package]] name = "rtoolbox" -version = "0.0.2" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +checksum = "50a0e551c1e27e1731aba276dbeaeac73f53c7cd34d1bda485d02bd1e0f36844" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "rust_decimal" -version = "1.37.1" +version = "1.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50" +checksum = "be2a24f50780bc85f09cc6ac299bdf1424302742d77221106859c9d8b102126a" dependencies = [ "arrayvec", "borsh", @@ -7382,19 +7602,14 @@ dependencies = [ "rkyv", "serde", "serde_json", + "wasm-bindgen", ] -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc_version" @@ -7416,35 +7631,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" -dependencies = [ - "bitflags 2.13.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.0.7" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags 2.13.0", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "linux-raw-sys", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ "log", "once_cell", @@ -7461,7 +7663,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ - "openssl-probe 0.1.5", + "openssl-probe 0.1.6", "rustls-pemfile", "rustls-pki-types", "schannel", @@ -7470,14 +7672,14 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" dependencies = [ - "openssl-probe 0.2.0", + "openssl-probe 0.2.1", "rustls-pki-types", "schannel", - "security-framework 3.5.1", + "security-framework 3.7.0", ] [[package]] @@ -7491,9 +7693,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.2" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ "web-time", "zeroize", @@ -7505,16 +7707,37 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ - "core-foundation 0.10.0", + "core-foundation 0.10.1", + "core-foundation-sys", + "jni 0.21.1", + "log", + "once_cell", + "rustls", + "rustls-native-certs 0.8.4", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework 3.7.0", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation 0.10.1", "core-foundation-sys", - "jni", + "jni 0.22.4", "log", "once_cell", "rustls", - "rustls-native-certs 0.8.3", + "rustls-native-certs 0.8.4", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework 3.5.1", + "security-framework 3.7.0", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -7539,15 +7762,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "rusty-fork" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" dependencies = [ "fnv", "quick-error 1.2.3", @@ -7584,9 +7807,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "salsa20" @@ -7608,18 +7831,18 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "schemars" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" dependencies = [ "dyn-clone", "indexmap 1.9.3", @@ -7630,17 +7853,48 @@ dependencies = [ "uuid", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "schemars_derive" -version = "0.8.21" -source = "git+https://github.com/tauri-apps/schemars.git?branch=feat%2Fpreserve-description-newlines#c30f98480e6e4742aa72202d55d5264c6b2e6476" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.117", + "syn 2.0.118", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -7658,13 +7912,13 @@ dependencies = [ [[package]] name = "scroll_derive" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" +checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -7675,7 +7929,7 @@ checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" dependencies = [ "pbkdf2", "salsa20", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] @@ -7691,7 +7945,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", - "der", + "der 0.7.10", "generic-array", "pkcs8", "subtle", @@ -7713,12 +7967,12 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.5.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags 2.13.0", - "core-foundation 0.10.0", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -7726,9 +7980,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", @@ -7742,7 +7996,7 @@ checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" dependencies = [ "bitflags 1.3.2", "cssparser 0.29.6", - "derive_more 0.99.18", + "derive_more 0.99.20", "fxhash", "log", "phf 0.8.0", @@ -7760,7 +8014,26 @@ checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" dependencies = [ "bitflags 2.13.0", "cssparser 0.36.0", - "derive_more 2.0.1", + "derive_more 2.1.1", + "log", + "new_debug_unreachable", + "phf 0.13.1", + "phf_codegen 0.13.1", + "precomputed-hash", + "rustc-hash", + "servo_arc 0.4.3", + "smallvec", +] + +[[package]] +name = "selectors" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adfa1c298912827b8a28b223b3b874357397ae706e6190acd9bf28cee99114d" +dependencies = [ + "bitflags 2.13.0", + "cssparser 0.37.0", + "derive_more 2.1.1", "log", "new_debug_unreachable", "phf 0.13.1", @@ -7799,12 +8072,13 @@ dependencies = [ [[package]] name = "serde-untagged" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2676ba99bd82f75cae5cbd2c8eda6fa0b8760f18978ea840e980dd5567b5c5b6" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" dependencies = [ "erased-serde", "serde", + "serde_core", "typeid", ] @@ -7858,7 +8132,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -7869,67 +8143,68 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "serde_fmt" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d4ddca14104cd60529e8c7f7ba71a2c8acd8f7f5cfcdc2faf97eeb7c3010a4" +checksum = "6e497af288b3b95d067a23a4f749f2861121ffcb2f6d8379310dcda040c345ed" dependencies = [ - "serde", + "serde_core", ] [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "indexmap 2.11.4", "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] name = "serde_path_to_error" -version = "0.1.16" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", ] [[package]] name = "serde_repr" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ "serde_core", ] @@ -7948,17 +8223,19 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.12.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ "base64 0.22.1", + "bs58", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.11.4", - "serde", - "serde_derive", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -7966,14 +8243,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.12.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" dependencies = [ - "darling", + "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8011,7 +8288,7 @@ checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8033,7 +8310,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8062,7 +8339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures 0.2.16", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -8096,12 +8373,12 @@ checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures 0.2.16", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -8118,9 +8395,9 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" dependencies = [ "digest 0.10.7", "keccak", @@ -8145,15 +8422,15 @@ checksum = "52b86057fcb5423f5018e331ac04623e32d6b5ce85e33300f92c79a1973928b0" [[package]] name = "shell-words" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "sigchld" @@ -8178,9 +8455,9 @@ dependencies = [ [[package]] name = "signal-hook" -version = "0.4.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a37d01603c37b5466f808de79f845c7116049b0579adb70a6b7d47c1fa3a952" +checksum = "b2a0c28ca5908dbdbcd52e6fdaa00358ab88637f8ab33e1f188dd510eb44b53d" dependencies = [ "libc", "signal-hook-registry", @@ -8188,10 +8465,11 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -8203,7 +8481,7 @@ checksum = "e513e435a8898a0002270f29d0a708b7879708fb5c4d00e46983ca2d2d378cf0" dependencies = [ "futures-core", "libc", - "signal-hook 0.4.1", + "signal-hook 0.4.4", "tokio", ] @@ -8219,9 +8497,19 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.7" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] [[package]] name = "simd_helpers" @@ -8240,9 +8528,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "similar" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simple-file-manifest" @@ -8267,24 +8555,21 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "slotmap" -version = "1.0.7" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" dependencies = [ "version_check", ] @@ -8297,9 +8582,9 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "smawk" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" +checksum = "e8e2fb0f499abb4d162f2bedad68f5ef91a1682b5a03596ddb67efd37768d100" [[package]] name = "snafu" @@ -8316,30 +8601,20 @@ version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.117", -] - -[[package]] -name = "socket2" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" -dependencies = [ - "libc", - "windows-sys 0.52.0", + "syn 2.0.118", ] [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -8355,24 +8630,24 @@ dependencies = [ [[package]] name = "softbuffer" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" dependencies = [ "bytemuck", - "cfg_aliases", - "core-graphics 0.24.0", - "foreign-types 0.5.0", "js-sys", - "log", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", + "ndk", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "objc2-quartz-core", "raw-window-handle", "redox_syscall", + "tracing", "wasm-bindgen", "web-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -8393,9 +8668,9 @@ dependencies = [ [[package]] name = "soup3" -version = "0.5.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +checksum = "92d38b59ff6d302538efd337e15d04d61c5b909ec223c60ae4061d74605a962a" dependencies = [ "futures-channel", "gio", @@ -8406,9 +8681,9 @@ dependencies = [ [[package]] name = "soup3-sys" -version = "0.5.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +checksum = "79d5d25225bb06f83b78ff8cc35973b56d45fcdd21af6ed6d2bbd67f5a6f9bea" dependencies = [ "gio-sys", "glib-sys", @@ -8426,30 +8701,30 @@ dependencies = [ "curve25519-dalek", "hkdf", "rand_core 0.6.4", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] name = "specta" -version = "2.0.0-rc.20" +version = "2.0.0-rc.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ccbb212565d2dc177bc15ecb7b039d66c4490da892436a4eee5b394d620c9bc" +checksum = "38f9a30cbcbb7011f1da7d73483983bf838af123883e45f2b36ed76328df9c50" dependencies = [ "paste", + "rustc_version", "specta-macros", - "thiserror 1.0.69", ] [[package]] name = "specta-macros" -version = "2.0.0-rc.17" +version = "2.0.0-rc.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68999d29816965eb9e5201f60aec02a76512139811661a7e8e653abc810b8f72" +checksum = "2ce14957ecc2897f1f848b8255b6531d13ddf49cbcf506b7c2c9fb1d005593bb" dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8465,14 +8740,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der", + "der 0.7.10", ] [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -8503,14 +8778,13 @@ dependencies = [ [[package]] name = "string_cache" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" dependencies = [ "new_debug_unreachable", - "once_cell", "parking_lot", - "phf_shared 0.10.0", + "phf_shared 0.11.3", "precomputed-hash", "serde", ] @@ -8529,12 +8803,12 @@ dependencies = [ [[package]] name = "string_cache_codegen" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator 0.11.3", + "phf_shared 0.11.3", "proc-macro2", "quote", ] @@ -8551,6 +8825,12 @@ dependencies = [ "quote", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "strsim" version = "0.11.1" @@ -8572,10 +8852,10 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8592,15 +8872,15 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sval" -version = "2.13.2" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6dc0f9830c49db20e73273ffae9b5240f63c42e515af1da1fceefb69fceafd8" +checksum = "5fb9efbae90f97301f4d25f3be63dfd99d6b7af9d088228a52ec960d649b2e7d" [[package]] name = "sval_buffer" -version = "2.13.2" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "429922f7ad43c0ef8fd7309e14d750e38899e32eb7e8da656ea169dd28ee212f" +checksum = "ff5c0280ea0af40b3a1fd0b532680b5067482ffb81412ee66ec04b1d9952b49a" dependencies = [ "sval", "sval_ref", @@ -8608,18 +8888,18 @@ dependencies = [ [[package]] name = "sval_dynamic" -version = "2.13.2" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f16ff5d839396c11a30019b659b0976348f3803db0626f736764c473b50ff4" +checksum = "59b9067f2e68f58e110cf8019a268057e3791cf74b0fdb1b3c7c6e49104f44e6" dependencies = [ "sval", ] [[package]] name = "sval_fmt" -version = "2.13.2" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01c27a80b6151b0557f9ccbe89c11db571dc5f68113690c1e028d7e974bae94" +checksum = "96ebdbf0e4b175884aa587fcf551c16dabe245ea04235abdd8cbbd160b27ed5a" dependencies = [ "itoa", "ryu", @@ -8628,9 +8908,9 @@ dependencies = [ [[package]] name = "sval_json" -version = "2.13.2" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0deef63c70da622b2a8069d8600cf4b05396459e665862e7bdb290fd6cf3f155" +checksum = "1e448d9fa216a6c16670b28d624fbbcf5c04e41eb187bd7c52e01222ffa72a12" dependencies = [ "itoa", "ryu", @@ -8639,9 +8919,9 @@ dependencies = [ [[package]] name = "sval_nested" -version = "2.13.2" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a39ce5976ae1feb814c35d290cf7cf8cd4f045782fe1548d6bc32e21f6156e9f" +checksum = "021de5b5c26efd544c694cef9b8a9abe8633481bf3be1ea145a18a740818b291" dependencies = [ "sval", "sval_buffer", @@ -8650,20 +8930,20 @@ dependencies = [ [[package]] name = "sval_ref" -version = "2.13.2" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7c6ee3751795a728bc9316a092023529ffea1783499afbc5c66f5fabebb1fa" +checksum = "54ef5ffec8bc52ded04ee424ab8d959e25e64fd40a48a16d21f8991ce824c1bb" dependencies = [ "sval", ] [[package]] name = "sval_serde" -version = "2.13.2" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5572d0321b68109a343634e3a5d576bf131b82180c6c442dee06349dfc652a" +checksum = "b983833a8a2390f89ebcf9b9acd06883017014b4ffd72ee28e0c9de6852039f5" dependencies = [ - "serde", + "serde_core", "sval", "sval_nested", ] @@ -8675,7 +8955,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "695b5790b3131dafa99b3bbfd25a216edb3d216dad9ca208d4657bfb8f2abc3d" dependencies = [ "kurbo", - "siphasher 1.0.1", + "siphasher 1.0.3", ] [[package]] @@ -8702,9 +8982,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -8722,13 +9002,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8746,57 +9026,65 @@ dependencies = [ [[package]] name = "system-deps" -version = "6.2.2" +version = "7.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7" dependencies = [ "cfg-expr", - "heck 0.5.0", + "heck", "pkg-config", - "toml 0.8.20", + "toml 1.1.0+spec-1.1.0", "version-compare", ] [[package]] name = "tao" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cf65722394c2ac443e80120064987f8914ee1d4e4e36e63cdf10f2990f01159" +version = "0.35.3" dependencies = [ + "async-channel", "bitflags 2.13.0", - "block2 0.6.2", - "core-foundation 0.10.0", - "core-graphics 0.25.0", + "block2", + "core-foundation 0.10.1", + "core-graphics", "crossbeam-channel", "dbus", "dispatch2", "dlopen2", "dpi", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", - "jni", + "gdk4-wayland", + "gdk4-x11", + "gtk4", + "jni 0.21.1", "libc", "log", "ndk", "ndk-sys", - "objc2 0.6.4", + "objc2", "objc2-app-kit", - "objc2-foundation 0.3.0", + "objc2-foundation", "objc2-ui-kit", "once_cell", "parking_lot", "percent-encoding", "raw-window-handle", - "tao-macros", + "tao-macros 0.1.3", "unicode-segmentation", "url", - "windows 0.61.1", - "windows-core 0.61.0", + "windows", + "windows-core 0.61.2", "windows-version", "x11-dl", ] +[[package]] +name = "tao-macros" +version = "0.1.3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "tao-macros" version = "0.1.3" @@ -8805,7 +9093,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8827,9 +9115,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.16" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" [[package]] name = "tauri" @@ -8845,19 +9133,19 @@ dependencies = [ "embed_plist", "getrandom 0.3.4", "glob", - "gtk", - "heck 0.5.0", + "gtk4", + "heck", "http", "http-range", "image", - "jni", + "jni 0.21.1", "libc", "log", "mime", "muda", - "objc2 0.6.4", + "objc2", "objc2-app-kit", - "objc2-foundation 0.3.0", + "objc2-foundation", "objc2-ui-kit", "objc2-web-kit", "percent-encoding", @@ -8866,7 +9154,7 @@ dependencies = [ "quickcheck", "quickcheck_macros", "raw-window-handle", - "reqwest 0.13.3", + "reqwest 0.13.4", "rustls", "serde", "serde_json", @@ -8880,16 +9168,16 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.12", + "thiserror 2.0.18", "tokio", "tracing", "tray-icon", "url", "uuid", - "webkit2gtk", + "webkit6", "webview2-com", "window-vibrancy", - "windows 0.61.1", + "windows", ] [[package]] @@ -8900,10 +9188,10 @@ dependencies = [ "cargo_toml", "dirs 6.0.0", "glob", - "heck 0.5.0", + "heck", "json-patch", "quote", - "schemars", + "schemars 0.8.22", "semver", "serde", "serde_json", @@ -8925,7 +9213,7 @@ dependencies = [ "flate2", "glob", "handlebars", - "heck 0.5.0", + "heck", "hex", "image", "log", @@ -8940,13 +9228,13 @@ dependencies = [ "serde_json", "sha1 0.11.0", "sha2 0.11.0", - "strsim", + "strsim 0.11.1", "tar", "tauri-icns", "tauri-macos-sign", "tauri-utils", "tempfile", - "thiserror 2.0.12", + "thiserror 2.0.18", "time", "ureq", "url", @@ -8955,7 +9243,7 @@ dependencies = [ "which", "windows-registry", "windows-sys 0.61.2", - "zip 8.0.0", + "zip 8.6.0", ] [[package]] @@ -8966,7 +9254,7 @@ dependencies = [ "axum", "base64 0.22.1", "cargo-mobile2", - "clap", + "clap 4.6.1", "clap_complete", "colored 3.1.1", "common-path", @@ -8977,10 +9265,10 @@ dependencies = [ "duct", "dunce", "elf", - "env_logger 0.11.6", + "env_logger", "glob", "handlebars", - "heck 0.5.0", + "heck", "ignore", "image", "include_dir", @@ -9026,17 +9314,17 @@ dependencies = [ "tauri-macos-sign", "tauri-utils", "tempfile", - "thiserror 2.0.12", + "thiserror 2.0.18", "tokio", - "toml 1.0.6+spec-1.1.0", - "toml_edit 0.25.4+spec-1.1.0", + "toml 1.1.0+spec-1.1.0", + "toml_edit 0.25.6+spec-1.1.0", "ureq", "url", "uuid", "walkdir", "which", "windows-sys 0.61.2", - "zip 8.0.0", + "zip 8.6.0", ] [[package]] @@ -9065,10 +9353,10 @@ dependencies = [ "semver", "serde", "serde_json", - "sha2 0.10.8", - "syn 2.0.117", + "sha2 0.10.9", + "syn 2.0.118", "tauri-utils", - "thiserror 2.0.12", + "thiserror 2.0.18", "time", "url", "uuid", @@ -9088,7 +9376,7 @@ dependencies = [ "pico-args", "serde", "serde_json", - "signal-hook 0.4.1", + "signal-hook 0.4.4", "signal-hook-tokio", "tokio", "which", @@ -9134,7 +9422,7 @@ dependencies = [ "serde", "serde_json", "tempfile", - "thiserror 2.0.12", + "thiserror 2.0.18", "x509-certificate", ] @@ -9142,10 +9430,10 @@ dependencies = [ name = "tauri-macros" version = "2.6.3" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "tauri-codegen", "tauri-utils", ] @@ -9157,7 +9445,7 @@ dependencies = [ "anyhow", "glob", "plist", - "schemars", + "schemars 0.8.22", "serde", "serde_json", "tauri-utils", @@ -9166,23 +9454,23 @@ dependencies = [ [[package]] name = "tauri-plugin-log" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a59139183e0907cec1499dddee4e085f5a801dc659efa0848ee224f461371426" +checksum = "7545bd67f070a4500432c826e2e0682146a1d6712aee22a2786490156b574d93" dependencies = [ "android_logger", "byte-unit", "fern", "log", - "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2", + "objc2-foundation", "serde", "serde_json", "serde_repr", "swift-rs", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.18", "time", ] @@ -9194,7 +9482,7 @@ dependencies = [ "serde", "tauri", "tauri-plugin", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -9203,32 +9491,32 @@ version = "2.11.3" dependencies = [ "cookie", "dpi", - "gtk", + "gtk4", "http", - "jni", - "objc2 0.6.4", + "jni 0.21.1", + "objc2", "objc2-ui-kit", "objc2-web-kit", "raw-window-handle", "serde", "serde_json", "tauri-utils", - "thiserror 2.0.12", + "thiserror 2.0.18", "url", - "webkit2gtk", + "webkit6", "webview2-com", - "windows 0.61.1", + "windows", ] [[package]] name = "tauri-runtime-wry" version = "2.11.4" dependencies = [ - "gtk", + "gtk4", "http", - "jni", + "jni 0.21.1", "log", - "objc2 0.6.4", + "objc2", "objc2-app-kit", "once_cell", "percent-encoding", @@ -9239,9 +9527,9 @@ dependencies = [ "tauri-utils", "tracing", "url", - "webkit2gtk", + "webkit6", "webview2-com", - "windows 0.61.1", + "windows", "wry", ] @@ -9249,7 +9537,7 @@ dependencies = [ name = "tauri-schema-generator" version = "0.0.0" dependencies = [ - "schemars", + "schemars 0.8.22", "serde", "serde_json", "tauri-utils", @@ -9279,7 +9567,7 @@ dependencies = [ "brotli", "cargo_metadata", "ctor", - "dom_query", + "dom_query 0.27.0", "dunce", "getrandom 0.3.4", "glob", @@ -9296,7 +9584,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "schemars", + "schemars 0.8.22", "semver", "serde", "serde-untagged", @@ -9307,8 +9595,8 @@ dependencies = [ "swift-rs", "tauri", "tempfile", - "thiserror 2.0.12", - "toml 1.0.6+spec-1.1.0", + "thiserror 2.0.18", + "toml 1.1.0+spec-1.1.0", "url", "urlpattern", "uuid", @@ -9323,7 +9611,7 @@ checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" dependencies = [ "dunce", "embed-resource", - "toml 1.0.6+spec-1.1.0", + "toml 1.1.0+spec-1.1.0", ] [[package]] @@ -9339,16 +9627,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.15.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ - "cfg-if", "fastrand", - "getrandom 0.2.15", + "getrandom 0.4.3", "once_cell", - "rustix 0.38.43", - "windows-sys 0.59.0", + "rustix", + "windows-sys 0.61.2", ] [[package]] @@ -9364,12 +9651,11 @@ dependencies = [ [[package]] name = "tendril" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24" +checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" dependencies = [ "new_debug_unreachable", - "utf-8", ] [[package]] @@ -9378,10 +9664,19 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ - "rustix 1.0.7", + "rustix", "windows-sys 0.61.2", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width 0.1.14", +] + [[package]] name = "textwrap" version = "0.16.2" @@ -9391,7 +9686,7 @@ dependencies = [ "smawk", "terminal_size", "unicode-linebreak", - "unicode-width", + "unicode-width 0.2.2", ] [[package]] @@ -9405,11 +9700,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.18", ] [[package]] @@ -9420,18 +9715,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9450,9 +9745,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" dependencies = [ "deranged", "libc", @@ -9472,9 +9767,9 @@ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.30" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcef1a61bdb119096e153208ec5cbec23944ce8bca13be5c7f60c634f7403935" +checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" dependencies = [ "num-conv", "time-core", @@ -9508,9 +9803,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -9518,9 +9813,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -9533,31 +9828,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.1" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ - "backtrace", "bytes", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.8", + "socket2", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9572,9 +9866,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.1" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -9582,9 +9876,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -9594,21 +9888,21 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.26.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.26.2", + "tungstenite 0.29.0", ] [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -9620,119 +9914,104 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned 0.6.8", - "toml_datetime 0.6.8", - "toml_edit 0.22.24", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] name = "toml" -version = "1.0.6+spec-1.1.0" +version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399b1124a3c9e16766831c6bba21e50192572cdd98706ea114f9502509686ffc" +checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc" dependencies = [ "indexmap 2.11.4", "serde_core", - "serde_spanned 1.0.4", - "toml_datetime 1.0.0+spec-1.1.0", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 0.7.14", + "winnow 1.0.3", ] [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_datetime" -version = "1.0.0+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.11.4", - "toml_datetime 0.6.8", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.11.4", - "toml_datetime 0.6.8", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.24" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.11.4", "serde", - "serde_spanned 0.6.8", - "toml_datetime 0.6.8", - "winnow 0.7.14", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", ] [[package]] name = "toml_edit" -version = "0.25.4+spec-1.1.0" +version = "0.25.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" +checksum = "0db3bae107c9522f86d361697dee1d7386a2ddcf659d5aea5159819a21a3c4a7" dependencies = [ "indexmap 2.11.4", "serde_core", - "serde_spanned 1.0.4", - "toml_datetime 1.0.0+spec-1.1.0", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 0.7.14", + "winnow 1.0.3", ] [[package]] name = "toml_parser" -version = "1.0.9+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow 0.7.14", + "winnow 1.0.3", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -9746,20 +10025,20 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "bitflags 2.13.0", "bytes", "futures-util", "http", "http-body", - "iri-string", "pin-project-lite", "tower", "tower-layer", "tower-service", + "url", ] [[package]] @@ -9776,9 +10055,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -9788,43 +10067,42 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", ] [[package]] name = "tray-icon" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e47e6d063cfe4ad2e416fcbb310be3a37c5fd85c745b62cb562bfa4a003df674" +version = "0.24.1" dependencies = [ + "arc-swap", "crossbeam-channel", "dirs 6.0.0", - "libappindicator", + "ksni", "muda", - "objc2 0.6.4", + "objc2", "objc2-app-kit", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation 0.3.0", + "objc2-foundation", "once_cell", "png 0.18.1", "serde", - "thiserror 2.0.12", + "thiserror 2.0.18", "windows-sys 0.61.2", ] @@ -9866,9 +10144,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.26.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", @@ -9877,8 +10155,7 @@ dependencies = [ "log", "rand 0.9.4", "sha1 0.10.6", - "thiserror 2.0.12", - "utf-8", + "thiserror 2.0.18", ] [[package]] @@ -9908,21 +10185,21 @@ checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" [[package]] name = "typeid" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "typewit" -version = "1.11.0" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb77c29baba9e4d3a6182d51fa75e3215c7fd1dab8f4ea9d107c716878e55fc0" +checksum = "214ca0b2191785cbc06209b9ca1861e048e39b5ba33574b3cedd58363d5bb5f6" dependencies = [ "typewit_proc_macros", ] @@ -9989,15 +10266,15 @@ checksum = "0b993bddc193ae5bd0d623b49ec06ac3e9312875fdae725a975c51db1cc1677f" [[package]] name = "unicode-id-start" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f322b60f6b9736017344fa0635d64be2f458fbc04eef65f6be22976dd1ffd5b" +checksum = "81b79ad29b5e19de4260020f8919b443b2ef0277d242ce532ec7b7a2cc8b6007" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-linebreak" @@ -10007,21 +10284,21 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-script" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" +checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-vo" @@ -10031,9 +10308,15 @@ checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" @@ -10047,7 +10330,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common 0.1.6", + "crypto-common 0.1.7", "subtle", ] @@ -10065,31 +10348,31 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "3.1.4" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a" +checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" dependencies = [ "base64 0.22.1", - "der", + "der 0.8.0", "flate2", "log", "native-tls", "percent-encoding", "rustls", "rustls-pki-types", - "rustls-platform-verifier", + "rustls-platform-verifier 0.6.2", "socks", "ureq-proto", - "utf-8", + "utf8-zero", "webpki-root-certs", - "webpki-roots 1.0.5", + "webpki-roots", ] [[package]] name = "ureq-proto" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f" +checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" dependencies = [ "base64 0.22.1", "http", @@ -10139,7 +10422,7 @@ dependencies = [ "roxmltree 0.21.1", "rustybuzz", "simplecss", - "siphasher 1.0.1", + "siphasher 1.0.3", "strict-num", "svgtypes", "tiny-skia-path", @@ -10158,9 +10441,15 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "utf8-width" -version = "0.1.7" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "159a7cadce548703edd50d24069bc294c5415ecab0a480e0cd1ca06d112dc94a" + +[[package]] +name = "utf8-zero" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" [[package]] name = "utf8_iter" @@ -10176,13 +10465,15 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.11.0" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ - "getrandom 0.2.15", - "serde", + "getrandom 0.4.3", + "js-sys", + "serde_core", "sha1_smol", + "wasm-bindgen", ] [[package]] @@ -10197,11 +10488,11 @@ dependencies = [ [[package]] name = "v_frame" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" dependencies = [ - "aligned-vec 0.5.0", + "aligned-vec", "num-traits", "wasm-bindgen", ] @@ -10248,11 +10539,17 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version-compare" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" [[package]] name = "version_check" @@ -10284,9 +10581,9 @@ dependencies = [ [[package]] name = "vswhom-sys" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" dependencies = [ "cc", "libc", @@ -10294,9 +10591,9 @@ dependencies = [ [[package]] name = "wait-timeout" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ "libc", ] @@ -10328,9 +10625,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" @@ -10343,9 +10640,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -10356,9 +10653,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.75" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ "js-sys", "wasm-bindgen", @@ -10366,9 +10663,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10376,22 +10673,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] @@ -10422,11 +10719,71 @@ dependencies = [ "web-sys", ] +[[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", + "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.13.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" +dependencies = [ + "bitflags 2.13.0", + "wayland-backend", + "wayland-client", + "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.4", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + [[package]] name = "web-sys" -version = "0.3.102" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -10444,9 +10801,9 @@ dependencies = [ [[package]] name = "web_atoms" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a9779e9f04d2ac1ce317aee707aa2f6b773afba7b931222bff6983843b1576" +checksum = "075474b12bcb3d2e3d4546580e9de478eeeead668a1761e2a8860c836b7ef297" dependencies = [ "phf 0.13.1", "phf_codegen 0.13.1", @@ -10455,110 +10812,90 @@ dependencies = [ ] [[package]] -name = "webkit2gtk" -version = "2.0.2" +name = "webkit6" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" +checksum = "4959dd2a92813d4b2ae134e71345a03030bcff189b4f79cd131e9218aba22b70" dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "gdk", - "gdk-sys", + "gdk4", "gio", - "gio-sys", "glib", - "glib-sys", - "gobject-sys", - "gtk", - "gtk-sys", - "javascriptcore-rs", + "gtk4", + "javascriptcore6", "libc", - "once_cell", "soup3", - "webkit2gtk-sys", + "webkit6-sys", ] [[package]] -name = "webkit2gtk-sys" -version = "2.0.2" +name = "webkit6-sys" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" +checksum = "236078ce03ff041bf87904c8257e6a9b0e9e0f957267c15f9c1756aadcf02581" dependencies = [ - "bitflags 1.3.2", - "cairo-sys-rs", - "gdk-sys", + "gdk4-sys", "gio-sys", "glib-sys", "gobject-sys", - "gtk-sys", - "javascriptcore-rs-sys", + "gtk4-sys", + "javascriptcore6-sys", "libc", - "pkg-config", "soup3-sys", "system-deps", ] [[package]] name = "webpki-root-certs" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" +checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.5", -] - -[[package]] -name = "webpki-roots" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" dependencies = [ "rustls-pki-types", ] [[package]] name = "webview2-com" -version = "0.38.0" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows 0.61.1", - "windows-core 0.61.0", + "windows", + "windows-core 0.61.2", "windows-implement", "windows-interface", ] [[package]] name = "webview2-com-macros" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "webview2-com-sys" -version = "0.38.0" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" +checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" dependencies = [ - "thiserror 2.0.12", - "windows 0.61.1", - "windows-core 0.61.0", + "thiserror 2.0.18", + "windows", + "windows-core 0.61.2", ] [[package]] @@ -10569,29 +10906,27 @@ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "which" -version = "8.0.0" +version = "8.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d" +checksum = "48d7cd18d4acb58fb3cdfe9ea54e6cd96a4e7d4cc45c56338b236e82dad47248" dependencies = [ - "env_home", - "rustix 1.0.7", - "winsafe", + "libc", ] [[package]] name = "widestring" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" [[package]] name = "win32job" -version = "2.0.0" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b2b1bf557d947847a30eb73f79aa6cdb3eaf3ce02f5e9599438f77896a62b3c" +checksum = "8c6a6724ccfbf34154a8691bd868b0fcd2be2ca3f7b47b32614654f1a01b191c" dependencies = [ "thiserror 1.0.69", - "windows 0.52.0", + "windows", ] [[package]] @@ -10612,11 +10947,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -10631,10 +10966,10 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" dependencies = [ - "objc2 0.6.4", + "objc2", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation", "raw-window-handle", "windows-sys 0.59.0", "windows-version", @@ -10642,24 +10977,14 @@ dependencies = [ [[package]] name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core 0.52.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.61.1" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", - "windows-core 0.61.0", + "windows-core 0.61.2", "windows-future", - "windows-link 0.1.1", + "windows-link 0.1.3", "windows-numerics", ] @@ -10669,68 +10994,73 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.61.0", + "windows-core 0.61.2", ] [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] name = "windows-core" -version = "0.61.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.1.1", - "windows-result 0.3.2", - "windows-strings 0.4.0", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] name = "windows-future" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core 0.61.0", - "windows-link 0.1.1", + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-link" @@ -10744,8 +11074,8 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.61.0", - "windows-link 0.1.1", + "windows-core 0.61.2", + "windows-link 0.1.3", ] [[package]] @@ -10761,11 +11091,11 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link 0.1.1", + "windows-link 0.1.3", ] [[package]] @@ -10779,11 +11109,11 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link 0.1.1", + "windows-link 0.1.3", ] [[package]] @@ -10837,7 +11167,7 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.2", + "windows-targets 0.53.5", ] [[package]] @@ -10897,27 +11227,37 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.2" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "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-version" -version = "0.1.2" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c12476c23a74725c539b24eae8bfc0dac4029c39cdb561d9f23616accd4ae26d" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" dependencies = [ - "windows-targets 0.53.2", + "windows-link 0.2.1", ] [[package]] @@ -10940,9 +11280,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -10964,9 +11304,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -10988,9 +11328,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -11000,9 +11340,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -11024,9 +11364,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -11048,9 +11388,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -11072,9 +11412,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -11096,24 +11436,24 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.5.40" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr", ] [[package]] name = "winnow" -version = "0.7.14" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" dependencies = [ "memchr", ] @@ -11128,12 +11468,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "winsafe" -version = "0.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" - [[package]] name = "wit-bindgen" version = "0.57.1" @@ -11182,7 +11516,7 @@ dependencies = [ "proc-macro2", "quote", "strum", - "syn 2.0.117", + "syn 2.0.118", "wasm-bindgen", "wasm-bindgen-macro-support", "worker-sys", @@ -11208,47 +11542,41 @@ checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "wry" -version = "0.55.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3013fd6116aac351dd2e18f349b28b2cfef3a5ff3253a9d0ce2d7193bb1b4429" +version = "0.55.1" dependencies = [ "base64 0.22.1", - "block2 0.6.2", + "block2", "cookie", "crossbeam-channel", "dirs 6.0.0", - "dom_query", + "dom_query 0.28.0", "dpi", "dunce", - "gdkx11", - "gtk", + "gtk4", "http", - "javascriptcore-rs", - "jni", + "jni 0.21.1", "libc", "ndk", - "objc2 0.6.4", + "objc2", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation", "objc2-ui-kit", "objc2-web-kit", "once_cell", "percent-encoding", "raw-window-handle", - "sha2 0.10.8", + "sha2 0.10.9", "soup3", - "tao-macros", - "thiserror 2.0.12", + "tao-macros 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.18", "tracing", "url", - "webkit2gtk", - "webkit2gtk-sys", + "webkit6", "webview2-com", - "windows 0.61.1", - "windows-core 0.61.0", + "windows", + "windows-core 0.61.2", "windows-version", - "x11-dl", ] [[package]] @@ -11260,16 +11588,6 @@ dependencies = [ "tap", ] -[[package]] -name = "x11" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" -dependencies = [ - "libc", - "pkg-config", -] - [[package]] name = "x11-dl" version = "2.21.0" @@ -11323,7 +11641,7 @@ dependencies = [ "bcder", "bytes", "chrono", - "der", + "der 0.7.10", "hex", "pem", "ring", @@ -11335,20 +11653,19 @@ dependencies = [ [[package]] name = "xattr" -version = "1.4.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "linux-raw-sys 0.4.15", - "rustix 0.38.43", + "rustix", ] [[package]] name = "xml-rs" -version = "0.8.25" +version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" [[package]] name = "xmlwriter" @@ -11385,9 +11702,9 @@ checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -11402,77 +11719,76 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -11481,9 +11797,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -11498,7 +11814,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -11514,15 +11830,15 @@ dependencies = [ "flate2", "indexmap 2.11.4", "memchr", - "thiserror 2.0.12", + "thiserror 2.0.18", "zopfli", ] [[package]] name = "zip" -version = "8.0.0" +version = "8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b32dd4ad3aca14ae109f8cce0495ac1c57f6f4f00ad459a40e582f89440d97" +checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" dependencies = [ "crc32fast", "flate2", @@ -11545,47 +11861,51 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.5.0" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8" +checksum = "5431d5661c32445236631278f27946e444ddafe4684cac70b185272d4f9c52d5" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "zopfli" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" dependencies = [ "bumpalo", "crc32fast", - "lockfree-object-pool", "log", - "once_cell", "simd-adler32", ] [[package]] name = "zstd" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.2.1" +version = "7.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ "cc", "pkg-config", @@ -11614,3 +11934,8 @@ checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" dependencies = [ "zune-core", ] + +[[patch.unused]] +name = "schemars_derive" +version = "0.8.21" +source = "git+https://github.com/tauri-apps/schemars.git?branch=feat%2Fpreserve-description-newlines#c30f98480e6e4742aa72202d55d5264c6b2e6476" diff --git a/Cargo.toml b/Cargo.toml index 3bf88a350845..85dae9c32460 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ members = [ "examples/api/src-tauri", "examples/api/src-tauri/tauri-plugin-sample", ] +exclude = ["ports/muda", "ports/tao", "ports/tray-icon", "ports/wry"] resolver = "2" [workspace.package] @@ -68,7 +69,11 @@ opt-level = "s" # Temporary patch to schemars to preserve newlines in docstrings for our reference docs schemas # See https://github.com/GREsau/schemars/issues/120 for reference [patch.crates-io] +muda = { path = "./ports/muda" } schemars_derive = { git = 'https://github.com/tauri-apps/schemars.git', branch = 'feat/preserve-description-newlines' } +tao = { path = "./ports/tao" } tauri = { path = "./crates/tauri" } tauri-plugin = { path = "./crates/tauri-plugin" } tauri-utils = { path = "./crates/tauri-utils" } +tray-icon = { path = "./ports/tray-icon" } +wry = { path = "./ports/wry" } diff --git a/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gtk.sh b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gtk.sh index 65ead4b7313f..eec65b5932f6 100644 --- a/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gtk.sh +++ b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gtk.sh @@ -87,7 +87,7 @@ search_tool() { } #DEPLOY_GTK_VERSION="${DEPLOY_GTK_VERSION:-0}" # When not set by user, this variable use the integer '0' as a sentinel value -DEPLOY_GTK_VERSION=3 # Force GTK3 for tauri apps +DEPLOY_GTK_VERSION=4 # Force GTK4 for tauri apps APPDIR= while [ "$1" != "" ]; do @@ -324,4 +324,3 @@ EOF #binary patch absolute paths in libwebkit files find "$APPDIR"/usr/lib* -name 'libwebkit*' -exec sed -i -e "s|/usr|././|g" '{}' \; - diff --git a/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs index 87364eb0cd41..99bb57895df7 100644 --- a/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs +++ b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs @@ -149,11 +149,11 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { for file in [ "WebKitNetworkProcess", "WebKitWebProcess", - "injected-bundle/libwebkit2gtkinjectedbundle.so", + "injected-bundle/libwebkitgtkinjectedbundle.so", ] { for source in search_dirs.map(PathBuf::from) { // TODO: Check if it's the same dir name on all systems - let source = source.join("webkit2gtk-4.1").join(file); + let source = source.join("webkitgtk-6.0").join(file); if source.exists() { fs_utils::copy_file( &source, diff --git a/crates/tauri-cli/src/info/env_system.rs b/crates/tauri-cli/src/info/env_system.rs index fb429c0db8f5..a5a1cdc3b429 100644 --- a/crates/tauri-cli/src/info/env_system.rs +++ b/crates/tauri-cli/src/info/env_system.rs @@ -167,8 +167,8 @@ fn pkg_conf_version(package: &str) -> Option { target_os = "openbsd", target_os = "netbsd" ))] -fn webkit2gtk_ver() -> Option { - pkg_conf_version("webkit2gtk-4.1") +fn webkitgtk_ver() -> Option { + pkg_conf_version("webkitgtk-6.0") } #[cfg(any( target_os = "linux", @@ -294,12 +294,12 @@ pub fn items() -> Vec { target_os = "netbsd" ))] SectionItem::new().action(|| { - webkit2gtk_ver() - .map(|v| (format!("webkit2gtk-4.1: {v}"), Status::Success)) + webkitgtk_ver() + .map(|v| (format!("webkitgtk-6.0: {v}"), Status::Success)) .unwrap_or_else(|| { ( format!( - "webkit2gtk-4.1: {}\nVisit {} to learn more about tauri prerequisites", + "webkitgtk-6.0: {}\nVisit {} to learn more about tauri prerequisites", "not installed".red(), "https://v2.tauri.app/start/prerequisites/".cyan() ), diff --git a/crates/tauri-cli/src/interface/rust.rs b/crates/tauri-cli/src/interface/rust.rs index 78fc38f8476a..669d839e97fa 100644 --- a/crates/tauri-cli/src/interface/rust.rs +++ b/crates/tauri-cli/src/interface/rust.rs @@ -46,6 +46,27 @@ use crate::helpers::config::custom_sign_settings; use cargo_config::Config as CargoConfig; use manifest::{rewrite_manifest, Manifest}; +#[cfg(any(target_os = "linux", test))] +const LINUX_DEB_RUNTIME_DEPENDENCIES: &[&str] = + &["libwebkitgtk-6.0-4", "libgtk-4-1", "libdbus-1-3"]; +#[cfg(any(target_os = "linux", test))] +const LINUX_RPM_RUNTIME_LIBRARIES: &[&str] = + &["libwebkitgtk-6.0.so.4", "libgtk-4.so.1", "libdbus-1.so.3"]; + +#[cfg(any(target_os = "linux", test))] +fn linux_rpm_runtime_dependencies(arch64bits: bool) -> Vec { + LINUX_RPM_RUNTIME_LIBRARIES + .iter() + .map(|lib| { + let mut requires = (*lib).to_string(); + if arch64bits { + requires.push_str("()(64bit)"); + } + requires + }) + .collect() +} + #[derive(Debug, Default, Clone)] pub struct Options { pub runner: Option, @@ -1371,12 +1392,6 @@ fn tauri_config_to_bundle_settings( updater_config: Option, arch64bits: bool, ) -> crate::Result { - let enabled_features = settings - .manifest - .lock() - .unwrap() - .all_enabled_features(features); - #[allow(unused_mut)] let mut resources = config .resources @@ -1393,66 +1408,12 @@ fn tauri_config_to_bundle_settings( // set env vars used by the bundler and inject dependencies #[cfg(target_os = "linux")] { - let mut libs: Vec = Vec::new(); - - if enabled_features.contains(&"tray-icon".into()) - || enabled_features.contains(&"tauri/tray-icon".into()) - { - let (tray_kind, path) = std::env::var_os("TAURI_LINUX_AYATANA_APPINDICATOR") - .map(|ayatana| { - if ayatana == "true" || ayatana == "1" { - ( - pkgconfig_utils::TrayKind::Ayatana, - format!( - "{}/libayatana-appindicator3.so.1", - pkgconfig_utils::get_library_path("ayatana-appindicator3-0.1") - .expect("failed to get ayatana-appindicator library path using pkg-config.") - ), - ) - } else { - ( - pkgconfig_utils::TrayKind::Libappindicator, - format!( - "{}/libappindicator3.so.1", - pkgconfig_utils::get_library_path("appindicator3-0.1") - .expect("failed to get libappindicator-gtk library path using pkg-config.") - ), - ) - } - }) - .unwrap_or_else(pkgconfig_utils::get_appindicator_library_path); - match tray_kind { - pkgconfig_utils::TrayKind::Ayatana => { - depends_deb.push("libayatana-appindicator3-1".into()); - libs.push("libayatana-appindicator3.so.1".into()); - } - pkgconfig_utils::TrayKind::Libappindicator => { - depends_deb.push("libappindicator3-1".into()); - libs.push("libappindicator3.so.1".into()); - } - } - - // conditionally setting it in case the user provided its own version for some reason - let path = PathBuf::from(path); - if !appimage_files.contains_key(&path) { - // manually construct target path, just in case the source path is something unexpected - appimage_files.insert(Path::new("/usr/lib/").join(path.file_name().unwrap()), path); - } - } - - depends_deb.push("libwebkit2gtk-4.1-0".to_string()); - depends_deb.push("libgtk-3-0".to_string()); - - libs.push("libwebkit2gtk-4.1.so.0".into()); - libs.push("libgtk-3.so.0".into()); - - for lib in libs { - let mut requires = lib; - if arch64bits { - requires.push_str("()(64bit)"); - } - depends_rpm.push(requires); - } + depends_deb.extend( + LINUX_DEB_RUNTIME_DEPENDENCIES + .iter() + .map(|dependency| (*dependency).to_string()), + ); + depends_rpm.extend(linux_rpm_runtime_dependencies(arch64bits)); } #[cfg(windows)] @@ -1700,51 +1661,6 @@ fn tauri_config_to_bundle_settings( }) } -#[cfg(target_os = "linux")] -mod pkgconfig_utils { - use std::process::Command; - - pub enum TrayKind { - Ayatana, - Libappindicator, - } - - pub fn get_appindicator_library_path() -> (TrayKind, String) { - match get_library_path("ayatana-appindicator3-0.1") { - Some(p) => ( - TrayKind::Ayatana, - format!("{p}/libayatana-appindicator3.so.1"), - ), - None => match get_library_path("appindicator3-0.1") { - Some(p) => ( - TrayKind::Libappindicator, - format!("{p}/libappindicator3.so.1"), - ), - None => panic!("Can't detect any appindicator library"), - }, - } - } - - /// Gets the folder in which a library is located using `pkg-config`. - pub fn get_library_path(name: &str) -> Option { - let mut cmd = Command::new("pkg-config"); - cmd.env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1"); - cmd.arg("--libs-only-L"); - cmd.arg(name); - if let Ok(output) = cmd.output() { - if !output.stdout.is_empty() { - // output would be "-L/path/to/library\n" - let word = output.stdout[2..].to_vec(); - Some(String::from_utf8_lossy(&word).trim().to_string()) - } else { - None - } - } else { - None - } - } -} - #[cfg(test)] mod tests { use super::*; @@ -1806,6 +1722,40 @@ mod tests { assert_eq!(get_cargo_option(&args, "--non-existent"), None); } + #[test] + fn linux_deb_runtime_dependencies_use_gtk4_webkitgtk6_and_ksni() { + assert_eq!( + LINUX_DEB_RUNTIME_DEPENDENCIES, + &["libwebkitgtk-6.0-4", "libgtk-4-1", "libdbus-1-3"] + ); + assert!(!LINUX_DEB_RUNTIME_DEPENDENCIES + .iter() + .any(|dependency| dependency.contains("webkit2gtk") + || dependency.contains("gtk-3") + || dependency.contains("appindicator"))); + } + + #[test] + fn linux_rpm_runtime_dependencies_use_gtk4_webkitgtk6_and_ksni() { + assert_eq!( + linux_rpm_runtime_dependencies(false), + ["libwebkitgtk-6.0.so.4", "libgtk-4.so.1", "libdbus-1.so.3"] + ); + assert_eq!( + linux_rpm_runtime_dependencies(true), + [ + "libwebkitgtk-6.0.so.4()(64bit)", + "libgtk-4.so.1()(64bit)", + "libdbus-1.so.3()(64bit)" + ] + ); + assert!(!LINUX_RPM_RUNTIME_LIBRARIES + .iter() + .any(|library| library.contains("webkit2gtk") + || library.contains("gtk-3") + || library.contains("appindicator"))); + } + #[test] fn get_binaries_ignores_src_bin_with_disabled_required_features() { let cargo_toml = r#" diff --git a/crates/tauri-cli/src/interface/rust/manifest.rs b/crates/tauri-cli/src/interface/rust/manifest.rs index 40d307c2bcf3..ab50d99e9c36 100644 --- a/crates/tauri-cli/src/interface/rust/manifest.rs +++ b/crates/tauri-cli/src/interface/rust/manifest.rs @@ -18,7 +18,6 @@ use std::{ #[derive(Default)] pub struct Manifest { pub inner: DocumentMut, - pub tauri_features: HashSet, } impl Manifest { @@ -46,37 +45,6 @@ impl Manifest { f } - - pub fn all_enabled_features(&self, enabled_features: &[String]) -> Vec { - let mut all_enabled_features: Vec = self - .tauri_features - .iter() - .map(|f| format!("tauri/{f}")) - .collect(); - - let manifest_features = self.features(); - for f in enabled_features { - all_enabled_features.extend(get_enabled_features(&manifest_features, f)); - } - - all_enabled_features - } -} - -fn get_enabled_features(list: &HashMap>, feature: &str) -> Vec { - let mut f = Vec::new(); - - if let Some(enabled_features) = list.get(feature) { - for enabled in enabled_features { - if list.contains_key(enabled) { - f.extend(get_enabled_features(list, enabled)); - } else { - f.push(enabled.clone()); - } - } - } - - f } pub fn read_manifest(manifest_path: &Path) -> crate::Result<(DocumentMut, String)> { @@ -301,32 +269,14 @@ pub fn rewrite_manifest(config: &Config, tauri_dir: &Path) -> crate::Result<(Man let persist = inject_features(&mut manifest, &mut dependencies)?; - let tauri_features = dependencies - .into_iter() - .find(|d| d.name == "tauri") - .unwrap() - .features; - let new_manifest_str = serialize_manifest(&manifest); if persist && original_manifest_str != new_manifest_str { std::fs::write(&manifest_path, new_manifest_str) .fs_context("failed to rewrite Cargo manifest", &manifest_path)?; - Ok(( - Manifest { - inner: manifest, - tauri_features, - }, - true, - )) + Ok((Manifest { inner: manifest }, true)) } else { - Ok(( - Manifest { - inner: manifest, - tauri_features, - }, - false, - )) + Ok((Manifest { inner: manifest }, false)) } } diff --git a/crates/tauri-runtime-wry/Cargo.toml b/crates/tauri-runtime-wry/Cargo.toml index 7c576dea5ec2..b4600a86f4cd 100644 --- a/crates/tauri-runtime-wry/Cargo.toml +++ b/crates/tauri-runtime-wry/Cargo.toml @@ -37,8 +37,8 @@ version = "0.61" features = ["Win32_Foundation", "Win32_Graphics_Dwm"] [target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] -gtk = { version = "0.18", features = ["v3_24"] } -webkit2gtk = { version = "=2.0", features = ["v2_40"] } +gtk = { package = "gtk4", version = "0.11", features = ["v4_10"] } +webkit = { package = "webkit6", version = "0.6", features = ["v2_42"] } percent-encoding = "2" [target.'cfg(target_vendor = "apple")'.dependencies] diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 7e3fbbae8a31..3fa6c211aacf 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -33,6 +33,14 @@ use tauri_runtime::{ UserAttentionType, UserEvent, WebviewDispatch, WebviewEventId, WindowDispatch, WindowEventId, }; +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +use gtk::glib::object::Cast; #[cfg(target_vendor = "apple")] use objc2::rc::Retained; #[cfg(target_os = "android")] @@ -1089,7 +1097,7 @@ impl WindowBuilder for WindowBuilderWrapper { target_os = "netbsd", target_os = "openbsd" ))] - fn transient_for(mut self, parent: &impl gtk::glib::IsA) -> Self { + fn transient_for(mut self, parent: &impl gtk::glib::object::IsA) -> Self { self.inner = self.inner.with_transient_for(parent); self } @@ -3328,7 +3336,9 @@ fn handle_user_message( target_os = "netbsd", target_os = "openbsd" ))] - WindowMessage::GtkWindow(tx) => tx.send(GtkWindow(window.gtk_window().clone())).unwrap(), + WindowMessage::GtkWindow(tx) => tx + .send(GtkWindow(window.gtk_window().clone().into())) + .unwrap(), #[cfg(any( target_os = "linux", target_os = "dragonfly", @@ -4564,7 +4574,7 @@ fn create_window( target_os = "netbsd", target_os = "openbsd" ))] - gtk_window: window.gtk_window(), + gtk_window: window.gtk_window().upcast_ref(), #[cfg(any( target_os = "linux", target_os = "dragonfly", diff --git a/crates/tauri-runtime-wry/src/monitor/linux.rs b/crates/tauri-runtime-wry/src/monitor/linux.rs index 62f87eb05c03..7b1d3df76686 100644 --- a/crates/tauri-runtime-wry/src/monitor/linux.rs +++ b/crates/tauri-runtime-wry/src/monitor/linux.rs @@ -2,13 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use gtk::prelude::MonitorExt; +use gtk::gdk::prelude::MonitorExt; use tao::platform::unix::MonitorHandleExtUnix; use tauri_runtime::dpi::{LogicalPosition, LogicalSize, PhysicalRect}; impl super::MonitorExt for tao::monitor::MonitorHandle { fn work_area(&self) -> PhysicalRect { - let rect = self.gdk_monitor().workarea(); + let rect = self.gdk_monitor().geometry(); let scale_factor = self.scale_factor(); PhysicalRect { size: LogicalSize::new(rect.width() as u32, rect.height() as u32).to_physical(scale_factor), diff --git a/crates/tauri-runtime-wry/src/undecorated_resizing.rs b/crates/tauri-runtime-wry/src/undecorated_resizing.rs index 7a1dad6ff5c9..de392e53de32 100644 --- a/crates/tauri-runtime-wry/src/undecorated_resizing.rs +++ b/crates/tauri-runtime-wry/src/undecorated_resizing.rs @@ -506,123 +506,83 @@ mod gtk { const BORDERLESS_RESIZE_INSET: i32 = 5; impl HitTestResult { - fn to_gtk_edge(self) -> gtk::gdk::WindowEdge { + fn to_gtk_edge(self) -> gtk::gdk::SurfaceEdge { match self { - HitTestResult::Client | HitTestResult::NoWhere => gtk::gdk::WindowEdge::__Unknown(0), - HitTestResult::Left => gtk::gdk::WindowEdge::West, - HitTestResult::Right => gtk::gdk::WindowEdge::East, - HitTestResult::Top => gtk::gdk::WindowEdge::North, - HitTestResult::Bottom => gtk::gdk::WindowEdge::South, - HitTestResult::TopLeft => gtk::gdk::WindowEdge::NorthWest, - HitTestResult::TopRight => gtk::gdk::WindowEdge::NorthEast, - HitTestResult::BottomLeft => gtk::gdk::WindowEdge::SouthWest, - HitTestResult::BottomRight => gtk::gdk::WindowEdge::SouthEast, + HitTestResult::Client | HitTestResult::NoWhere => gtk::gdk::SurfaceEdge::__Unknown(8), + HitTestResult::Left => gtk::gdk::SurfaceEdge::West, + HitTestResult::Right => gtk::gdk::SurfaceEdge::East, + HitTestResult::Top => gtk::gdk::SurfaceEdge::North, + HitTestResult::Bottom => gtk::gdk::SurfaceEdge::South, + HitTestResult::TopLeft => gtk::gdk::SurfaceEdge::NorthWest, + HitTestResult::TopRight => gtk::gdk::SurfaceEdge::NorthEast, + HitTestResult::BottomLeft => gtk::gdk::SurfaceEdge::SouthWest, + HitTestResult::BottomRight => gtk::gdk::SurfaceEdge::SouthEast, } } } pub fn attach_resize_handler(webview: &wry::WebView) { use gtk::{ - gdk::{prelude::*, WindowEdge}, - glib::Propagation, + gdk::{self, SurfaceEdge}, prelude::*, + GestureClick, }; use wry::WebViewExtUnix; let webview = webview.webview(); + let click_controller = GestureClick::new(); + click_controller.set_button(gdk::BUTTON_PRIMARY); + + let webview_ = webview.clone(); + click_controller.connect_pressed(move |event, _, x, y| { + let Some(window) = webview_ + .root() + .and_then(|root| root.downcast::().ok()) + else { + return; + }; - webview.add_events( - gtk::gdk::EventMask::BUTTON1_MOTION_MASK - | gtk::gdk::EventMask::BUTTON_PRESS_MASK - | gtk::gdk::EventMask::TOUCH_MASK, - ); - - webview.connect_button_press_event( - move |webview: &webkit2gtk::WebView, event: >k::gdk::EventButton| { - if event.button() == 1 { - // This one should be GtkBox - if let Some(window) = webview.parent().and_then(|w| w.parent()) { - // Safe to unwrap unless this is not from tao - let window: gtk::Window = window.downcast().unwrap(); - if !window.is_decorated() && window.is_resizable() && !window.is_maximized() { - if let Some(window) = window.window() { - let (root_x, root_y) = event.root(); - let (window_x, window_y) = window.position(); - let (client_x, client_y) = (root_x - window_x as f64, root_y - window_y as f64); - let border = window.scale_factor() * BORDERLESS_RESIZE_INSET; - let edge = hit_test( - 0.0, - 0.0, - window.width() as f64, - window.height() as f64, - client_x, - client_y, - border as _, - border as _, - ) - .to_gtk_edge(); - - // we ignore the `__Unknown` variant so the webview receives the click correctly if it is not on the edges. - match edge { - WindowEdge::__Unknown(_) => (), - _ => { - window.begin_resize_drag(edge, 1, root_x as i32, root_y as i32, event.time()) - } - } - } - } - } - } + if window.is_decorated() || !window.is_resizable() || window.is_maximized() { + return; + } - Propagation::Proceed - }, - ); - - webview.connect_touch_event( - move |webview: &webkit2gtk::WebView, event: >k::gdk::Event| { - // This one should be GtkBox - if let Some(window) = webview.parent().and_then(|w| w.parent()) { - // Safe to unwrap unless this is not from tao - let window: gtk::Window = window.downcast().unwrap(); - if !window.is_decorated() && window.is_resizable() && !window.is_maximized() { - if let Some(window) = window.window() { - if let Some((root_x, root_y)) = event.root_coords() { - if let Some(device) = event.device() { - let (window_x, window_y) = window.position(); - let (client_x, client_y) = (root_x - window_x as f64, root_y - window_y as f64); - let border = window.scale_factor() * BORDERLESS_RESIZE_INSET; - let edge = hit_test( - 0.0, - 0.0, - window.width() as f64, - window.height() as f64, - client_x, - client_y, - border as _, - border as _, - ) - .to_gtk_edge(); - - // we ignore the `__Unknown` variant so the window receives the click correctly if it is not on the edges. - match edge { - WindowEdge::__Unknown(_) => (), - _ => window.begin_resize_drag_for_device( - edge, - &device, - 0, - root_x as i32, - root_y as i32, - event.time(), - ), - } - } - } + let Some((client_x, client_y)) = webview_.translate_coordinates(&window, x, y) else { + return; + }; + + let border = window.scale_factor() * BORDERLESS_RESIZE_INSET; + let edge = hit_test( + 0.0, + 0.0, + window.width() as f64, + window.height() as f64, + client_x, + client_y, + border as _, + border as _, + ) + .to_gtk_edge(); + + // Ignore the `__Unknown` variant so the webview receives the click correctly if it is not on the edges. + match edge { + SurfaceEdge::__Unknown(_) => (), + _ => { + if let Some(surface) = window.surface() { + if let Ok(toplevel) = surface.downcast::() { + toplevel.begin_resize( + edge, + event.device().as_ref(), + event.button() as i32, + client_x, + client_y, + event.current_event_time(), + ); } } } + } + }); - Propagation::Proceed - }, - ); + webview.add_controller(click_controller); } } diff --git a/crates/tauri-runtime-wry/src/webview.rs b/crates/tauri-runtime-wry/src/webview.rs index 67b607392b88..c5a7aabb2174 100644 --- a/crates/tauri-runtime-wry/src/webview.rs +++ b/crates/tauri-runtime-wry/src/webview.rs @@ -10,7 +10,7 @@ target_os = "openbsd" ))] mod imp { - pub type Webview = webkit2gtk::WebView; + pub type Webview = webkit::WebView; } #[cfg(target_vendor = "apple")] diff --git a/crates/tauri-runtime/Cargo.toml b/crates/tauri-runtime/Cargo.toml index c2c54cccc519..e034a688aed3 100644 --- a/crates/tauri-runtime/Cargo.toml +++ b/crates/tauri-runtime/Cargo.toml @@ -43,8 +43,8 @@ features = ["Win32_Foundation", "Win32_System_WinRT"] webview2-com = "0.38" [target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] -gtk = { version = "0.18", features = ["v3_24"] } -webkit2gtk = { version = "=2.0", features = ["v2_40"] } +gtk = { package = "gtk4", version = "0.11", features = ["v4_10"] } +webkit = { package = "webkit6", version = "0.6", features = ["v2_42"] } [target."cfg(target_os = \"android\")".dependencies] jni = "0.21" diff --git a/crates/tauri-runtime/src/webview.rs b/crates/tauri-runtime/src/webview.rs index d7fb9c80f311..f383d3cd2a0f 100644 --- a/crates/tauri-runtime/src/webview.rs +++ b/crates/tauri-runtime/src/webview.rs @@ -101,7 +101,7 @@ pub struct NewWindowOpener { target_os = "netbsd", target_os = "openbsd", ))] - pub webview: webkit2gtk::WebView, + pub webview: webkit::WebView, /// The instance of the webview that initiated the new window request. /// /// The target webview environment **MUST** match the environment of the opener webview. See [`WebviewAttributes::with_environment`]. @@ -417,7 +417,7 @@ pub struct WebviewAttributes { target_os = "netbsd", target_os = "openbsd", ))] - pub related_view: Option, + pub related_view: Option, #[cfg(target_os = "macos")] pub webview_configuration: Option>, diff --git a/crates/tauri-runtime/src/window.rs b/crates/tauri-runtime/src/window.rs index 936280ca18c3..18e7cbae4429 100644 --- a/crates/tauri-runtime/src/window.rs +++ b/crates/tauri-runtime/src/window.rs @@ -447,7 +447,7 @@ pub trait WindowBuilder: WindowBuilderBase { /// Sets the window to be created transient for parent. /// - /// See + /// See #[cfg(any( target_os = "linux", target_os = "dragonfly", @@ -455,7 +455,7 @@ pub trait WindowBuilder: WindowBuilderBase { target_os = "netbsd", target_os = "openbsd" ))] - fn transient_for(self, parent: &impl gtk::glib::IsA) -> Self; + fn transient_for(self, parent: &impl gtk::glib::object::IsA) -> Self; /// Enables or disables drag and drop support. #[cfg(windows)] diff --git a/crates/tauri/Cargo.toml b/crates/tauri/Cargo.toml index 3f1dd5f82e2d..a36a24a79fbd 100644 --- a/crates/tauri/Cargo.toml +++ b/crates/tauri/Cargo.toml @@ -93,13 +93,13 @@ muda = { version = "0.19", default-features = false, features = [ ] } tray-icon = { version = "0.24", default-features = false, features = [ "serde", - "gtk", + "linux-ksni", ], optional = true } # linux [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies] -gtk = { version = "0.18", features = ["v3_24"] } -webkit2gtk = { version = "2", features = ["v2_40"], optional = true } +gtk = { package = "gtk4", version = "0.11", features = ["v4_10"] } +webkit = { package = "webkit6", version = "0.6", features = ["v2_42"], optional = true } # darwin [target.'cfg(target_vendor = "apple")'.dependencies] @@ -206,7 +206,7 @@ tray-icon = ["dep:tray-icon"] tracing = ["dep:tracing", "tauri-macros/tracing", "tauri-runtime-wry?/tracing"] test = [] compression = ["tauri-macros/compression", "tauri-utils/compression"] -wry = ["webview2-com", "webkit2gtk", "tauri-runtime-wry"] +wry = ["webview2-com", "webkit", "tauri-runtime-wry"] # TODO: Remove in v3 - wry does not have this feature anymore objc-exception = [] linux-libxdo = ["tray-icon/libxdo", "muda/libxdo"] diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index d4b7d139433e..c5015e2e81b0 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -2090,7 +2090,7 @@ tauri::Builder::default() /// /// Leverages [setURLSchemeHandler](https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/2875766-seturlschemehandler) on macOS, /// [AddWebResourceRequestedFilter](https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.addwebresourcerequestedfilter?view=webview2-dotnet-1.0.774.44) on Windows - /// and [webkit-web-context-register-uri-scheme](https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebContext.html#webkit-web-context-register-uri-scheme) on Linux. + /// and `webkit_web_context_register_uri_scheme` on Linux. /// /// # Arguments /// diff --git a/crates/tauri/src/ipc/channel.rs b/crates/tauri/src/ipc/channel.rs index 0b3eb6778920..76fffed89ecb 100644 --- a/crates/tauri/src/ipc/channel.rs +++ b/crates/tauri/src/ipc/channel.rs @@ -56,7 +56,7 @@ const _: () = { #[derive(specta::Type)] #[specta(remote = super::Channel)] #[allow(dead_code, non_camel_case_types)] - struct TAURI_CHANNEL(std::marker::PhantomData); + struct TAURI_CHANNEL(#[specta(skip)] std::marker::PhantomData); }; impl Clone for Channel { diff --git a/crates/tauri/src/lib.rs b/crates/tauri/src/lib.rs index 75e7b042d82c..8a3691b6e948 100644 --- a/crates/tauri/src/lib.rs +++ b/crates/tauri/src/lib.rs @@ -1102,34 +1102,34 @@ pub mod test; #[cfg(feature = "specta")] const _: () = { - use specta::{datatype::DataType, function::FunctionArg, TypeMap}; + use specta::{datatype::DataType, function::FunctionArg, Types}; impl FunctionArg for crate::State<'_, T> { - fn to_datatype(_: &mut TypeMap) -> Option { + fn to_datatype(_: &mut Types) -> Option { None } } impl FunctionArg for crate::AppHandle { - fn to_datatype(_: &mut TypeMap) -> Option { + fn to_datatype(_: &mut Types) -> Option { None } } impl FunctionArg for crate::Window { - fn to_datatype(_: &mut TypeMap) -> Option { + fn to_datatype(_: &mut Types) -> Option { None } } impl FunctionArg for crate::Webview { - fn to_datatype(_: &mut TypeMap) -> Option { + fn to_datatype(_: &mut Types) -> Option { None } } impl FunctionArg for crate::WebviewWindow { - fn to_datatype(_: &mut TypeMap) -> Option { + fn to_datatype(_: &mut Types) -> Option { None } } diff --git a/crates/tauri/src/plugin.rs b/crates/tauri/src/plugin.rs index 3a22de7bc700..6bdd05f9ac99 100644 --- a/crates/tauri/src/plugin.rs +++ b/crates/tauri/src/plugin.rs @@ -596,7 +596,7 @@ impl Builder { /// /// Leverages [setURLSchemeHandler](https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/2875766-seturlschemehandler) on macOS, /// [AddWebResourceRequestedFilter](https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.addwebresourcerequestedfilter?view=webview2-dotnet-1.0.774.44) on Windows - /// and [webkit-web-context-register-uri-scheme](https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebContext.html#webkit-web-context-register-uri-scheme) on Linux. + /// and `webkit_web_context_register_uri_scheme` on Linux. /// /// # Known limitations /// diff --git a/crates/tauri/src/test/mock_runtime.rs b/crates/tauri/src/test/mock_runtime.rs index 23982ea992f1..66d4543b5897 100644 --- a/crates/tauri/src/test/mock_runtime.rs +++ b/crates/tauri/src/test/mock_runtime.rs @@ -501,7 +501,7 @@ impl WindowBuilder for MockWindowBuilder { target_os = "netbsd", target_os = "openbsd" ))] - fn transient_for(self, parent: &impl gtk::glib::IsA) -> Self { + fn transient_for(self, parent: &impl gtk::glib::object::IsA) -> Self { self } diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs index b89d3c95d0e8..1662f9e3336b 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -152,7 +152,7 @@ pub struct PlatformWebview(tauri_runtime_wry::Webview); #[cfg(feature = "wry")] impl PlatformWebview { - /// Returns [`webkit2gtk::WebView`] handle. + /// Returns [`webkit::WebView`] handle. #[cfg(any( target_os = "linux", target_os = "dragonfly", @@ -170,7 +170,7 @@ impl PlatformWebview { target_os = "openbsd" ))) )] - pub fn inner(&self) -> webkit2gtk::WebView { + pub fn inner(&self) -> webkit::WebView { self.0.clone() } @@ -1273,7 +1273,7 @@ fn main() { target_os = "openbsd", ) ))] - pub fn with_related_view(mut self, related_view: webkit2gtk::WebView) -> Self { + pub fn with_related_view(mut self, related_view: webkit::WebView) -> Self { self.webview_attributes.related_view.replace(related_view); self } @@ -1609,7 +1609,7 @@ impl Webview { /// /// The closure is executed on the main thread. /// - /// Note that `webview2-com`, `webkit2gtk`, `objc2_web_kit` and similar crates may be updated in minor releases of Tauri. + /// Note that `webview2-com`, `webkit`, `objc2_web_kit` and similar crates may be updated in minor releases of Tauri. /// Therefore it's recommended to pin Tauri to at least a minor version when you're using `with_webview`. /// /// # Examples @@ -1626,9 +1626,9 @@ tauri::Builder::default() main_webview.with_webview(|webview| { #[cfg(target_os = "linux")] { - // see - // and - use webkit2gtk::WebViewExt; + // see + // and + use webkit::prelude::WebViewExt; webview.inner().set_zoom_level(4.); } diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs index 13b4982a198c..b67e4d1d004c 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -717,7 +717,7 @@ impl<'a, R: Runtime, M: Manager> WebviewWindowBuilder<'a, R, M> { target_os = "openbsd" ))] #[must_use] - pub fn transient_for_raw(mut self, parent: &impl gtk::glib::IsA) -> Self { + pub fn transient_for_raw(mut self, parent: &impl gtk::glib::object::IsA) -> Self { self.window_builder = self.window_builder.transient_for_raw(parent); self } @@ -1343,7 +1343,7 @@ impl> WebviewWindowBuilder<'_, R, M> { target_os = "openbsd", ) ))] - pub fn with_related_view(mut self, related_view: webkit2gtk::WebView) -> Self { + pub fn with_related_view(mut self, related_view: webkit::WebView) -> Self { self.webview_builder = self.webview_builder.with_related_view(related_view); self } @@ -2327,7 +2327,7 @@ impl WebviewWindow { /// /// The closure is executed on the main thread. /// - /// Note that `webview2-com`, `webkit2gtk`, `objc2_web_kit` and similar crates may be updated in minor releases of Tauri. + /// Note that `webview2-com`, `webkit`, `objc2_web_kit` and similar crates may be updated in minor releases of Tauri. /// Therefore it's recommended to pin Tauri to at least a minor version when you're using `with_webview`. /// /// # Examples @@ -2342,9 +2342,9 @@ impl WebviewWindow { /// main_webview.with_webview(|webview| { /// #[cfg(target_os = "linux")] /// { - /// // see - /// // and - /// use webkit2gtk::WebViewExt; + /// // see + /// // and + /// use webkit::prelude::WebViewExt; /// webview.inner().set_zoom_level(4.); /// } /// diff --git a/crates/tauri/src/window/mod.rs b/crates/tauri/src/window/mod.rs index e2f36441c778..0783552e5bb6 100644 --- a/crates/tauri/src/window/mod.rs +++ b/crates/tauri/src/window/mod.rs @@ -759,7 +759,7 @@ impl<'a, R: Runtime, M: Manager> WindowBuilder<'a, R, M> { target_os = "openbsd" ))] #[must_use] - pub fn transient_for_raw(mut self, parent: &impl gtk::glib::IsA) -> Self { + pub fn transient_for_raw(mut self, parent: &impl gtk::glib::object::IsA) -> Self { self.window_builder = self.window_builder.transient_for(parent); self } diff --git a/ports/muda/.changes/config.json b/ports/muda/.changes/config.json new file mode 100644 index 000000000000..8d336d283e36 --- /dev/null +++ b/ports/muda/.changes/config.json @@ -0,0 +1,52 @@ +{ + "gitSiteUrl": "https://www.github.com/tauri-apps/muda/", + "timeout": 3600000, + "pkgManagers": { + "rust": { + "version": true, + "getPublishedVersion": "cargo search ${ pkg.pkg } --limit 1 | sed -nE 's/^[^\"]*\"//; s/\".*//1p' -", + "prepublish": [ + "sudo apt-get update", + "sudo apt-get install -y libgtk-3-dev libxdo-dev" + ], + "publish": [ + { + "command": "cargo package --no-verify", + "dryRunCommand": true + }, + { + "command": "echo '
\n

Cargo Publish

\n\n```'", + "dryRunCommand": true, + "pipe": true + }, + { + "command": "cargo publish", + "dryRunCommand": "cargo publish --dry-run", + "pipe": true + }, + { + "command": "echo '```\n\n
\n'", + "dryRunCommand": true, + "pipe": true + } + ], + "postpublish": [ + "git tag ${ pkg.pkg }-v${ pkgFile.versionMajor } -f", + "git tag ${ pkg.pkg }-v${ pkgFile.versionMajor }.${ pkgFile.versionMinor } -f", + "git push --tags -f" + ] + } + }, + "packages": { + "muda": { + "path": ".", + "manager": "rust", + "assets": [ + { + "path": "${ pkg.path }/target/package/muda-${ pkgFile.version }.crate", + "name": "${ pkg.pkg }-${ pkgFile.version }.crate" + } + ] + } + } +} \ No newline at end of file diff --git a/ports/muda/.changes/gtk4.md b/ports/muda/.changes/gtk4.md new file mode 100644 index 000000000000..cc149bb84713 --- /dev/null +++ b/ports/muda/.changes/gtk4.md @@ -0,0 +1,5 @@ +--- +"muda": minor +--- + +Port the Linux backend from GTK3 to GTK4 (`gtk4` 0.11, `glib` 0.22). Every public method keeps its name and signature shape; the gtk types in returns and bounds follow the toolkit (`PopoverMenu`/`PopoverMenuBar`, `Widget` bounds), and `ContextMenu::gtk_context_menu` is retained on GTK4. Raises MSRV to 1.92. diff --git a/ports/muda/.changes/readme.md b/ports/muda/.changes/readme.md new file mode 100644 index 000000000000..b969dbd76abc --- /dev/null +++ b/ports/muda/.changes/readme.md @@ -0,0 +1,29 @@ +# Changes + +##### via https://github.com/jbolda/covector + +As you create PRs and make changes that require a version bump, please add a new markdown file in this folder. You do not note the version _number_, but rather the type of bump that you expect: major, minor, or patch. The filename is not important, as long as it is a `.md`, but we recommend it represents the overall change for our sanity. + +When you select the version bump required, you do _not_ need to consider dependencies. Only note the package with the actual change, and any packages that depend on that package will be bumped automatically in the process. + +Use the following format: + +```md +--- +"muda": patch +--- + +Change summary goes here +``` + +Summaries do not have a specific character limit, but are text only. These summaries are used within the (future implementation of) changelogs. They will give context to the change and also point back to the original PR if more details and context are needed. + +Changes will be designated as a `major`, `minor` or `patch` as further described in [semver](https://semver.org/). + +Given a version number MAJOR.MINOR.PATCH, increment the: + +- MAJOR version when you make incompatible API changes, +- MINOR version when you add functionality in a backwards compatible manner, and +- PATCH version when you make backwards compatible bug fixes. + +Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format, but will be discussed prior to usage (as extra steps will be necessary in consideration of merging and publishing). diff --git a/ports/muda/.github/workflows/audit.yml b/ports/muda/.github/workflows/audit.yml new file mode 100644 index 000000000000..fd10e86e6e59 --- /dev/null +++ b/ports/muda/.github/workflows/audit.yml @@ -0,0 +1,33 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: audit + +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * *' + push: + branches: + - dev + paths: + - 'Cargo.lock' + - 'Cargo.toml' + pull_request: + paths: + - 'Cargo.lock' + - 'Cargo.toml' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rustsec/audit-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/ports/muda/.github/workflows/clippy-fmt.yml b/ports/muda/.github/workflows/clippy-fmt.yml new file mode 100644 index 000000000000..35cc66e730c5 --- /dev/null +++ b/ports/muda/.github/workflows/clippy-fmt.yml @@ -0,0 +1,48 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: clippy & fmt + +on: + push: + branches: + - dev + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + clippy: + strategy: + fail-fast: false + matrix: + platform: [ubuntu-latest, macos-latest, windows-latest] + + runs-on: ${{ matrix.platform }} + + steps: + - uses: actions/checkout@v4 + - name: install system deps + if: matrix.platform == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev libgtk-4-dev libxdo-dev libwebkit2gtk-4.1-dev + + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + + - run: cargo clippy --all-targets --all-features -- -D warnings + + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + + - run: cargo fmt --all -- --check diff --git a/ports/muda/.github/workflows/covector-status.yml b/ports/muda/.github/workflows/covector-status.yml new file mode 100644 index 000000000000..41d265a1b735 --- /dev/null +++ b/ports/muda/.github/workflows/covector-status.yml @@ -0,0 +1,20 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: covector status +on: [pull_request] + +jobs: + covector: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: covector status + uses: jbolda/covector/packages/action@covector-v0 + id: covector + with: + command: "status" + token: ${{ secrets.GITHUB_TOKEN }} + comment: true \ No newline at end of file diff --git a/ports/muda/.github/workflows/covector-version-or-publish.yml b/ports/muda/.github/workflows/covector-version-or-publish.yml new file mode 100644 index 000000000000..e063fa0e3fac --- /dev/null +++ b/ports/muda/.github/workflows/covector-version-or-publish.yml @@ -0,0 +1,59 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: covector version or publish + +on: + push: + branches: + - dev + +jobs: + version-or-publish: + runs-on: ubuntu-latest + timeout-minutes: 65 + outputs: + change: ${{ steps.covector.outputs.change }} + commandRan: ${{ steps.covector.outputs.commandRan }} + successfulPublish: ${{ steps.covector.outputs.successfulPublish }} + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: cargo login + run: cargo login ${{ secrets.ORG_CRATES_IO_TOKEN }} + + - name: git config + run: | + git config --global user.name "${{ github.event.pusher.name }}" + git config --global user.email "${{ github.event.pusher.email }}" + + - name: covector version or publish (publish when no change files present) + uses: jbolda/covector/packages/action@covector-v0 + id: covector + env: + NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }} + with: + token: ${{ secrets.GITHUB_TOKEN }} + command: 'version-or-publish' + createRelease: true + recognizeContributors: true + + - name: Sync Cargo.lock + if: steps.covector.outputs.commandRan == 'version' + run: cargo tree --depth 0 + + - name: Create Pull Request With Versions Bumped + if: steps.covector.outputs.commandRan == 'version' + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # 8.1.1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + title: Apply Version Updates From Current Changes + commit-message: 'apply version updates' + labels: 'version updates' + branch: 'release' + body: ${{ steps.covector.outputs.change }} + sign-commits: true \ No newline at end of file diff --git a/ports/muda/.github/workflows/test.yml b/ports/muda/.github/workflows/test.yml new file mode 100644 index 000000000000..ebf3e90df0f6 --- /dev/null +++ b/ports/muda/.github/workflows/test.yml @@ -0,0 +1,49 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: test + +on: + push: + branches: + - dev + pull_request: + +env: + RUST_BACKTRACE: 1 + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + strategy: + fail-fast: false + matrix: + platform: ["windows-latest", "macos-latest", "ubuntu-latest"] + + runs-on: ${{ matrix.platform }} + + steps: + - uses: actions/checkout@v4 + + - name: install system deps + if: matrix.platform == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev libgtk-4-dev libxdo-dev libwebkit2gtk-4.1-dev + + - uses: dtolnay/rust-toolchain@master + with: + toolchain: "1.92" + - run: cargo build + + - uses: dtolnay/rust-toolchain@stable + - run: cargo test + + - uses: dtolnay/rust-toolchain@nightly + with: + components: miri + - run: cargo +nightly miri test diff --git a/ports/muda/.gitignore b/ports/muda/.gitignore new file mode 100644 index 000000000000..9409f7d4ae5f --- /dev/null +++ b/ports/muda/.gitignore @@ -0,0 +1,6 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +/target +/.vscode \ No newline at end of file diff --git a/ports/muda/CHANGELOG.md b/ports/muda/CHANGELOG.md new file mode 100644 index 000000000000..c7617b28686f --- /dev/null +++ b/ports/muda/CHANGELOG.md @@ -0,0 +1,348 @@ +# Changelog + +## \[0.19.3] + +- [`73106f5`](https://www.github.com/tauri-apps/muda/commit/73106f5c548a08bfeea35a1627ea533726f5ba2e) ([#363](https://www.github.com/tauri-apps/muda/pull/363) by [@Legend-Master](https://www.github.com/tauri-apps/muda/../../Legend-Master)) On Windows, fixed a `dangling` pointer crash when `Menu::remove_for_hwnd` is called before dropping that `Menu` and then attached a new `Menu` + +## \[0.19.2] + +- [`597e1bc`](https://www.github.com/tauri-apps/muda/commit/597e1bcb300fce429643725810e63a95333c7046) ([#354](https://www.github.com/tauri-apps/muda/pull/354) by [@kohii](https://www.github.com/tauri-apps/muda/../../kohii)) On macOS, render `Key::Enter` accelerators in menus as ⏎ (Return) instead of ⌤ (numeric-keypad Enter). Activation behavior is unchanged. +- [`51fde8e`](https://www.github.com/tauri-apps/muda/commit/51fde8e47e4c181fce892b2420d22f3d4e69bead) ([#357](https://www.github.com/tauri-apps/muda/pull/357) by [@mattico](https://www.github.com/tauri-apps/muda/../../mattico)) On Windows, fixed a bug that would truncate menubar items text to ~10 characters in dark-mode. + +## \[0.19.1] + +- [`b3d108e`](https://www.github.com/tauri-apps/muda/commit/b3d108ea60028acb3faf62d2ab975b4ded1d2e4e) ([#350](https://www.github.com/tauri-apps/muda/pull/350) by [@lucasfernog](https://www.github.com/tauri-apps/muda/../../lucasfernog)) Bump objc2 requirement to 0.6.1. + +## \[0.19.0] + +- [`521b5ff`](https://www.github.com/tauri-apps/muda/commit/521b5ffdac0dae0bc865434241c401bac483daed) ([#344](https://www.github.com/tauri-apps/muda/pull/344) by [@Legend-Master](https://www.github.com/tauri-apps/muda/../../Legend-Master)) Update png dependency version to 0.18. + + This avoids duplicated dependencies in downstream crates. +- [`521b5ff`](https://www.github.com/tauri-apps/muda/commit/521b5ffdac0dae0bc865434241c401bac483daed) ([#344](https://www.github.com/tauri-apps/muda/pull/344) by [@Legend-Master](https://www.github.com/tauri-apps/muda/../../Legend-Master)) Update rust version to 1.73. +- [`820bd54`](https://www.github.com/tauri-apps/muda/commit/820bd54069b3dccba9b5c6e9c6aa7c00f0e6ffb6) ([#347](https://www.github.com/tauri-apps/muda/pull/347) by [@renovate](https://www.github.com/tauri-apps/muda/../../renovate)) Relaxed `windows-sys` dependency to `>=0.60, <=0.61` instead of `0.60` + +## \[0.18.0] + +- [`b324619`](https://www.github.com/tauri-apps/muda/commit/b324619069e6ebd7b259fa15400fca87586b5dc6) ([#339](https://www.github.com/tauri-apps/muda/pull/339) by [@LeonMatthes](https://www.github.com/tauri-apps/muda/../../LeonMatthes)) Add a new `KeyAccelerator` struct based on `keyboard_types::Key` alongside the existing `Accelerator` (based on `Code`). + This enables expressing logical key shortcuts like "Ctrl++", "Ctrl+€" that physical key codes cannot represent (see https://github.com/tauri-apps/muda/issues/333). +- [`adb9f55`](https://www.github.com/tauri-apps/muda/commit/adb9f5565444f6240c3df25347a25bcfcdc442b2) ([#337](https://www.github.com/tauri-apps/muda/pull/337) by [@npwoods](https://www.github.com/tauri-apps/muda/../../npwoods)) On Windows, fixed a bug that would cause window subclasses to not be cleaned up when menus were dropped + +## \[0.17.2] + +- [`dca0836`](https://www.github.com/tauri-apps/muda/commit/dca083660d04209109ae854b9a9436a809daf409) ([#321](https://www.github.com/tauri-apps/muda/pull/321)) Fix padding unconditionally added to top-level submenus for icons even when there's no icon on Linux +- [`372d367`](https://www.github.com/tauri-apps/muda/commit/372d3675e477d698297b0e10864932261d41c66e) ([#335](https://www.github.com/tauri-apps/muda/pull/335)) Fix `Submenu::set_as_help_menu_for_nsapp` and `Submenu::set_as_windows_menu_for_nsapp` not working and macOS wouldn't recognize and add default menu items to them. +- [`43ba984`](https://www.github.com/tauri-apps/muda/commit/43ba984a89b6b36f2aa87be6206763d96f9c259b) ([#326](https://www.github.com/tauri-apps/muda/pull/326)) Add support for `PredefinedMenuItem::undo` and `PredefinedMenuItem::redo` on Windows. + +## \[0.17.1] + +- [`0ae81ad`](https://www.github.com/tauri-apps/muda/commit/0ae81ad8b22dd2622e302254ce434d14880087a3) ([#308](https://www.github.com/tauri-apps/muda/pull/308) by [@s00d](https://www.github.com/tauri-apps/muda/../../s00d)) On Windows, fix icon of `Submenu` not visible when added to a root `Menu` + +## \[0.17.0] + +- [`8e986af`](https://www.github.com/tauri-apps/muda/commit/8e986af3cea96a729413abc75c3702dec3990bd2) ([#289](https://www.github.com/tauri-apps/muda/pull/289) by [@amrbashir](https://www.github.com/tauri-apps/muda/../../amrbashir)) Add helper methods on `ContextMenu` trait to convert it back to a concrete type: + + - `ContextMenu::as_menu` + - `ContextMenu::as_menu_unchecked` + - `ContextMenu::as_submenu` + - `ContextMenu::as_submenu_unchecked` +- [`8efa5a2`](https://www.github.com/tauri-apps/muda/commit/8efa5a201b6acad72dee4c0c097a4bbda172b353) ([#300](https://www.github.com/tauri-apps/muda/pull/300) by [@dgerhardt](https://www.github.com/tauri-apps/muda/../../dgerhardt)) On Linux, fix `&&` resulting in `&&` when it should be just `&`. Also fix `_` not visible and actually adding a mnemonic. This makes the behavior on Linux match the behavior on Windows. +- [`e19a6eb`](https://www.github.com/tauri-apps/muda/commit/e19a6eb7417e722ee73fbae8bd97becbf5600142) ([#283](https://www.github.com/tauri-apps/muda/pull/283) by [@ogoffart](https://www.github.com/tauri-apps/muda/../../ogoffart)) Make gtk an optional feature (enabled by default) +- [`e37d99b`](https://www.github.com/tauri-apps/muda/commit/e37d99b6de01dde0e3206a0f358cdc10a2aa3ddb) ([#277](https://www.github.com/tauri-apps/muda/pull/277) by [@s00d](https://www.github.com/tauri-apps/muda/../../s00d)) Add support for icons on `Submenu` so we added: + + - `Submenu::set_icon` + - `Submenu::set_native_icon` + - `SubmenuBuilder::icon` + - `SubmenuBuilder::native_icon` + +## \[0.16.1] + +- [`6b3e2e5`](https://www.github.com/tauri-apps/muda/commit/6b3e2e51bb501ffbdf4526e59e4dedcb37c7b29b) ([#278](https://www.github.com/tauri-apps/muda/pull/278) by [@Legend-Master](https://www.github.com/tauri-apps/muda/../../Legend-Master)) Fix the buffer overflow when calling `text` on Windows + +## \[0.16.0] + +- [`cf9dcfa`](https://www.github.com/tauri-apps/muda/commit/cf9dcfafd000336db4e9f239ed5581539d9168f6) ([#236](https://www.github.com/tauri-apps/muda/pull/236)) Return `bool` in `ContextMenu::show_context_menu_for_hwnd`, `ContextMenu::show_context_menu_for_nsview` and `ContextMenu::show_context_menu_for_gtk_window` to indicate why the context menu was closed. +- [`99ec648`](https://www.github.com/tauri-apps/muda/commit/99ec648de4dfd3b864540b1e30279c2c7afc1abd) ([#244](https://www.github.com/tauri-apps/muda/pull/244)) Add `Accelerator::modifiers` and `Accelerator::key` getter methods. +- [`372f8a1`](https://www.github.com/tauri-apps/muda/commit/372f8a1d095edf0c88f3708777484371202ee91c) ([#269](https://www.github.com/tauri-apps/muda/pull/269)) Updated objc2 to 0.6 +- [`e6b68f9`](https://www.github.com/tauri-apps/muda/commit/e6b68f9c4da1d47e612569a60a9da9199b324d81) Change internal `mut static` to use `thread_local!` and `Cell` instead. + +## \[0.15.3] + +- [`11a1ef8`](https://www.github.com/tauri-apps/muda/commit/11a1ef84fa85cbe2f0bfb0c3a986d7a36d84288f) ([#241](https://www.github.com/tauri-apps/muda/pull/241) by [@amrbashir](https://www.github.com/tauri-apps/muda/../../amrbashir)) On Windows, fix changing state of menu items inside a `muda::Menu` not immediately reflected on the window menu bar. + +## \[0.15.2] + +- [`3b58a2e`](https://www.github.com/tauri-apps/muda/commit/3b58a2ef973a7fb46ce6b4cfd34942d990929510) ([#237](https://www.github.com/tauri-apps/muda/pull/237) by [@amrbashir](https://www.github.com/tauri-apps/muda/../../amrbashir)) Fix `PredefinedMenuItem::about` sending events where it shouldn't. + +## \[0.15.1] + +- [`8bf315e`](https://www.github.com/tauri-apps/muda/commit/8bf315ea31f791e44d3c67f5fdb0ac4c47e16aaf) ([#229](https://www.github.com/tauri-apps/muda/pull/229) by [@amrbashir](https://www.github.com/tauri-apps/muda/../../amrbashir)) On Linux, fix `IconMenuItem` overlapping neighbouring items when added to a `Menu`. + +## \[0.15.0] + +- [`40d06c5`](https://www.github.com/tauri-apps/muda/commit/40d06c5c9712ab4e12a8bc3a9124e5975df595e3) ([#226](https://www.github.com/tauri-apps/muda/pull/226) by [@amrbashir](https://www.github.com/tauri-apps/muda/../../amrbashir)) **Breaking change** Renamed the `acccelerator` method (which has an extra `c`) on `MenuItemBuilder`, `CheckMenuItemBuilder`, and `IconMenuItemBuilder` to `accelerator`. +- [`0d368bb`](https://www.github.com/tauri-apps/muda/commit/0d368bb32728a104f0d6ad100193b0212495dd64) ([#220](https://www.github.com/tauri-apps/muda/pull/220) by [@madsmtm](https://www.github.com/tauri-apps/muda/../../madsmtm)) **Breaking Change** Changed the type of the pointer passed in `show_context_menu_for_nsview` to `c_void`, and make the method `unsafe`. +- [`63c9f28`](https://www.github.com/tauri-apps/muda/commit/63c9f2873c7d2f6c1b477e0d5c7f79ccda90ea85) ([#224](https://www.github.com/tauri-apps/muda/pull/224) by [@Legend-Master](https://www.github.com/tauri-apps/muda/../../Legend-Master)) Fix `set_theme_for_hwnd` always resulting in dark on Windows, and doesn't refresh until losing and regaining focus +- [`f781c0e`](https://www.github.com/tauri-apps/muda/commit/f781c0edd0af7ab166e10f816978ffed2761376b) ([#227](https://www.github.com/tauri-apps/muda/pull/227) by [@amrbashir](https://www.github.com/tauri-apps/muda/../../amrbashir)) **Breaking change** Marked a few methods with `unsafe` to better represent the safety guarantees: + + - `ContextMenu::show_context_menu_for_hwnd` + - `ContextMenu::attach_menu_subclass_for_hwnd` + - `ContextMenu::detach_menu_subclass_from_hwnd` + - `Menu::init_for_hwnd` + - `Menu::init_for_hwnd_with_theme` + - `Menu::set_theme_for_hwnd` + - `Menu::remove_for_hwnd` + - `Menu::hide_for_hwnd` + - `Menu::show_for_hwnd` + - `Menu::is_visible_on_hwnd` +- [`5c8971a`](https://www.github.com/tauri-apps/muda/commit/5c8971a7c28a48669605236ddc097460ffd3b32f) ([#221](https://www.github.com/tauri-apps/muda/pull/221) by [@madsmtm](https://www.github.com/tauri-apps/muda/../../madsmtm)) Use `objc2` internally, leading to much better memory safety. The crate will panic now if used from a thread that is not the main thread. + +## \[0.14.1] + +- [`07ca638`](https://www.github.com/tauri-apps/muda/commit/07ca6382bc1ae08984c21034b8033cee3eb147c7) ([#213](https://www.github.com/tauri-apps/muda/pull/213)) Fix handling the separator of `CARGO_PKG_AUTHORS` environment variable value in `from_cargo_metadata` macro. +- [`bb40d8c`](https://www.github.com/tauri-apps/muda/commit/bb40d8cec3187eccb3bce868befe1d0bf0dbf93c) On Windows, fix crash when showing a context menu but dropping the Menu before the context menu is closed. + +## \[0.14.0] + +- [`11d8b7a`](https://www.github.com/tauri-apps/muda/commit/11d8b7a6fefa2b47b5bd0a113c0f33f0ccdf6647) ([#208](https://www.github.com/tauri-apps/muda/pull/208) by [@amrbashir](https://www.github.com/tauri-apps/muda/../../amrbashir)) Added `about_metadata` module and `about_metadata::from_cargo_metadata` macro. +- [`11d8b7a`](https://www.github.com/tauri-apps/muda/commit/11d8b7a6fefa2b47b5bd0a113c0f33f0ccdf6647) ([#208](https://www.github.com/tauri-apps/muda/pull/208) by [@amrbashir](https://www.github.com/tauri-apps/muda/../../amrbashir)) **Breaking Change** Removed `AboutMetadata::from_cargo_metadata` and `AboutMetadataBuilder::with_cargo_metadata` which had incorrect implementation, use the new `about_metadata::from_cargo_metadata` macro instead. +- [`32bff56`](https://www.github.com/tauri-apps/muda/commit/32bff5610f355de86bfff55605ab3383d40b7d42) ([#210](https://www.github.com/tauri-apps/muda/pull/210) by [@amrbashir](https://www.github.com/tauri-apps/muda/../../amrbashir)) Update `window-sys` crate to `0.59` + +## \[0.13.5] + +- [`20ea54b`](https://www.github.com/tauri-apps/muda/commit/20ea54b69844b53f09e40e6399bb4ea26af58766)([#200](https://www.github.com/tauri-apps/muda/pull/200)) On macOS, close tray menu before removing it to prevent user click on a released menu item resulting in a crash. + +## \[0.13.4] + +- [`e758002`](https://www.github.com/tauri-apps/muda/commit/e758002bffe95f2d6f2d106967063ca87eb2f253)([#194](https://www.github.com/tauri-apps/muda/pull/194)) On Windows, fix menubar drawing when using a fixed dark theme while Windows itself in Light theme. + +## \[0.13.3] + +- [`e758002`](https://www.github.com/tauri-apps/muda/commit/e758002bffe95f2d6f2d106967063ca87eb2f253)([#194](https://www.github.com/tauri-apps/muda/pull/194)) On Windows, add `Menu::init_for_hwnd_with_theme` and `Menu::set_theme_for_hwnd` to control the window menu bar theme. + +## \[0.13.2] + +- [`1dc9d3f`](https://www.github.com/tauri-apps/muda/commit/1dc9d3f193e698b4a688414cc094ff360cb072a4)([#190](https://www.github.com/tauri-apps/muda/pull/190)) On Linux, fix context menu closing immediately when right click is released. + +## \[0.13.1] + +- [`2edfbf1`](https://www.github.com/tauri-apps/muda/commit/2edfbf1a3a33199eb963532118d83a40f4d99af2)([#176](https://www.github.com/tauri-apps/muda/pull/176)) On macOS, fix a crash when removing a menu item. + +## \[0.13.0] + +- [`90926d4`](https://www.github.com/tauri-apps/muda/commit/90926d43f7817ef7061aa8baa8072983a91d6a81)([#174](https://www.github.com/tauri-apps/muda/pull/174)) Moved the following items into `dpi` module which is just an export of `dpi` crate: + + - `Pixel` + - `validate_scale_factor` + - `LogicalPosition` + - `PhysicalPosition` + - `Position` + +## \[0.12.2] + +- [`8960f0d`](https://www.github.com/tauri-apps/muda/commit/8960f0ddb52b74f4bd9d5fed5e91b62c5db09c77)([#171](https://www.github.com/tauri-apps/muda/pull/171)) On Windows, fix using multiple context menus resulted in receiving events only for the last used one. + +## \[0.12.1] + +- [`cbb9fc0`](https://www.github.com/tauri-apps/muda/commit/cbb9fc0d7b98c362dfbdc09122fb9d0b3b7edabb)([#166](https://www.github.com/tauri-apps/muda/pull/166)) On Windows, fix events not emitted for other menus after using a menu as a context menu. +- [`a9937ef`](https://www.github.com/tauri-apps/muda/commit/a9937ef98144b3feaf8a16ae95e0e8c55583bd79)([#164](https://www.github.com/tauri-apps/muda/pull/164)) On Windows, fix menubar removed from window when another menu that was used as a conetxt menu is dropped. + +## \[0.12.0] + +- [`2d7828f`](https://www.github.com/tauri-apps/muda/commit/2d7828fdd9d216d9a245bad7eae8f096b42948c0)([#157](https://www.github.com/tauri-apps/muda/pull/157)) Refactored the errors when parsing accelerator from string: + + - Added `AcceleratorParseError` error enum. + - Removed `Error::UnrecognizedAcceleratorCode` enum variant + - Removed `Error::EmptyAcceleratorToken` enum variant + - Removed `Error::UnexpectedAcceleratorFormat` enum variant + - Changed `Error::AcceleratorParseError` inner value from `String` to the newly added `AcceleratorParseError` enum. +- [`2d7828f`](https://www.github.com/tauri-apps/muda/commit/2d7828fdd9d216d9a245bad7eae8f096b42948c0)([#157](https://www.github.com/tauri-apps/muda/pull/157)) Avoid panicking when parsing an invalid `Accelerator` from a string such as `SHIFT+SHIFT` and return an error instead. + +## \[0.11.5] + +- [`f64a62f`](https://www.github.com/tauri-apps/muda/commit/f64a62fc89d39e9fe6f3951250addf620ba8ba29)([#153](https://www.github.com/tauri-apps/muda/pull/153)) On Linux, fix a regression where menubar is not added as the first child when using a `gtk::Box` as the container. + +## \[0.11.4] + +- [`a7e61fb`](https://www.github.com/tauri-apps/muda/commit/a7e61fb939866897d0ed3d32b78a3a7cba8689ca)([#149](https://www.github.com/tauri-apps/muda/pull/149)) On macOS, fix a crash when appending separators. + +## \[0.11.3] + +- [`20c45a4`](https://www.github.com/tauri-apps/muda/commit/20c45a4ccc24914f5ad7533300e0d1e6d7d91384)([#147](https://www.github.com/tauri-apps/muda/pull/147)) On macOS, fixed a panic when releasing separator menu item. + +## \[0.11.2] + +- [`afd3e2e`](https://www.github.com/tauri-apps/muda/commit/afd3e2ecd4b40def7c0f458cd1465723392c1be1)([#143](https://www.github.com/tauri-apps/muda/pull/143)) Fixes menu item's `enabled` state not applied for submenus on macOS. + +## \[0.11.1] + +- [`07b188f`](https://www.github.com/tauri-apps/muda/commit/07b188f386522f42f47670d6de30afa4da1a24a8)([#141](https://www.github.com/tauri-apps/muda/pull/141)) Update `windows-sys` crate to `0.52` + +## \[0.11.0] + +- [`ae316bf`](https://www.github.com/tauri-apps/muda/commit/ae316bf2dd3dbefce5f866b98165b0336bb3010e)([#139](https://www.github.com/tauri-apps/muda/pull/139)) Changed `ContextMenu::show_context_menu_for_gtk_window` to take `gtk::Window` instead of `gtk::ApplicationWindow` and relaxed generic gtk constraints on the following methods: + + - `MenuBar::init_for_gtk_window` + - `MenuBar::remove_for_gtk_window` + - `MenuBar::hide_for_gtk_window` + - `MenuBar::show_for_gtk_window` + - `MenuBar::is_visible_on_gtk_window` + - `MenuBar::gtk_menubar_for_gtk_window` + +## \[0.10.0] + +- [`8d95612`](https://www.github.com/tauri-apps/muda/commit/8d95612c27374637895ac5d28f553143501adeff)([#133](https://www.github.com/tauri-apps/muda/pull/133)) Upgrade `gtk` to 0.18 and bump MSRV to 1.70.0. + +## \[0.9.4] + +- [`3672a0c`](https://www.github.com/tauri-apps/muda/commit/3672a0c663bb711528d18d1f4abee949f1ca26f2)([#130](https://www.github.com/tauri-apps/muda/pull/130)) Add `PredefinedMenuItem::bring_all_to_front` for 'Bring All to Front' menu item on macOS. +- [`e34040e`](https://www.github.com/tauri-apps/muda/commit/e34040e75a97e5b17d31c6d0f6df007cce5ddfc6)([#126](https://www.github.com/tauri-apps/muda/pull/126)) On Windows, draw over the white line under the menubar in dark mode. + +## \[0.9.3] + +- [`bdd0c9a`](https://www.github.com/tauri-apps/muda/commit/bdd0c9aa0d7d4158535796a20a1c1597799840a4)([#122](https://www.github.com/tauri-apps/muda/pull/122)) On macOS, fix menu crash due to a double freeing the underlying NsMenu. +- [`f7e3030`](https://www.github.com/tauri-apps/muda/commit/f7e3030f3438f92e92dfa724c5f8a6864387de0f)([#125](https://www.github.com/tauri-apps/muda/pull/125)) On Windows, redraw the menubar when adding a new menu item or a submenu. + +## \[0.9.2] + +- [`45345ad`](https://www.github.com/tauri-apps/muda/commit/45345ad631187190799bdaea6f9f0d0d7e245d5e) On macOS, fixed autorelease from separator twice. + +## \[0.9.1] + +- [`c1fbde7`](https://www.github.com/tauri-apps/muda/commit/c1fbde72a83fdef579436f2fc7a55de77fa907c2)([#116](https://www.github.com/tauri-apps/muda/pull/116)) Added `AboutMetadata::from_cargo_metadata` and `AboutMetadataBuilder::with_cargo_metadata` to build the application metadata from Cargo package metadata. + +## \[0.9.0] + +- [`02e537e`](https://www.github.com/tauri-apps/muda/commit/02e537ea06e74dd08c3bdeaf350d8c71e8e04f19)([#112](https://www.github.com/tauri-apps/muda/pull/112)) Added `into_id` method to `MenuItem`, `CheckMenuItem`, `PredefinedMenuItem`, `Submenu`, `MenuItemKind` and `IsMenuItem` trait. It moves the menu item into its id. +- [`622f30b`](https://www.github.com/tauri-apps/muda/commit/622f30b838a5dee879715ca5da3ff84bcaa48685) Update `keyboard-types` to `0.7` +- [`bce7540`](https://www.github.com/tauri-apps/muda/commit/bce7540bba0d26ae4e55b3e2d164f1579b58743a)([#113](https://www.github.com/tauri-apps/muda/pull/113)) Add `MenuItemKind::id` convenient method to get access to the inner kind id. + +## \[0.8.7] + +- [`8d832c0`](https://www.github.com/tauri-apps/muda/commit/8d832c06f4e810278c0da129063231f880c3f918) Wrapped the `id` field of the `Menu` struct in an `Rc` to be consistent with other menu structs and make it cheaper to clone. + +## \[0.8.6] + +- [`4701bb8`](https://www.github.com/tauri-apps/muda/commit/4701bb836e9d5f5c020c7807616d68bd049679a9)([#105](https://www.github.com/tauri-apps/muda/pull/105)) On Windows, fix menu items inside a context menu not firing events if the context menu was used on a Window that doesn't have a menu bar. + +## \[0.8.5] + +- [`e046132`](https://www.github.com/tauri-apps/muda/commit/e046132dfba47ab75905ff28c354f83b5b27703d) Changed `IconMenuItem::set_native_icon` to take `&self` instead of `&mut self`. + +## \[0.8.4] + +- [`47d1808`](https://www.github.com/tauri-apps/muda/commit/47d1808090dc8b064417d5aae192b924fdafaf58) Derive `serde` for more types. + +## \[0.8.3] + +- [`33168fa`](https://www.github.com/tauri-apps/muda/commit/33168fa0a01e2773d9da4628afd4b147bc603f4d)([#98](https://www.github.com/tauri-apps/muda/pull/98)) On Windows, draw a dark menu bar if the Window supports and has dark-mode enabled. +- [`1a527e8`](https://www.github.com/tauri-apps/muda/commit/1a527e87086cf8d93e02405b87ca97992c08ad04)([#100](https://www.github.com/tauri-apps/muda/pull/100)) Add `PartialEq<&str> for &MenuId` and `PartialEq for &MenuId` implementations. Also add a blanket `From for MenuId` where `T: ToString` implementation. + +## \[0.8.2] + +- [`829051a`](https://www.github.com/tauri-apps/muda/commit/829051a30a1fef1e83b9bc0d4c10ff9874589f65) Dereference `&String` and `&&str` in `PartialEq` for `MenuId` type + +## \[0.8.1] + +- [`32be0c5`](https://www.github.com/tauri-apps/muda/commit/32be0c58841252db4f07c273c894a01f1fa414ff)([#94](https://www.github.com/tauri-apps/muda/pull/94)) On Windows, reduce some unneccassry string cloning. +- [`32be0c5`](https://www.github.com/tauri-apps/muda/commit/32be0c58841252db4f07c273c894a01f1fa414ff)([#94](https://www.github.com/tauri-apps/muda/pull/94)) Add `MenuId::new` convenience method. + +## \[0.8.0] + +- [`662e17d`](https://www.github.com/tauri-apps/muda/commit/662e17d0ec75a746a330390ad3818e35bd2be234)([#92](https://www.github.com/tauri-apps/muda/pull/92)) Add `Drop` implementation for the inner types to release memory and OS resources. +- [`7ca4b11`](https://www.github.com/tauri-apps/muda/commit/7ca4b115646a0ec1c19547267959625b6842b288)([#89](https://www.github.com/tauri-apps/muda/pull/89)) **Breaking Change:** On Linux, `Menu::inti_for_gtk_window` has been changed to require the second parameter to extend `gtk::Box`. This ensures that the menu bar is added at the beginning of the box instead of at the bottom. +- [`bb92b56`](https://www.github.com/tauri-apps/muda/commit/bb92b5667eb43d39a162b86f0b779d06e36eca52) On macOS, changed `Submenu::set_windows_menu_for_nsapp` and `Submenu::set_help_menu_for_nsapp` to `Submenu::set_as_windows_menu_for_nsapp` and `Submenu::set_as_help_menu_for_nsapp` +- [`874f345`](https://www.github.com/tauri-apps/muda/commit/874f345f3c719d70065fceeabebed6224d857813) Add `MenuId` struct an changed all `.id()` methods to return `MenuId` instead of a u32. +- [`043026c`](https://www.github.com/tauri-apps/muda/commit/043026c30d46f81a0fc2975d7e6bea10421ceb47)([#93](https://www.github.com/tauri-apps/muda/pull/93)) Add `Menu/Submenu::remove_at` to remove an item at specified index. +- [`662e17d`](https://www.github.com/tauri-apps/muda/commit/662e17d0ec75a746a330390ad3818e35bd2be234)([#92](https://www.github.com/tauri-apps/muda/pull/92)) On Windows, fix `.set_text()` sometimes adding gebberish characters after multiple calls. + +## \[0.7.3] + +- [`22956ec`](https://www.github.com/tauri-apps/muda/commit/22956ec724673d21e1d6a675c536eff060737e02)([#87](https://www.github.com/tauri-apps/muda/pull/87)) Fix `remove_for_nsapp` not working. + +## \[0.7.2] + +- [`0bad3ac`](https://www.github.com/tauri-apps/muda/commit/0bad3aca9608df04656757064fe85d757ff17513)([#84](https://www.github.com/tauri-apps/muda/pull/84)) Manually retain/release NSMenu reference. + +## \[0.7.1] + +- [`7a3bc55`](https://www.github.com/tauri-apps/muda/commit/7a3bc5505f60fa16a34aac4fb209dbb4968db9bf)([#81](https://www.github.com/tauri-apps/muda/pull/81)) On Windows, fix `ContextMenu::detach_menu_subclass_from_hwnd` crashing and terminating the thread. + +## \[0.7.0] + +- [`ee30bf8`](https://www.github.com/tauri-apps/muda/commit/ee30bf8d29895c35d7cda0d67d9d64b71910380a)([#73](https://www.github.com/tauri-apps/muda/pull/73)) Added the `builders` which contains convenient builder types, like `AboutMetadataBuilder`, `MenuItemBuilder`, `SubmenuBuilder` ...etc. +- [`c7ec320`](https://www.github.com/tauri-apps/muda/commit/c7ec3207388947b5572847e589eb494d0222373d)([#78](https://www.github.com/tauri-apps/muda/pull/78)) **Breaking Change**: `ContextMenu::show_context_menu_for_hwnd`, `ContextMenu::show_context_menu_for_gtk_window` and `ContextMenu::show_context_menu_for_nsview` has been changed to take an optional `Into` type instead of `x` and `y`. if `None` is provided, it will use the current cursor position. +- [`98701d0`](https://www.github.com/tauri-apps/muda/commit/98701d0b3277dcb63ee50a8a11f5b008ed432307)([#75](https://www.github.com/tauri-apps/muda/pull/75)) **Breaking Change**: Changed `Menu::init_for_gtk_window` to accept a second argument for a container to which the menu bar should be added, if `None` was provided, it will add it to the window directly. The method will no longer create a `gtk::Box` and append it to the window, instead you should add the box to the window yourself, then pass a reference to it to the method so it can be used as the container for the menu bar. +- [`20c05ce`](https://www.github.com/tauri-apps/muda/commit/20c05ceae677338b2b9dbf247a86d4049280cc90)([#79](https://www.github.com/tauri-apps/muda/pull/79)) **Breaking Change**: Removed `MenuItemType` enum and replaced with `MenuItemKind` enum. `Menu::items` and `Submenu::items` methods will now return `Vec` instead of `Vec>` +- [`0000e56`](https://www.github.com/tauri-apps/muda/commit/0000e569746e7cb630a1453a401bf8f6b0568e9d)([#71](https://www.github.com/tauri-apps/muda/pull/71)) **Breaking Change**: Changed `MenuItemExt` trait name to `IsMenuItem` +- [`ee30bf8`](https://www.github.com/tauri-apps/muda/commit/ee30bf8d29895c35d7cda0d67d9d64b71910380a)([#73](https://www.github.com/tauri-apps/muda/pull/73)) Impl `TryFrom<&str>` and `TryFrom` for `Accelerator`. + +## \[0.6.0] + +- [`ac14222`](https://www.github.com/tauri-apps/muda/commit/ac142229340c8ded63316fbc1cd1c11bf27e0890)([#69](https://www.github.com/tauri-apps/muda/pull/69)) Add `common-controls-v6` feature flag, disabled by default, which could be used to enable usage of `TaskDialogIndirect` API from `ComCtl32.dll` v6 on Windows for The predefined `About` menu item. +- [`7af4477`](https://www.github.com/tauri-apps/muda/commit/7af44778962de62bf6d8b05aab08bb2e689295fe)([#67](https://www.github.com/tauri-apps/muda/pull/67)) Add `libxdo` feature flag, enabled by default, to control whether to link `libxdo` on Linux or not. +- [`fabbbac`](https://www.github.com/tauri-apps/muda/commit/fabbbacb4b8d77c84cd318a21df1951063e7ea14)([#66](https://www.github.com/tauri-apps/muda/pull/66)) Add support for `AboutMetadata` on macOS + +## \[0.5.0] + +- Add `(MenuItem|CheckMenuItem|IconMenuItem)::set_accelerator` to change or disable the accelerator after creation. + - [47ba0b4](https://www.github.com/tauri-apps/muda/commit/47ba0b47ed28a93428c253e8bac397e0b9cb8dec) feat: add `set_accelerator` ([#64](https://www.github.com/tauri-apps/muda/pull/64)) on 2023-05-04 + +## \[0.4.5] + +- On Windows, fix panic when click a menu item while the `PredefinedMenuItem::about` dialog is open. + - [f3883ee](https://www.github.com/tauri-apps/muda/commit/f3883ee2d4d8773e6b77e36700edb4ca7cb0988e) fix(windows): run the about dialog in its own thread, closes [#57](https://www.github.com/tauri-apps/muda/pull/57) ([#60](https://www.github.com/tauri-apps/muda/pull/60)) on 2023-03-27 +- On Windows, Fix a panic when adding `CheckMenuItem` to a `Menu`. + - [059fceb](https://www.github.com/tauri-apps/muda/commit/059fceb13007760d9e41b65068c91442eda64626) fix(windows): downcast check menu item correctly ([#58](https://www.github.com/tauri-apps/muda/pull/58)) on 2023-03-27 + +## \[0.4.4] + +- On Windows, fix `MenuEvent` not triggered for `IconMenuItem`. + - [88d3520](https://www.github.com/tauri-apps/muda/commit/88d352033ba571126a11bc681ee3b346b7579916) fix(Windows): dispatch menu event for icon menu item ([#53](https://www.github.com/tauri-apps/muda/pull/53)) on 2023-03-06 +- On Windows, The `Close` predefined menu item will send `WM_CLOSE` to the window instead of calling `DestroyWindow` to let the developer catch this event and decide whether to close the window or not. + - [f322ad4](https://www.github.com/tauri-apps/muda/commit/f322ad454dcd206e2802bb7c65f0a55616a8d002) fix(Windows): send `WM_CLOSE` instead of `DestroyWindow` ([#55](https://www.github.com/tauri-apps/muda/pull/55)) on 2023-03-06 + +## \[0.4.3] + +- Implement `PredefinedMenuItemm::maximize` and `PredefinedMenuItemm::hide` on Windows. + - [d2bd85b](https://www.github.com/tauri-apps/muda/commit/d2bd85bf7ec4b0bc974d487adaacb6a99b82fa91) docs: add docs for `PredefinedMenuItem` ([#51](https://www.github.com/tauri-apps/muda/pull/51)) on 2023-02-28 +- Add docs for predefined menu items + - [d2bd85b](https://www.github.com/tauri-apps/muda/commit/d2bd85bf7ec4b0bc974d487adaacb6a99b82fa91) docs: add docs for `PredefinedMenuItem` ([#51](https://www.github.com/tauri-apps/muda/pull/51)) on 2023-02-28 + +## \[0.4.2] + +- Fix panic when updating a `CheckMenuItem` right after it was clicked. + - [923af09](https://www.github.com/tauri-apps/muda/commit/923af09abfe885995ae0a4ef30f8a304cc4c20d2) fix(linux): fix multiple borrow panic ([#48](https://www.github.com/tauri-apps/muda/pull/48)) on 2023-02-14 + +## \[0.4.1] + +- Update docs + - [4b2ebc2](https://www.github.com/tauri-apps/muda/commit/4b2ebc247cfef64bcaab2ab619e30b65db37a72f) docs: update docs on 2023-02-08 + +## \[0.4.0] + +- Bump gtk version: 0.15 -> 0.16 + - [fb3d0aa](https://www.github.com/tauri-apps/muda/commit/fb3d0aa303a0ee4ffff6d3de97cc363f1ef6d34b) chore(deps): bump gtk version 0.15 -> 0.16 ([#38](https://www.github.com/tauri-apps/muda/pull/38)) on 2023-01-26 + +## \[0.3.0] + +- Add `MenuEvent::set_event_handler` to set a handler for new menu events. + - [f871c68](https://www.github.com/tauri-apps/muda/commit/f871c68e81aa10f9541c386615a05a2e455e5a82) refactor: allow changing the menu event sender ([#35](https://www.github.com/tauri-apps/muda/pull/35)) on 2023-01-03 +- **Breaking change** Remove `menu_event_receiver` function, use `MenuEvent::receiver` instead. + - [f871c68](https://www.github.com/tauri-apps/muda/commit/f871c68e81aa10f9541c386615a05a2e455e5a82) refactor: allow changing the menu event sender ([#35](https://www.github.com/tauri-apps/muda/pull/35)) on 2023-01-03 + +## \[0.2.0] + +- Add `IconMenuItem` + - [7fc1b02](https://www.github.com/tauri-apps/muda/commit/7fc1b02cac65f2524220cb79263643505e286863) feat: add `IconMenuItem`, closes [#30](https://www.github.com/tauri-apps/muda/pull/30) ([#32](https://www.github.com/tauri-apps/muda/pull/32)) on 2022-12-30 + +## \[0.1.1] + +- Derive `Copy` for `Accelerator` type. + - [e80c113](https://www.github.com/tauri-apps/muda/commit/e80c113d8c8db8137f97829b071b443772d4805c) feat: derive `Copy` for `Accelerator` on 2022-12-12 +- Fix parsing one letter string as valid accelerator without modifiers. + - [0173987](https://www.github.com/tauri-apps/muda/commit/0173987ed5da605ddc20e49fce57ba884ed0d5f4) fix: parse one letter string to valid accelerator ([#28](https://www.github.com/tauri-apps/muda/pull/28)) on 2022-12-20 + +## \[0.1.0] + +- Initial Release. + - [0309d10](https://www.github.com/tauri-apps/muda/commit/0309d101b16663ce67b518f8aa1d2c4af0de6dee) chore: prepare for first release on 2022-12-05 diff --git a/ports/muda/Cargo.lock b/ports/muda/Cargo.lock new file mode 100644 index 000000000000..06058496eec1 --- /dev/null +++ b/ports/muda/Cargo.lock @@ -0,0 +1,3928 @@ +# This file is automatically @generated by Cargo. +# 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 = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[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.13.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 = "arc-swap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" +dependencies = [ + "rustversion", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[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 = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +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 0.6.4", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" + +[[package]] +name = "cairo-rs" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc8d9aa793480744cd9a0524fef1a2e197d9eaa0f739cde19d16aba530dcb95" +dependencies = [ + "bitflags 2.13.0", + "cairo-sys-rs", + "glib", + "libc", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8b4985713047f5faee02b8db6a6ef32bbb50269ff53c1aee716d1d195b76d54" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.13.0", + "log", + "polling", + "rustix 0.38.44", + "slab", + "thiserror 1.0.69", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop", + "rustix 0.38.44", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "cc" +version = "1.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-expr" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb693542bcafa528e198be0ebd9d3632ca5b7c93dbe7237460e199910835997c" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +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 0.1.3", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" +dependencies = [ + "bitflags 2.13.0", + "core-foundation 0.10.1", + "core-graphics-types 0.2.0", + "foreign-types", + "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 = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.13.0", + "core-foundation 0.10.1", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a2a99df6e410a8ff4245aa2006499ea662245f967cc7c0a38c83ef8eb44dbf" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "cursor-icon" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" + +[[package]] +name = "dbus" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.13.0", + "block2 0.6.2", + "libc", + "objc2 0.6.4", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dlib" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" +dependencies = [ + "libloading", +] + +[[package]] +name = "dlopen2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dom_query" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac5fca71e65e94cc718a6e2af65d6e0f9c6027751c2aa562fbb5087fda639bc" +dependencies = [ + "bit-set", + "cssparser", + "foldhash", + "html5ever", + "precomputed-hash", + "selectors", + "tendril", +] + +[[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" +dependencies = [ + "serde", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[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 = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f420376dbee041b2db374ce4573892a36222bb3f6c0c43e24f0d67eae9b646" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f31b37b1fc4b48b54f6b91b7ef04c18e00b4585d98359dd7b998774bbd91fb" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk4" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d81e2a6c6ecba2aab60633a98df1868b03fa0bfdce8105edc27c1bccf71f0e39" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk4-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk4-sys" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d8f608d8d7d229975c4d0d026f5d3071598c4ddab3c5262b0a31840fec78d13" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdk4-wayland" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d95828dadc0357dee236cc6a5712808bd894d3217159982592ce24f2b8aaf7" +dependencies = [ + "gdk4", + "gdk4-wayland-sys", + "gio", + "glib", + "libc", + "wayland-backend", + "wayland-client", + "wayland-protocols", +] + +[[package]] +name = "gdk4-wayland-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653cafb8715f2ac1c56edaf8060d9360ae3acbe3c6fb61b676a2917d42b668cf" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk4-x11" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d892b4cf5a07e90e1390e93cd792975746c68b59f790a2de9e96ce77211ea9a" +dependencies = [ + "gdk4", + "gdk4-x11-sys", + "gio", + "glib", + "libc", +] + +[[package]] +name = "gdk4-x11-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d41f2e28f62378b081288914325d73bddbb6ccbbadb41aa6392afc71d27002" +dependencies = [ + "gdk4-sys", + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "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 = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "gio" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b3e1f669909c326b9413bde5a742097b8c90a7d78f45326db13668984769ded" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "pin-project-lite", + "smallvec", +] + +[[package]] +name = "gio-sys" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353fdc7da7cd16da916104b1e0e4e7de380ec9c8aaa20d4d742d66310ab4b0d5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "windows-sys 0.61.2", +] + +[[package]] +name = "glib" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddbcf514bd1881fc1b960e4e52b4e82873f4da3bceddbd58d42827b508888100" +dependencies = [ + "bitflags 2.13.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "smallvec", +] + +[[package]] +name = "glib-macros" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "506d23499707c7142898429757e8d9a3871d965239a2cb66dfa05052be6d6f19" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "glib-sys" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030967459f9f676851872c6304adea7825c6d462ec9b72554c733cf0c5952233" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "gobject-sys" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a861859b887a79cf461359c192c97a57d8fb0229dd291232e57aa11f6fa72c" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "graphene-rs" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb856b9c558971c3f13ab692358926da710b046932a4e087aedcc35b040d7dff" +dependencies = [ + "glib", + "graphene-sys", +] + +[[package]] +name = "graphene-sys" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ffdfde88f3570d3705e0d8a2433e036d387a1f2930bbf47eafcb5f569fd04" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gsk4" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b867be1c5f14dcb8f552c0eff6e9a9b1da5f8b43943e8efc3a63c889d84952ff" +dependencies = [ + "cairo-rs", + "gdk4", + "glib", + "graphene-rs", + "gsk4-sys", + "libc", + "pango", +] + +[[package]] +name = "gsk4-sys" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b7c7eb2e681ee896646cfb8872b431f24d09f53ba9283289d9b10caa6707088" +dependencies = [ + "cairo-sys-rs", + "gdk4-sys", + "glib-sys", + "gobject-sys", + "graphene-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk4" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98a0a0466484f64b07b5b8184d43fa46be78eb0b8e04ae4e179af31d770b76d9" +dependencies = [ + "cairo-rs", + "field-offset", + "futures-channel", + "gdk-pixbuf", + "gdk4", + "gio", + "glib", + "graphene-rs", + "gsk4", + "gtk4-macros", + "gtk4-sys", + "libc", + "pango", +] + +[[package]] +name = "gtk4-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac7179400a36a04de039c24206bb841c5596992b907b43b23ee8d5bdc40d00e" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "gtk4-sys" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f954786af0b1984425c4446b77f5ff6594346181316be3f850caab1c6f01" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk4-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "graphene-sys", + "gsk4-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "html5ever" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" +dependencies = [ + "log", + "markup5ever", +] + +[[package]] +name = "http" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "png", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "javascriptcore6" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d8d4f64d976c6dc6068723b6ef7838acf954d56b675f376c826f7e773362ddb" +dependencies = [ + "glib", + "javascriptcore6-sys", + "libc", +] + +[[package]] +name = "javascriptcore6-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b9787581c8949a7061c9b8593c4d1faf4b0fe5e5643c6c7793df20dbe39cf6" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[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.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.13.0", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link 0.2.1", +] + +[[package]] +name = "libredox" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" +dependencies = [ + "bitflags 2.13.0", + "libc", + "plain", + "redox_syscall 0.9.0", +] + +[[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.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "markup5ever" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +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 = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "muda" +version = "0.19.3" +dependencies = [ + "arc-swap", + "crossbeam-channel", + "dpi", + "gtk4", + "image", + "keyboard-types", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "once_cell", + "png", + "serde", + "tao", + "thiserror 2.0.18", + "windows-sys 0.61.2", + "winit", + "wry", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.13.0", + "jni-sys 0.3.1", + "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.1", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +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", + "objc2-exception-helper", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.13.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.13.0", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 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.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location 0.2.2", + "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.13.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.13.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 = [ + "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.13.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.13.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", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-contacts", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.13.0", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-exception-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.13.0", + "block2 0.5.1", + "dispatch", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.13.0", + "block2 0.6.2", + "objc2 0.6.4", + "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.13.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.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.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.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.13.0", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 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.13.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 0.2.2", + "objc2-foundation 0.2.2", + "objc2-link-presentation", + "objc2-quartz-core 0.2.2", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications 0.2.2", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.13.0", + "block2 0.6.2", + "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-location 0.3.2", + "objc2-core-text", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", + "objc2-user-notifications 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.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-web-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" +dependencies = [ + "bitflags 2.13.0", + "block2 0.6.2", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "orbclient" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df339f526ea9a60e371768d50efc2f2508c7203290731565d1f7a6f71d21747" +dependencies = [ + "libc", + "libredox", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "pango" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d800d8d0de2ad5d0fb046f5344dbaba14a003cf3dd27cc21d85893d35ea316c" +dependencies = [ + "gio", + "glib", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd111a20ca90fedf03e09c59783c679c00900f1d8491cca5399f5e33609d5d6" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.13.0", + "crc32fast", + "fdeflate", + "flate2", + "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", + "pin-project-lite", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "quick-xml" +version = "0.39.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.0", +] + +[[package]] +name = "redox_syscall" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5102a6aaa05aa011a238e178e6bca86d2cb56fc9f586d37cb80f5bca6e07759" +dependencies = [ + "bitflags 2.13.0", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.13.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.13.0", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[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", + "tiny-skia", +] + +[[package]] +name = "selectors" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adfa1c298912827b8a28b223b3b874357397ae706e6190acd9bf28cee99114d" +dependencies = [ + "bitflags 2.13.0", + "cssparser", + "derive_more", + "log", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "rustc-hash", + "servo_arc", + "smallvec", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "servo_arc" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[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 = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.13.0", + "calloop", + "calloop-wayland-source", + "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 = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "soup3" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d38b59ff6d302538efd337e15d04d61c5b909ec223c60ae4061d74605a962a" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79d5d25225bb06f83b78ff8cc35973b56d45fcdd21af6ed6d2bbd67f5a6f9bea" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "string_cache" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "string_cache_codegen" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", +] + +[[package]] +name = "syn" +version = "2.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-deps" +version = "7.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.35.3" +dependencies = [ + "async-channel", + "bitflags 2.13.0", + "block2 0.6.2", + "core-foundation 0.10.1", + "core-graphics 0.25.0", + "crossbeam-channel", + "dbus", + "dispatch2", + "dlopen2", + "dpi", + "gdk4-wayland", + "gdk4-x11", + "gtk4", + "jni 0.21.1", + "libc", + "log", + "ndk", + "ndk-sys", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", + "objc2-ui-kit 0.3.2", + "once_cell", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "tao-macros 0.1.3", + "unicode-segmentation", + "url", + "windows", + "windows-core", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + +[[package]] +name = "tendril" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" +dependencies = [ + "new_debug_unreachable", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" +dependencies = [ + "num-conv", + "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", + "tiny-skia-path", +] + +[[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]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +dependencies = [ + "unicode-ident", +] + +[[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.13.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.13.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.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" +dependencies = [ + "bitflags 2.13.0", + "wayland-backend", + "wayland-client", + "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.13.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.13.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", + "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-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web_atoms" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075474b12bcb3d2e3d4546580e9de478eeeead668a1761e2a8860c836b7ef297" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + +[[package]] +name = "webkit6" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4959dd2a92813d4b2ae134e71345a03030bcff189b4f79cd131e9218aba22b70" +dependencies = [ + "gdk4", + "gio", + "glib", + "gtk4", + "javascriptcore6", + "libc", + "soup3", + "webkit6-sys", +] + +[[package]] +name = "webkit6-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "236078ce03ff041bf87904c8257e6a9b0e9e0f957267c15f9c1756aadcf02581" +dependencies = [ + "gdk4-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk4-sys", + "javascriptcore6-sys", + "libc", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webview2-com" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows-core", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "webview2-com-sys" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" +dependencies = [ + "thiserror 2.0.18", + "windows", + "windows-core", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link 0.1.3", +] + +[[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-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[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-version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[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.13.0", + "block2 0.5.1", + "bytemuck", + "calloop", + "cfg_aliases", + "concurrent-queue", + "core-foundation 0.9.4", + "core-graphics 0.23.2", + "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", + "smol_str", + "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 = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wry" +version = "0.55.1" +dependencies = [ + "base64", + "block2 0.6.2", + "cookie", + "crossbeam-channel", + "dirs", + "dom_query", + "dpi", + "dunce", + "gtk4", + "http", + "jni 0.21.1", + "libc", + "ndk", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-ui-kit 0.3.2", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.18", + "url", + "webkit6", + "webview2-com", + "windows", + "windows-core", + "windows-version", +] + +[[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", + "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 = "xcursor" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.13.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 = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/ports/muda/Cargo.toml b/ports/muda/Cargo.toml new file mode 100644 index 000000000000..fefa059ceb90 --- /dev/null +++ b/ports/muda/Cargo.toml @@ -0,0 +1,88 @@ +[package] +name = "muda" +version = "0.19.3" +description = "Menu Utilities for Desktop Applications" +edition = "2021" +keywords = ["windowing", "menu"] +license = "Apache-2.0 OR MIT" +readme = "README.md" +repository = "https://github.com/tauri-apps/muda" +documentation = "https://docs.rs/muda" +categories = ["gui"] +rust-version = "1.92" +include = ["README.md", "src/**/*.rs", "Cargo.toml", "LICENSE-APACHE", "LICENSE-MIT", "LICENSE.spdx"] + +[features] +default = ["libxdo", "gtk"] +# No-op on GTK4: libxdo is X11-only. The feature name stays for compatibility. +libxdo = [] +gtk = ["dep:gtk", "dep:png"] +linux-ksni = ["gtk", "dep:arc-swap"] +common-controls-v6 = [] +serde = ["dep:serde", "dpi/serde", "keyboard-types/serde"] + +[dependencies] +arc-swap = { version = "1.7.1", optional = true } +crossbeam-channel = "0.5" +keyboard-types = "0.7" +once_cell = "1" +thiserror = "2" +serde = { version = "1", optional = true } +dpi = "0.1" + +[target.'cfg(target_os = "windows")'.dependencies.windows-sys] +version = ">=0.60, <=0.61" +features = [ + "Win32_UI_WindowsAndMessaging", + "Win32_Foundation", + "Win32_Graphics_Gdi", + "Win32_UI_Shell", + "Win32_Globalization", + "Win32_UI_Input_KeyboardAndMouse", + "Win32_System_SystemServices", + "Win32_UI_Accessibility", + "Win32_UI_HiDpi", + "Win32_System_LibraryLoader", + "Win32_UI_Controls", +] + +[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))'.dependencies] +gtk = { package = "gtk4", version = "0.11", optional = true } +png = { version = "0.18", optional = true } + +[target.'cfg(target_os = "macos")'.dependencies] +objc2 = "0.6.1" +objc2-core-foundation = { version = "0.3.0", default-features = false, features = [ + "std", + "CFCGTypes", +] } +objc2-foundation = { version = "0.3.0", default-features = false, features = [ + "std", + "NSAttributedString", + "NSData", + "NSDictionary", + "NSGeometry", + "NSString", + "NSThread", +] } +objc2-app-kit = { version = "0.3.0", default-features = false, features = [ + "std", + "objc2-core-foundation", + "NSApplication", + "NSCell", + "NSEvent", + "NSImage", + "NSMenu", + "NSMenuItem", + "NSResponder", + "NSRunningApplication", + "NSView", + "NSWindow", +] } +png = "0.18" + +[dev-dependencies] +winit = "0.30" +tao = { path = "../tao" } +wry = { path = "../wry" } +image = { version = "0.25", default-features = false, features = ["png"] } diff --git a/ports/muda/LICENSE-APACHE b/ports/muda/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/ports/muda/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/ports/muda/LICENSE-MIT b/ports/muda/LICENSE-MIT new file mode 100644 index 000000000000..da5faffb87e7 --- /dev/null +++ b/ports/muda/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2022 Tauri Programme within The Commons Conservancy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ports/muda/LICENSE.spdx b/ports/muda/LICENSE.spdx new file mode 100644 index 000000000000..987162a83b89 --- /dev/null +++ b/ports/muda/LICENSE.spdx @@ -0,0 +1,19 @@ +SPDXVersion: SPDX-2.1 +DataLicense: CC0-1.0 +PackageName: muda +DataFormat: SPDXRef-1 +PackageSupplier: Organization: The Tauri Programme in the Commons Conservancy +PackageHomePage: https://tauri.app +PackageLicenseDeclared: Apache-2.0 +PackageLicenseDeclared: MIT +PackageCopyrightText: 2020-2022, The Tauri Programme in the Commons Conservancy +PackageSummary: Menu Utilities for Desktop Applications. + +PackageComment: The package includes the following libraries; see +Relationship information. + +Created: 2022-12-05T09:00:00Z +PackageDownloadLocation: git://github.com/tauri-apps/muda +PackageDownloadLocation: git+https://github.com/tauri-apps/muda.git +PackageDownloadLocation: git+ssh://github.com/tauri-apps/muda.git +Creator: Person: Daniel Thompson-Yvetot \ No newline at end of file diff --git a/ports/muda/README.md b/ports/muda/README.md new file mode 100644 index 000000000000..a72c5cb95717 --- /dev/null +++ b/ports/muda/README.md @@ -0,0 +1,142 @@ +### muda + +Menu Utilities library for Desktop Applications. + +[![Documentation](https://img.shields.io/docsrs/muda)](https://docs.rs/muda/latest/muda/) + +## Platforms supported: + +- Windows +- macOS +- Linux (gtk Only) +- FreeBSD (gtk Only) + +## Platform-specific notes: + +- On Windows, accelerators don't work unless the win32 message loop calls + [`TranslateAcceleratorW`](https://docs.rs/windows-sys/latest/windows_sys/Win32/UI/WindowsAndMessaging/fn.TranslateAcceleratorW.html). + See [`Menu::init_for_hwnd`](https://docs.rs/muda/latest/x86_64-pc-windows-msvc/muda/struct.Menu.html#method.init_for_hwnd) for more details + +### Cargo Features + +- `common-controls-v6`: Use `TaskDialogIndirect` API from `ComCtl32.dll` v6 on Windows for showing the predefined `About` menu item dialog. +- `libxdo`: Enables linking to `libxdo` on Linux or FreeBSD which is used for the predefined `Copy`, `Cut`, `Paste` and `SelectAll` menu item. +- `serde`: Enables de/serializing the dpi types. +- `gtk`: Enables the `gtk` crate dependency on Linux or FreeBSD. This is required for `muda` to function properly on Linux or FreeBSD. + +## Dependencies (Linux Only) + +`gtk` is used for menus and `libxdo` is used to make the predefined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work. Be sure to install following packages before building: + +#### Arch Linux / Manjaro: + +```sh +pacman -S gtk3 xdotool +``` + +#### Debian / Ubuntu: + +```sh +sudo apt install libgtk-3-dev libxdo-dev +``` + +## Dependencies in FreeBSD + +Install this dependencies in order to compile `muda`. Instructions using `pkg`: + +```sh +pkg install -y rust glib pkgconf gtk3 +``` + +## Example + +Create the menu and add your items + +```rs +let menu = Menu::new(); +let menu_item2 = MenuItem::new("Menu item #2", false, None); +let submenu = Submenu::with_items("Submenu Outer", true,&[ + &MenuItem::new("Menu item #1", true, Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyD))), + &PredefinedMenuItem::separator(), + &menu_item2, + &MenuItem::new("Menu item #3", true, None), + &PredefinedMenuItem::separator(), + &Submenu::with_items("Submenu Inner", true,&[ + &MenuItem::new("Submenu item #1", true, None), + &PredefinedMenuItem::separator(), + &menu_item2, + ]) +]); + +``` + +Then add your root menu to a Window on Windows and Linux +or use it as your global app menu on macOS + +```rs +// --snip-- +#[cfg(target_os = "windows")] +unsafe { menu.init_for_hwnd(window.hwnd() as isize) }; +#[cfg(target_os = "linux")] +menu.init_for_gtk_window(>k_window, Some(&vertical_gtk_box)); +#[cfg(target_os = "macos")] +menu.init_for_nsapp(); +``` + +## Context menus (Popup menus) + +You can also use a [`Menu`] or a [`Submenu`] show a context menu. + +```rs +// --snip-- +let position = muda::PhysicalPosition { x: 100., y: 120. }; +#[cfg(target_os = "windows")] +unsafe { menu.show_context_menu_for_hwnd(window.hwnd() as isize, Some(position.into())) }; +#[cfg(target_os = "linux")] +menu.show_context_menu_for_gtk_window(>k_window, Some(position.into())); +#[cfg(target_os = "macos")] +unsafe { menu.show_context_menu_for_nsview(nsview, Some(position.into())) }; +``` + +## Processing menu events + +You can use `MenuEvent::receiver` to get a reference to the `MenuEventReceiver` +which you can use to listen to events when a menu item is activated + +```rs +if let Ok(event) = MenuEvent::receiver().try_recv() { + match event.id { + _ if event.id == save_item.id() => { + println!("Save menu item activated"); + }, + _ => {} + } +} +``` + +### Note for [winit] or [tao] users: + +You should use [`MenuEvent::set_event_handler`] and forward +the menu events to the event loop by using [`EventLoopProxy`] +so that the event loop is awakened on each menu event. + +```rust +enum UserEvent { + MenuEvent(muda::MenuEvent) +} + +let event_loop = EventLoop::::with_user_event().build().unwrap(); + +let proxy = event_loop.create_proxy(); +muda::MenuEvent::set_event_handler(Some(move |event| { + proxy.send_event(UserEvent::MenuEvent(event)); +})); +``` + +[`EventLoopProxy`]: https://docs.rs/winit/latest/winit/event_loop/struct.EventLoopProxy.html +[winit]: https://docs.rs/winit +[tao]: https://docs.rs/tao + +## License + +Apache-2.0/MIT diff --git a/ports/muda/examples/gtk.rs b/ports/muda/examples/gtk.rs new file mode 100644 index 000000000000..95345f0e7427 --- /dev/null +++ b/ports/muda/examples/gtk.rs @@ -0,0 +1,97 @@ +#[cfg(target_os = "linux")] +use gtk::prelude::*; +#[cfg(target_os = "linux")] +use keyboard_types::{Code, Modifiers}; +#[cfg(target_os = "linux")] +use muda::{accelerator::Accelerator, MenuEvent}; + +#[cfg(target_os = "linux")] +fn main() { + // Create a new application + let application = gtk::Application::builder() + .application_id("com.github.gtk4-rs.examples.menubar") + .build(); + application.connect_startup(on_startup); + application.connect_activate(on_activate); + application.run(); +} + +#[cfg(target_os = "linux")] +fn on_startup(_: >k::Application) { + MenuEvent::set_event_handler(Some(|event| { + println!("{event:?}"); + })); +} + +#[cfg(target_os = "linux")] +fn on_activate(application: >k::Application) { + use muda::ContextMenu; + + let window = gtk::ApplicationWindow::builder() + .application(application) + .title("Menubar Example") + .default_width(350) + .default_height(350) + .show_menubar(true) + .build(); + + window.present(); + + let about_menu_item = muda::MenuItem::new("About", true, None); + + let check = muda::CheckMenuItem::new( + "Check", + true, + true, + Some(Accelerator::new(Some(Modifiers::empty()), Code::KeyQ)), + ); + + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); + let icon = load_icon(std::path::Path::new(path)); + let icon_menu_item = muda::IconMenuItem::new("Icon", true, Some(icon), None); + + let quit_menu_item = muda::MenuItem::with_id( + "quit", + "&Quit", + true, + Some(Accelerator::new(Some(Modifiers::CONTROL), Code::KeyQ)), + ); + + let file_menu = muda::Submenu::new("&File", true); + file_menu.append(&about_menu_item).unwrap(); + file_menu.append(&check).unwrap(); + file_menu.append(&icon_menu_item).unwrap(); + file_menu.append(&quit_menu_item).unwrap(); + + let menubar = muda::Menu::new(); + menubar.append(&file_menu).unwrap(); + + let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0); + menubar.init_for_gtk_window(&window, Some(&vbox)).unwrap(); + + let btn = gtk::Button::with_label("ASdasd"); + let w = window.clone(); + + btn.connect_clicked(move |_| { + file_menu.show_context_menu_for_gtk_window(w.dynamic_cast_ref().unwrap(), None); + }); + vbox.append(&btn); + + window.set_child(Some(&vbox)); +} + +#[cfg(not(target_os = "linux"))] +fn main() {} + +#[cfg(target_os = "linux")] +fn load_icon(path: &std::path::Path) -> muda::Icon { + let (icon_rgba, icon_width, icon_height) = { + let image = image::open(path) + .expect("Failed to open icon path") + .into_rgba8(); + let (width, height) = image.dimensions(); + let rgba = image.into_raw(); + (rgba, width, height) + }; + muda::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") +} diff --git a/ports/muda/examples/icon.png b/ports/muda/examples/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3c3627c36d15b6ae0c04f882a6b59a339f58befd GIT binary patch literal 1481 zcmV;)1vdJLP)O(Y>E8jVW~N@9%Bs8NXt zafw8uxItV#xWpyI^@AV8XpnJZT1u55R!QHRwxJbK46+Vg=Dp(wrqerbrVHr#cF*~r z^Z&oQynC*2Hl`}hE_V(-&1%UEQLR)YjnXUV4!757=LYd7QcBK*cYb?&$&sO{cZujd zK;0P7-w|FdOAl`9SYChPe-Yrcb;MD!z|G8FQG z6mT4<030A1!VIa%ov8-<-Ln!<+m>2r1;IC2f?;z}p3Rg;Kk1oQb7a_ApXjI@h?TBJ zc_cJbzN)NBHQ8UBk$~y#2P$Hjbcdibjf~ea>F5JJ%WL{a%UhO6MEhb@PXg- zdTGz1nu8`bJY9Jf%cR%kk;6+~gLD5_IRM`*U!DOTwRgHFP&Q=UQ=>s<18|3l9d!om zt!^3T(gh?%bem7)$F4=SKOqu~Cm^p*tNRtOGCLenU#e0|?7xQNqs~BPS~M0to|)@4 zJBP+1s7m(6%1Q>}fz5W(ofod9NYWV8o3Vl=n3?D-0oL-zi_ zvQ~CA#5)TLa{8=KZ$Gf2B6IRSU_Qz(L5cNZ--7B>CaylwQ8|D%kCc@kiwYpZ6KHOw zPWcj9)!k5Alzi9@ESR1Ko*oM`P*J)T&23afb*mY-0OGs6Stv^ll^eSoYkwZA@I)-0 z^lX&J4A)+-(f-!NL;=KCbKM7JP&bE*RV904<4Kown3kxnKRm*PmZbJMQ zfb&QEZ1I|$&%#12084}F98P3k7}Q%;a|*LcDu%8LW8*thUn0DpM-JbmOD3%i zV{-!3l9A0AP;kv!5?oj;IZ$g_*eB?DA=jsojDKx*!xq?SV&%9|;es$o1Noi^gFvat zFM)0^z#`{om$Mgm+-tDk4zIgu!#|>54Bui@^R8)ciIY;1wZO@&s~@;Gd(q@6)=0xo=NFb6@M^tv$cEs?Z%1r_CW5fpeplGmH}61%A$_hGZr%o;O9AW zPAc-c;a^}^d(Tan9I$tK>ot(wC~p9_03VJ=4n|96x4Kgl*(c~UBRXyantiN1C87@- zd56mU!Am+8*B_p+0DySXTPzXXj#6eIQUp8`Zox19Vc%pw8d=Th&i68-%#ey)oocWP zPRO_d0PGfb6~YJPzXJdQpbI$4>AeyMBB5#n1l;B|IUh}gyr=-kJx1OE3i`k?%u|)y zQ%&}cGsr346Lu|%@8U4?MD;#|)HpS|6?rIgDth^ulEXyahN@E6);Ze`BF%!::with_user_event(); + + let menu_bar = Menu::new(); + + // setup accelerator handler on Windows + #[cfg(target_os = "windows")] + { + let menu_bar = menu_bar.clone(); + event_loop_builder.with_msg_hook(move |msg| { + use windows_sys::Win32::UI::WindowsAndMessaging::{TranslateAcceleratorW, MSG}; + unsafe { + let msg = msg as *const MSG; + let translated = TranslateAcceleratorW((*msg).hwnd, menu_bar.haccel() as _, msg); + translated == 1 + } + }); + } + + let event_loop = event_loop_builder.build(); + + // set a menu event handler that wakes up the event loop + let proxy = event_loop.create_proxy(); + muda::MenuEvent::set_event_handler(Some(move |event| { + proxy.send_event(UserEvent::MenuEvent(event)); + })); + + let window = WindowBuilder::new() + .with_title("Window 1") + .build(&event_loop) + .unwrap(); + let window2 = WindowBuilder::new() + .with_title("Window 2") + .build(&event_loop) + .unwrap(); + + #[cfg(target_os = "macos")] + { + let app_m = Submenu::new("App", true); + menu_bar.append(&app_m); + app_m.append_items(&[ + &PredefinedMenuItem::about(None, None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::services(None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::hide(None), + &PredefinedMenuItem::hide_others(None), + &PredefinedMenuItem::show_all(None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::quit(None), + ]); + } + + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); + let icon = load_icon(std::path::Path::new(path)); + + let file_m = Submenu::new("&File", true); + let edit_m = Submenu::new("&Edit", true); + let window_m = Submenu::new("&Window", true); + let help_m = Submenu::new("&Custom Help", true); + + window_m.set_icon(Some(icon.clone())); + + menu_bar.append_items(&[&file_m, &edit_m, &window_m, &help_m]); + + let custom_i_1 = MenuItem::with_id( + "custom-i-1", + "C&ustom 1", + true, + Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyC)), + ); + + let image_item = IconMenuItem::with_id( + "image-custom-1", + "Image custom 1", + true, + Some(icon), + Some(Accelerator::new(Some(Modifiers::CONTROL), Code::KeyC)), + ); + + let check_custom_i_1 = + CheckMenuItem::with_id("check-custom-1", "Check Custom 1", true, true, None); + let check_custom_i_2 = + CheckMenuItem::with_id("check-custom-2", "Check Custom 2", false, true, None); + let check_custom_i_3 = CheckMenuItem::with_id( + "check-custom-3", + "Check Custom 3", + true, + true, + Some(Accelerator::new(Some(Modifiers::SHIFT), Code::KeyD)), + ); + + let copy_i = PredefinedMenuItem::copy(None); + let cut_i = PredefinedMenuItem::cut(None); + let paste_i = PredefinedMenuItem::paste(None); + + file_m.append_items(&[ + &custom_i_1, + &image_item, + &window_m, + &PredefinedMenuItem::separator(), + &check_custom_i_1, + &check_custom_i_2, + ]); + + window_m.append_items(&[ + &PredefinedMenuItem::minimize(None), + &PredefinedMenuItem::maximize(None), + &PredefinedMenuItem::close_window(Some("Close")), + &PredefinedMenuItem::fullscreen(None), + &PredefinedMenuItem::bring_all_to_front(None), + &PredefinedMenuItem::about( + None, + Some(AboutMetadata { + name: Some("tao".to_string()), + version: Some("1.2.3".to_string()), + copyright: Some("Copyright tao".to_string()), + ..Default::default() + }), + ), + &check_custom_i_3, + &image_item, + &custom_i_1, + ]); + + help_m.append_items(&[&MenuItem::new("Supposed to show search", true, None)]); + + edit_m.append_items(&[©_i, &PredefinedMenuItem::separator(), &paste_i]); + + #[cfg(target_os = "windows")] + unsafe { + menu_bar.init_for_hwnd(window.hwnd() as _); + menu_bar.init_for_hwnd(window2.hwnd() as _); + } + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + // Pending a tao release on gtk4; muda's gtk API now takes gtk4 types. + // menu_bar.init_for_gtk_window(window.gtk_window(), window.default_vbox()); + // menu_bar.init_for_gtk_window(window2.gtk_window(), window2.default_vbox()); + let _ = (&menu_bar, &window, &window2); + } + #[cfg(target_os = "macos")] + { + menu_bar.init_for_nsapp(); + window_m.set_as_windows_menu_for_nsapp(); + help_m.set_as_help_menu_for_nsapp(); + } + + let menu_channel = MenuEvent::receiver(); + let mut window_cursor_position = PhysicalPosition { x: 0., y: 0. }; + let mut use_window_pos = false; + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + Event::WindowEvent { + event: WindowEvent::CursorMoved { position, .. }, + window_id, + .. + } => { + window_cursor_position.x = position.x; + window_cursor_position.y = position.y; + } + Event::WindowEvent { + event: + WindowEvent::MouseInput { + state: ElementState::Released, + button: MouseButton::Right, + .. + }, + window_id, + .. + } => { + show_context_menu( + if window_id == window.id() { + &window + } else { + &window2 + }, + &file_m, + if use_window_pos { + Some(window_cursor_position.into()) + } else { + None + }, + ); + use_window_pos = !use_window_pos; + } + Event::MainEventsCleared => { + window.request_redraw(); + } + + Event::UserEvent(UserEvent::MenuEvent(event)) => { + if event.id == custom_i_1.id() { + file_m.insert(&MenuItem::new("New Menu Item", true, None), 2); + } + println!("{event:?}"); + } + _ => (), + } + }) +} + +fn show_context_menu(window: &Window, menu: &dyn ContextMenu, position: Option) { + println!("Show context menu at position {position:?}"); + #[cfg(target_os = "windows")] + unsafe { + menu.show_context_menu_for_hwnd(window.hwnd() as _, position); + } + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + // Pending a tao release on gtk4; muda's gtk API now takes gtk4 types. + // menu.show_context_menu_for_gtk_window(window.gtk_window().as_ref(), position); + let _ = (window, menu, position); + } + #[cfg(target_os = "macos")] + unsafe { + menu.show_context_menu_for_nsview(window.ns_view() as _, position); + } +} + +fn load_icon(path: &std::path::Path) -> muda::Icon { + let (icon_rgba, icon_width, icon_height) = { + let image = image::open(path) + .expect("Failed to open icon path") + .into_rgba8(); + let (width, height) = image.dimensions(); + let rgba = image.into_raw(); + (rgba, width, height) + }; + muda::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") +} diff --git a/ports/muda/examples/windows-common-controls-v6/.gitignore b/ports/muda/examples/windows-common-controls-v6/.gitignore new file mode 100644 index 000000000000..869df07dae8b --- /dev/null +++ b/ports/muda/examples/windows-common-controls-v6/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock \ No newline at end of file diff --git a/ports/muda/examples/windows-common-controls-v6/Cargo.toml b/ports/muda/examples/windows-common-controls-v6/Cargo.toml new file mode 100644 index 000000000000..f397c825c6df --- /dev/null +++ b/ports/muda/examples/windows-common-controls-v6/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "windows-common-controls-v6" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +muda = { path = "../../", features = ["common-controls-v6"] } +tao = "0.28" +image = "0.25" + +[target."cfg(target_os = \"windows\")".dependencies.windows-sys] +version = "0.59" +features = ["Win32_UI_WindowsAndMessaging", "Win32_Foundation"] + +[build-dependencies] +embed-resource = "2" diff --git a/ports/muda/examples/windows-common-controls-v6/app.exe.manifest b/ports/muda/examples/windows-common-controls-v6/app.exe.manifest new file mode 100644 index 000000000000..d4da5bc09b8d --- /dev/null +++ b/ports/muda/examples/windows-common-controls-v6/app.exe.manifest @@ -0,0 +1,15 @@ + + + + + + + + \ No newline at end of file diff --git a/ports/muda/examples/windows-common-controls-v6/build.rs b/ports/muda/examples/windows-common-controls-v6/build.rs new file mode 100644 index 000000000000..f9b40498929f --- /dev/null +++ b/ports/muda/examples/windows-common-controls-v6/build.rs @@ -0,0 +1,4 @@ +fn main() { + #[cfg(target_os = "windows")] + embed_resource::compile("manifest.rc", embed_resource::NONE); +} diff --git a/ports/muda/examples/windows-common-controls-v6/manifest.rc b/ports/muda/examples/windows-common-controls-v6/manifest.rc new file mode 100644 index 000000000000..6dae79430008 --- /dev/null +++ b/ports/muda/examples/windows-common-controls-v6/manifest.rc @@ -0,0 +1,2 @@ +#define RT_MANIFEST 24 +1 RT_MANIFEST "app.exe.manifest" \ No newline at end of file diff --git a/ports/muda/examples/windows-common-controls-v6/src/main.rs b/ports/muda/examples/windows-common-controls-v6/src/main.rs new file mode 100644 index 000000000000..22959ff64757 --- /dev/null +++ b/ports/muda/examples/windows-common-controls-v6/src/main.rs @@ -0,0 +1,242 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![allow(unused)] +use muda::{ + accelerator::{Accelerator, Code, Modifiers}, + dpi::{PhysicalPosition, Position}, + AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuEvent, MenuItem, + PredefinedMenuItem, Submenu, +}; +#[cfg(target_os = "macos")] +use tao::platform::macos::WindowExtMacOS; +#[cfg(target_os = "windows")] +use tao::platform::windows::{EventLoopBuilderExtWindows, WindowExtWindows}; +use tao::{ + event::{ElementState, Event, MouseButton, WindowEvent}, + event_loop::{ControlFlow, EventLoopBuilder}, + window::{Window, WindowBuilder}, +}; + +fn main() { + let mut event_loop_builder = EventLoopBuilder::new(); + + let menu_bar = Menu::new(); + + #[cfg(target_os = "windows")] + { + let menu_bar = menu_bar.clone(); + event_loop_builder.with_msg_hook(move |msg| { + use windows_sys::Win32::UI::WindowsAndMessaging::{TranslateAcceleratorW, MSG}; + unsafe { + let msg = msg as *const MSG; + let translated = TranslateAcceleratorW((*msg).hwnd, menu_bar.haccel() as _, msg); + translated == 1 + } + }); + } + + let event_loop = event_loop_builder.build(); + + let window = WindowBuilder::new() + .with_title("Window 1") + .build(&event_loop) + .unwrap(); + let window2 = WindowBuilder::new() + .with_title("Window 2") + .build(&event_loop) + .unwrap(); + + #[cfg(target_os = "macos")] + { + let app_m = Submenu::new("App", true); + menu_bar.append(&app_m); + app_m.append_items(&[ + &PredefinedMenuItem::about(None, None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::services(None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::hide(None), + &PredefinedMenuItem::hide_others(None), + &PredefinedMenuItem::show_all(None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::quit(None), + ]); + } + + let file_m = Submenu::new("&File", true); + let edit_m = Submenu::new("&Edit", true); + let window_m = Submenu::new("&Window", true); + + menu_bar.append_items(&[&file_m, &edit_m, &window_m]); + + let custom_i_1 = MenuItem::new( + "C&ustom 1", + true, + Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyC)), + ); + + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); + let icon = load_icon(std::path::Path::new(path)); + + let image_item = IconMenuItem::new("Image Custom 1", true, Some(icon), None); + + let check_custom_i_1 = CheckMenuItem::new("Check Custom 1", true, true, None); + let check_custom_i_2 = CheckMenuItem::new("Check Custom 2", false, true, None); + let check_custom_i_3 = CheckMenuItem::new( + "Check Custom 3", + true, + true, + Some(Accelerator::new(Some(Modifiers::SHIFT), Code::KeyD)), + ); + + let copy_i = PredefinedMenuItem::copy(None); + let cut_i = PredefinedMenuItem::cut(None); + let paste_i = PredefinedMenuItem::paste(None); + + file_m.append_items(&[ + &custom_i_1, + &image_item, + &window_m, + &PredefinedMenuItem::separator(), + &check_custom_i_1, + &check_custom_i_2, + ]); + + window_m.append_items(&[ + &PredefinedMenuItem::minimize(None), + &PredefinedMenuItem::maximize(None), + &PredefinedMenuItem::close_window(Some("Close")), + &PredefinedMenuItem::fullscreen(None), + &PredefinedMenuItem::bring_all_to_front(None), + &PredefinedMenuItem::about( + None, + Some(AboutMetadata { + name: Some("tao".to_string()), + version: Some("1.2.3".to_string()), + copyright: Some("Copyright tao".to_string()), + ..Default::default() + }), + ), + &check_custom_i_3, + &image_item, + &custom_i_1, + ]); + + edit_m.append_items(&[©_i, &PredefinedMenuItem::separator(), &paste_i]); + + #[cfg(target_os = "windows")] + unsafe { + use tao::rwh_06::*; + if let RawWindowHandle::Win32(handle) = window.window_handle().unwrap().as_raw() { + menu_bar.init_for_hwnd(handle.hwnd.get()).unwrap(); + } + if let RawWindowHandle::Win32(handle) = window2.window_handle().unwrap().as_raw() { + menu_bar.init_for_hwnd(handle.hwnd.get()).unwrap(); + } + } + #[cfg(target_os = "macos")] + { + menu_bar.init_for_nsapp(); + window_m.set_as_windows_menu_for_nsapp(); + } + + let menu_channel = MenuEvent::receiver(); + let mut window_cursor_position = PhysicalPosition { x: 0., y: 0. }; + let mut use_window_pos = false; + + event_loop.run(move |event, event_loop, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + Event::WindowEvent { + event: WindowEvent::CursorMoved { position, .. }, + window_id, + .. + } => { + window_cursor_position.x = position.x; + window_cursor_position.y = position.y; + } + Event::WindowEvent { + event: + WindowEvent::MouseInput { + state: ElementState::Pressed, + button: MouseButton::Right, + .. + }, + window_id, + .. + } => { + show_context_menu( + if window_id == window.id() { + &window + } else { + &window2 + }, + &file_m, + if use_window_pos { + Some(window_cursor_position.into()) + } else { + None + }, + ); + use_window_pos = !use_window_pos; + } + _ => (), + } + + if let Ok(event) = menu_channel.try_recv() { + if event.id == custom_i_1.id() { + file_m.insert(&MenuItem::new("New Menu Item", true, None), 2); + } + println!("{event:?}"); + } + }); +} + +fn show_context_menu(window: &Window, menu: &dyn ContextMenu, position: Option) { + println!("Show context menu at position {position:?}"); + #[cfg(target_os = "windows")] + { + use tao::rwh_06::*; + if let RawWindowHandle::Win32(handle) = window.window_handle().unwrap().as_raw() { + unsafe { menu.show_context_menu_for_hwnd(handle.hwnd.get(), position) }; + } + } + + #[cfg(target_os = "macos")] + { + use tao::rwh_06::*; + if let RawWindowHandle::AppKit(handle) = window.window_handle().unwrap().as_raw() { + unsafe { menu.show_context_menu_for_nsview(handle.ns_view.as_ptr() as _, position) }; + } + } + + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + menu.show_context_menu_for_gtk(window.gtk_window().as_ref(), position); + } +} + +fn load_icon(path: &std::path::Path) -> muda::Icon { + let (icon_rgba, icon_width, icon_height) = { + let image = image::open(path) + .expect("Failed to open icon path") + .into_rgba8(); + let (width, height) = image.dimensions(); + let rgba = image.into_raw(); + (rgba, width, height) + }; + muda::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") +} diff --git a/ports/muda/examples/winit.rs b/ports/muda/examples/winit.rs new file mode 100644 index 000000000000..188e9d11cdb5 --- /dev/null +++ b/ports/muda/examples/winit.rs @@ -0,0 +1,299 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![allow(unused)] +use std::collections::HashMap; + +use muda::{ + accelerator::{Accelerator, Code, Modifiers}, + dpi::{PhysicalPosition, Position}, + AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuEvent, MenuItem, + PredefinedMenuItem, Submenu, +}; +#[cfg(target_os = "macos")] +use winit::platform::macos::{EventLoopBuilderExtMacOS, WindowExtMacOS}; +#[cfg(target_os = "windows")] +use winit::platform::windows::{EventLoopBuilderExtWindows, WindowExtWindows}; +#[cfg(any(windows, target_os = "macos"))] +use winit::raw_window_handle::*; +use winit::{ + application::ApplicationHandler, + event::{ElementState, Event, MouseButton, StartCause, WindowEvent}, + event_loop::{ActiveEventLoop, ControlFlow, EventLoop, EventLoopBuilder}, + window::{Window, WindowAttributes, WindowId}, +}; + +enum AppEvent { + MenuEvent(muda::MenuEvent), +} + +fn main() { + let mut event_loop_builder = EventLoop::::with_user_event(); + + let menu_bar = Menu::new(); + + // setup accelerator handler on Windows + #[cfg(target_os = "windows")] + { + let menu_bar = menu_bar.clone(); + event_loop_builder.with_msg_hook(move |msg| { + use windows_sys::Win32::UI::WindowsAndMessaging::{TranslateAcceleratorW, MSG}; + unsafe { + let msg = msg as *const MSG; + let translated = TranslateAcceleratorW((*msg).hwnd, menu_bar.haccel() as _, msg); + translated == 1 + } + }); + } + #[cfg(target_os = "macos")] + event_loop_builder.with_default_menu(false); + + let event_loop = event_loop_builder.build().unwrap(); + + // set a menu event handler that wakes up the event loop + let proxy = event_loop.create_proxy(); + muda::MenuEvent::set_event_handler(Some(move |event| { + proxy.send_event(AppEvent::MenuEvent(event)); + })); + + let mut app = App { + app_menu: AppMenu::new(menu_bar), + windows: HashMap::default(), + cursor_position: PhysicalPosition::new(0., 0.), + use_window_pos: false, + }; + + event_loop.run_app(&mut app).unwrap() +} + +struct App { + app_menu: AppMenu, + windows: HashMap, + cursor_position: PhysicalPosition, + use_window_pos: bool, +} + +impl ApplicationHandler for App { + fn resumed(&mut self, event_loop: &ActiveEventLoop) {} + + fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) { + if cause == StartCause::Init { + let window_attrs = WindowAttributes::default().with_title("Window 1"); + let window = event_loop.create_window(window_attrs).unwrap(); + + let window_attrs2 = WindowAttributes::default().with_title("Window 2"); + let window2 = event_loop.create_window(window_attrs2).unwrap(); + + #[cfg(target_os = "windows")] + { + use winit::raw_window_handle::*; + if let RawWindowHandle::Win32(handle) = window.window_handle().unwrap().as_raw() { + unsafe { self.app_menu.menu_bar.init_for_hwnd(handle.hwnd.get()) }; + } + if let RawWindowHandle::Win32(handle) = window2.window_handle().unwrap().as_raw() { + unsafe { self.app_menu.menu_bar.init_for_hwnd(handle.hwnd.get()) }; + } + } + #[cfg(target_os = "macos")] + { + self.app_menu.menu_bar.init_for_nsapp(); + self.app_menu.window_menu.set_as_windows_menu_for_nsapp(); + self.app_menu.custom_help_menu.set_as_help_menu_for_nsapp(); + } + + self.windows.insert(window.id(), window); + self.windows.insert(window2.id(), window2); + } + } + + fn window_event( + &mut self, + event_loop: &ActiveEventLoop, + window_id: WindowId, + event: WindowEvent, + ) { + match event { + WindowEvent::CloseRequested => { + self.windows.remove(&window_id); + if self.windows.is_empty() { + event_loop.exit(); + } + } + + WindowEvent::CursorMoved { position, .. } => { + self.cursor_position = position; + } + + WindowEvent::MouseInput { + button: MouseButton::Right, + state: ElementState::Pressed, + .. + } => { + show_context_menu( + self.windows.get(&window_id).unwrap(), + &self.app_menu.file_menu, + if self.use_window_pos { + Some(self.cursor_position.into()) + } else { + None + }, + ); + self.use_window_pos = !self.use_window_pos; + } + + _ => {} + } + } + + fn user_event(&mut self, event_loop: &ActiveEventLoop, event: AppEvent) { + match event { + AppEvent::MenuEvent(event) => { + println!("{event:?}"); + + if event.id == self.app_menu.custom_item.id() { + let new_item = MenuItem::new("New Menu Item", true, None); + self.app_menu.file_menu.insert(&new_item, 2); + } + } + } + } +} + +struct AppMenu { + menu_bar: Menu, + file_menu: Submenu, + edit_menu: Submenu, + window_menu: Submenu, + custom_help_menu: Submenu, + custom_item: MenuItem, +} + +impl AppMenu { + fn new(menu_bar: Menu) -> Self { + #[cfg(target_os = "macos")] + { + let app_menu = Submenu::new("App", true); + app_menu.append_items(&[ + &PredefinedMenuItem::about(None, None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::services(None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::hide(None), + &PredefinedMenuItem::hide_others(None), + &PredefinedMenuItem::show_all(None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::quit(None), + ]); + menu_bar.append(&app_menu); + } + + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); + let icon = load_icon(std::path::Path::new(path)); + + let file_menu = Submenu::new("&File", true); + let edit_menu = Submenu::new("&Edit", true); + let window_menu = Submenu::new("&Window", true); + + window_menu.set_icon(Some(icon.clone())); + + menu_bar.append_items(&[&file_menu, &edit_menu, &window_menu]); + + let custom_i_1 = MenuItem::new( + "C&ustom 1", + true, + Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyC)), + ); + + let image_item = IconMenuItem::new("Image Custom 1", true, Some(icon), None); + + let check_custom_i_1 = CheckMenuItem::new("Check Custom 1", true, true, None); + let check_custom_i_2 = CheckMenuItem::new("Check Custom 2", false, true, None); + let check_custom_i_3 = CheckMenuItem::new( + "Check Custom 3", + true, + true, + Some(Accelerator::new(Some(Modifiers::SHIFT), Code::KeyD)), + ); + + let copy_i = PredefinedMenuItem::copy(None); + let cut_i = PredefinedMenuItem::cut(None); + let paste_i = PredefinedMenuItem::paste(None); + + file_menu.append_items(&[ + &custom_i_1, + &image_item, + &window_menu, + &PredefinedMenuItem::separator(), + &check_custom_i_1, + &check_custom_i_2, + ]); + + window_menu.append_items(&[ + &PredefinedMenuItem::minimize(None), + &PredefinedMenuItem::maximize(None), + &PredefinedMenuItem::close_window(Some("Close")), + &PredefinedMenuItem::fullscreen(None), + &PredefinedMenuItem::bring_all_to_front(None), + &PredefinedMenuItem::about( + None, + Some(AboutMetadata { + name: Some("winit".to_string()), + version: Some("1.2.3".to_string()), + copyright: Some("Copyright winit".to_string()), + ..Default::default() + }), + ), + &check_custom_i_3, + &image_item, + &custom_i_1, + ]); + + edit_menu.append_items(&[©_i, &PredefinedMenuItem::separator(), &paste_i]); + + let custom_help_menu = Submenu::new("Help", true); + custom_help_menu.append_items(&[&MenuItem::new( + "Supposed to show a search bar on macOS", + true, + None, + )]); + menu_bar.append(&custom_help_menu); + + Self { + menu_bar, + file_menu, + edit_menu, + window_menu, + custom_help_menu, + custom_item: custom_i_1, + } + } +} + +fn show_context_menu(window: &Window, menu: &dyn ContextMenu, position: Option) { + println!("Show context menu at position {position:?}"); + #[cfg(target_os = "windows")] + { + if let RawWindowHandle::Win32(handle) = window.window_handle().unwrap().as_raw() { + unsafe { menu.show_context_menu_for_hwnd(handle.hwnd.get(), position) }; + } + } + #[cfg(target_os = "macos")] + { + if let RawWindowHandle::AppKit(handle) = window.window_handle().unwrap().as_raw() { + unsafe { menu.show_context_menu_for_nsview(handle.ns_view.as_ptr() as _, position) }; + } + } +} + +fn load_icon(path: &std::path::Path) -> muda::Icon { + let (icon_rgba, icon_width, icon_height) = { + let image = image::open(path) + .expect("Failed to open icon path") + .into_rgba8(); + let (width, height) = image.dimensions(); + let rgba = image.into_raw(); + (rgba, width, height) + }; + muda::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") +} diff --git a/ports/muda/examples/wry.rs b/ports/muda/examples/wry.rs new file mode 100644 index 000000000000..42517722082c --- /dev/null +++ b/ports/muda/examples/wry.rs @@ -0,0 +1,391 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![allow(unused)] +use std::rc::Rc; + +use muda::{ + accelerator::{Accelerator, Code, Key, KeyAccelerator, Modifiers}, + dpi::Position, + AboutMetadata, CheckMenuItem, ContextMenu, IconMenuItem, Menu, MenuEvent, MenuItem, + PredefinedMenuItem, Submenu, +}; +#[cfg(target_os = "macos")] +use tao::platform::macos::WindowExtMacOS; +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +use tao::platform::unix::WindowExtUnix; +#[cfg(target_os = "windows")] +use tao::platform::windows::{EventLoopBuilderExtWindows, WindowExtWindows}; +use tao::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoopBuilder}, + window::{Window, WindowBuilder}, +}; +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +use wry::WebViewBuilderExtUnix; +use wry::{http::Request, WebViewBuilder}; + +enum UserEvent { + MenuEvent(muda::MenuEvent), +} + +fn main() -> wry::Result<()> { + let mut event_loop_builder = EventLoopBuilder::::with_user_event(); + + let menu_bar = Menu::new(); + + // setup accelerator handler on Windows + #[cfg(target_os = "windows")] + { + let menu_bar = menu_bar.clone(); + event_loop_builder.with_msg_hook(move |msg| { + use windows_sys::Win32::UI::WindowsAndMessaging::{TranslateAcceleratorW, MSG}; + unsafe { + let msg = msg as *const MSG; + let translated = TranslateAcceleratorW((*msg).hwnd, menu_bar.haccel() as _, msg); + translated == 1 + } + }); + } + + let event_loop = event_loop_builder.build(); + + // set a menu event handler that wakes up the event loop + let proxy = event_loop.create_proxy(); + muda::MenuEvent::set_event_handler(Some(move |event| { + proxy.send_event(UserEvent::MenuEvent(event)); + })); + + let window = WindowBuilder::new() + .with_title("Window 1") + .build(&event_loop) + .unwrap(); + + let window2 = WindowBuilder::new() + .with_title("Window 2") + .build(&event_loop) + .unwrap(); + + #[cfg(target_os = "macos")] + { + let app_m = Submenu::new("App", true); + menu_bar.append(&app_m).unwrap(); + app_m + .append_items(&[ + &PredefinedMenuItem::about(None, None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::services(None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::hide(None), + &PredefinedMenuItem::hide_others(None), + &PredefinedMenuItem::show_all(None), + &PredefinedMenuItem::separator(), + &PredefinedMenuItem::quit(None), + ]) + .unwrap(); + } + + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); + let icon = load_icon(std::path::Path::new(path)); + + let file_m = Submenu::new("&File", true); + let edit_m = Submenu::new("&Edit", true); + let window_m = Submenu::new("&Window", true); + + window_m.set_icon(Some(icon.clone())); + + menu_bar + .append_items(&[&file_m, &edit_m, &window_m]) + .unwrap(); + + let custom_i_1 = MenuItem::new("C&ustom 1", true, None); + custom_i_1.set_key_accelerator(Some(KeyAccelerator::new( + Some(Modifiers::CONTROL), + Key::Character("+".into()), + ))); + + let image_item = IconMenuItem::new( + "Image custom 1", + true, + Some(icon), + Some(Accelerator::new(Some(Modifiers::CONTROL), Code::KeyC)), + ); + + let check_custom_i_1 = CheckMenuItem::new("Check Custom 1", true, true, None); + let check_custom_i_2 = CheckMenuItem::new("Check Custom 2", false, true, None); + let check_custom_i_3 = CheckMenuItem::new( + "Check Custom 3", + true, + true, + Some(Accelerator::new(Some(Modifiers::SHIFT), Code::KeyD)), + ); + + let copy_i = PredefinedMenuItem::copy(None); + let cut_i = PredefinedMenuItem::cut(None); + let paste_i = PredefinedMenuItem::paste(None); + + file_m + .append_items(&[ + &custom_i_1, + &image_item, + &window_m, + &PredefinedMenuItem::separator(), + &check_custom_i_1, + &check_custom_i_2, + ]) + .unwrap(); + + window_m + .append_items(&[ + &PredefinedMenuItem::minimize(None), + &PredefinedMenuItem::maximize(None), + &PredefinedMenuItem::close_window(Some("Close")), + &PredefinedMenuItem::fullscreen(None), + &PredefinedMenuItem::bring_all_to_front(None), + &PredefinedMenuItem::about( + None, + Some(AboutMetadata { + name: Some("tao".to_string()), + version: Some("1.2.3".to_string()), + copyright: Some("Copyright tao".to_string()), + ..Default::default() + }), + ), + &check_custom_i_3, + &image_item, + &custom_i_1, + ]) + .unwrap(); + + edit_m + .append_items(&[ + ©_i, + &PredefinedMenuItem::separator(), + &cut_i, + &PredefinedMenuItem::separator(), + &paste_i, + ]) + .unwrap(); + + #[cfg(target_os = "windows")] + unsafe { + menu_bar.init_for_hwnd(window.hwnd() as _).unwrap(); + menu_bar.init_for_hwnd(window2.hwnd() as _).unwrap(); + } + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + // Pending a tao release on gtk4; muda's gtk API now takes gtk4 types. + // menu_bar + // .init_for_gtk_window(window.gtk_window(), window.default_vbox()) + // .unwrap(); + // menu_bar + // .init_for_gtk_window(window2.gtk_window(), window2.default_vbox()) + // .unwrap(); + let _ = (&menu_bar, &window, &window2); + } + #[cfg(target_os = "macos")] + { + menu_bar.init_for_nsapp(); + window_m.set_as_windows_menu_for_nsapp(); + } + + #[cfg(windows)] + let condition = "e.button !== 2"; + #[cfg(not(windows))] + let condition = "e.button == 2 && e.buttons === 0"; + let html: String = format!( + r#" + + + +
+

WRYYYYYYYYYYYYYYYYYYYYYY!

+
+ + + + "#, + ); + + let window = Rc::new(window); + let window2 = Rc::new(window2); + + let create_ipc_handler = |window: &Rc| { + let window = window.clone(); + let file_m_c = file_m.clone(); + let menu_bar = menu_bar.clone(); + move |req: Request| { + let req = req.body(); + if req == "showContextMenu" { + show_context_menu(&window, &file_m_c, None) + } else if let Some(rest) = req.strip_prefix("showContextMenuPos:") { + let (x, mut y) = rest + .split_once(',') + .map(|(x, y)| (x.parse::().unwrap(), y.parse::().unwrap())) + .unwrap(); + + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + // Pending a tao release on gtk4; muda's gtk API now takes gtk4 types. + // if let Some(menu_bar) = menu_bar + // .clone() + // .gtk_menubar_for_gtk_window(window.gtk_window()) + // { + // use gtk::prelude::*; + // y += menu_bar.allocated_height(); + // } + let _ = &mut y; + } + + show_context_menu(&window, &file_m_c, Some(Position::Logical((x, y).into()))) + } + } + }; + + fn create_webview(window: &Rc) -> WebViewBuilder<'_> { + #[cfg(not(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + )))] + return WebViewBuilder::new(window); + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + WebViewBuilder::new_gtk(window.default_vbox().unwrap()) + }; + + let webview = create_webview(&window) + .with_html(&html) + .with_ipc_handler(create_ipc_handler(&window)) + .build()?; + let webview2 = create_webview(&window2) + .with_html(html) + .with_ipc_handler(create_ipc_handler(&window2)) + .build()?; + + let menu_channel = MenuEvent::receiver(); + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + + Event::UserEvent(UserEvent::MenuEvent(event)) => { + if event.id == custom_i_1.id() { + file_m.insert(&MenuItem::new("New Menu Item", true, None), 2); + } + println!("{event:?}"); + } + _ => {} + } + }) +} + +fn show_context_menu(window: &Window, menu: &dyn ContextMenu, position: Option) { + println!("Show context menu at position {position:?}"); + #[cfg(target_os = "windows")] + unsafe { + menu.show_context_menu_for_hwnd(window.hwnd() as _, position); + } + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + // Pending a tao release on gtk4; muda's gtk API now takes gtk4 types. + // menu.show_context_menu_for_gtk_window(window.gtk_window().as_ref(), position); + let _ = (window, menu, position); + } + #[cfg(target_os = "macos")] + unsafe { + menu.show_context_menu_for_nsview(window.ns_view() as _, position); + } +} + +fn load_icon(path: &std::path::Path) -> muda::Icon { + let (icon_rgba, icon_width, icon_height) = { + let image = image::open(path) + .expect("Failed to open icon path") + .into_rgba8(); + let (width, height) = image.dimensions(); + let rgba = image.into_raw(); + (rgba, width, height) + }; + muda::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") +} diff --git a/ports/muda/renovate.json b/ports/muda/renovate.json new file mode 100644 index 000000000000..043faf790d0a --- /dev/null +++ b/ports/muda/renovate.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:base", ":disableDependencyDashboard"] +} diff --git a/ports/muda/rustfmt.toml b/ports/muda/rustfmt.toml new file mode 100644 index 000000000000..f8e8a75063c9 --- /dev/null +++ b/ports/muda/rustfmt.toml @@ -0,0 +1,12 @@ +max_width = 100 +hard_tabs = false +tab_spaces = 4 +newline_style = "Unix" +use_small_heuristics = "Default" +reorder_imports = true +reorder_modules = true +edition = "2021" +merge_derives = true +use_try_shorthand = false +use_field_init_shorthand = false +force_explicit_abi = true diff --git a/ports/muda/src/about_metadata.rs b/ports/muda/src/about_metadata.rs new file mode 100644 index 000000000000..15f6539e4475 --- /dev/null +++ b/ports/muda/src/about_metadata.rs @@ -0,0 +1,258 @@ +//! Types and functions to create [`AboutMetadata`] for the [`PredefinedMenuItem::about`](crate::PredefinedMenuItem::about) dialog. + +use crate::icon::Icon; + +/// Application metadata for the [`PredefinedMenuItem::about`](crate::PredefinedMenuItem::about) dialog. +#[derive(Debug, Clone, Default)] +pub struct AboutMetadata { + /// Sets the application name. + pub name: Option, + /// The application version. + pub version: Option, + /// The short version, e.g. "1.0". + /// + /// ## Platform-specific + /// + /// - **Windows / Linux:** Appended to the end of `version` in parentheses. + pub short_version: Option, + /// The authors of the application. + /// + /// ## Platform-specific + /// + /// - **macOS:** Unsupported. + pub authors: Option>, + /// Application comments. + /// + /// ## Platform-specific + /// + /// - **macOS:** Unsupported. + pub comments: Option, + /// The copyright of the application. + pub copyright: Option, + /// The license of the application. + /// + /// ## Platform-specific + /// + /// - **macOS:** Unsupported. + pub license: Option, + /// The application website. + /// + /// ## Platform-specific + /// + /// - **macOS:** Unsupported. + pub website: Option, + /// The website label. + /// + /// ## Platform-specific + /// + /// - **macOS:** Unsupported. + pub website_label: Option, + /// The credits. + /// + /// ## Platform-specific + /// + /// - **Windows / Linux:** Unsupported. + pub credits: Option, + /// The application icon. + /// + /// ## Platform-specific + /// + /// - **Windows:** Unsupported. + pub icon: Option, +} + +impl AboutMetadata { + #[allow(unused)] + pub(crate) fn full_version(&self) -> Option { + Some(format!( + "{}{}", + (self.version.as_ref())?, + (self.short_version.as_ref()) + .map(|v| format!(" ({v})")) + .unwrap_or_default() + )) + } +} + +/// Creates [`AboutMetadata`] from [Cargo metadata][cargo]. The following fields are set by this function. +/// +/// - [`AboutMetadata::name`] (from `CARGO_PKG_NAME`) +/// - [`AboutMetadata::version`] (from `CARGO_PKG_VERSION`) +/// - [`AboutMetadata::short_version`] (from `CARGO_PKG_VERSION_MAJOR` and `CARGO_PKG_VERSION_MINOR`) +/// - [`AboutMetadata::authors`] (from `CARGO_PKG_AUTHORS`) +/// - [`AboutMetadata::comments`] (from `CARGO_PKG_DESCRIPTION`) +/// - [`AboutMetadata::license`] (from `CARGO_PKG_LICENSE`) +/// - [`AboutMetadata::website`] (from `CARGO_PKG_HOMEPAGE`) +/// +/// [cargo]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates +#[macro_export] +#[doc(hidden)] +macro_rules! from_cargo_metadata { + () => {{ + #[allow(unused_mut)] + let mut m = $crate::about_metadata::AboutMetadata { + name: Some(::std::env!("CARGO_PKG_NAME").into()), + version: Some(::std::env!("CARGO_PKG_VERSION").into()), + short_version: Some(::std::format!( + "{}.{}", + env!("CARGO_PKG_VERSION_MAJOR"), + env!("CARGO_PKG_VERSION_MINOR"), + )), + ..::std::default::Default::default() + }; + + #[cfg(not(target_os = "macos"))] + { + let authors = env!("CARGO_PKG_AUTHORS") + .split(':') + .map(|a| a.trim().to_string()) + .collect::<::std::vec::Vec<_>>(); + + m.authors = if !authors.is_empty() { + Some(authors) + } else { + None + }; + + #[inline] + fn non_empty(s: &str) -> Option { + if !s.is_empty() { + Some(s.to_string()) + } else { + None + } + } + + m.comments = non_empty(::std::env!("CARGO_PKG_DESCRIPTION")); + m.license = non_empty(::std::env!("CARGO_PKG_LICENSE")); + m.website = non_empty(::std::env!("CARGO_PKG_HOMEPAGE")); + } + + m + }}; +} + +pub use from_cargo_metadata; + +/// A builder type for [`AboutMetadata`]. +#[derive(Clone, Debug, Default)] +pub struct AboutMetadataBuilder(AboutMetadata); + +impl AboutMetadataBuilder { + pub fn new() -> Self { + Default::default() + } + + /// Sets the application name. + pub fn name>(mut self, name: Option) -> Self { + self.0.name = name.map(|s| s.into()); + self + } + /// Sets the application version. + pub fn version>(mut self, version: Option) -> Self { + self.0.version = version.map(|s| s.into()); + self + } + /// Sets the short version, e.g. "1.0". + /// + /// ## Platform-specific + /// + /// - **Windows / Linux:** Appended to the end of `version` in parentheses. + pub fn short_version>(mut self, short_version: Option) -> Self { + self.0.short_version = short_version.map(|s| s.into()); + self + } + /// Sets the authors of the application. + /// + /// ## Platform-specific + /// + /// - **macOS:** Unsupported. + pub fn authors(mut self, authors: Option>) -> Self { + self.0.authors = authors; + self + } + /// Application comments. + /// + /// ## Platform-specific + /// + /// - **macOS:** Unsupported. + pub fn comments>(mut self, comments: Option) -> Self { + self.0.comments = comments.map(|s| s.into()); + self + } + /// Sets the copyright of the application. + pub fn copyright>(mut self, copyright: Option) -> Self { + self.0.copyright = copyright.map(|s| s.into()); + self + } + /// Sets the license of the application. + /// + /// ## Platform-specific + /// + /// - **macOS:** Unsupported. + pub fn license>(mut self, license: Option) -> Self { + self.0.license = license.map(|s| s.into()); + self + } + /// Sets the application website. + /// + /// ## Platform-specific + /// + /// - **macOS:** Unsupported. + pub fn website>(mut self, website: Option) -> Self { + self.0.website = website.map(|s| s.into()); + self + } + /// Sets the website label. + /// + /// ## Platform-specific + /// + /// - **macOS:** Unsupported. + pub fn website_label>(mut self, website_label: Option) -> Self { + self.0.website_label = website_label.map(|s| s.into()); + self + } + /// Sets the credits. + /// + /// ## Platform-specific + /// + /// - **Windows / Linux:** Unsupported. + pub fn credits>(mut self, credits: Option) -> Self { + self.0.credits = credits.map(|s| s.into()); + self + } + /// Sets the application icon. + /// + /// ## Platform-specific + /// + /// - **Windows:** Unsupported. + pub fn icon(mut self, icon: Option) -> Self { + self.0.icon = icon; + self + } + + /// Construct the final [`AboutMetadata`] + pub fn build(self) -> AboutMetadata { + self.0 + } +} + +#[cfg(test)] +mod tests { + + #[test] + fn test_build_from_metadata() { + let m = from_cargo_metadata!(); + assert_eq!(m.name, Some("muda".to_string())); + assert!(m.version.is_some()); + assert!(m.short_version.is_some()); + + #[cfg(not(target_os = "macos"))] + { + assert!(matches!(m.authors, Some(a) if !a.is_empty())); + assert!(m.comments.is_some()); + assert!(m.license.is_some()); + // Note: `m.website` is not tested because this package doesn't have the "website" field + } + } +} diff --git a/ports/muda/src/accelerator.rs b/ports/muda/src/accelerator.rs new file mode 100644 index 000000000000..a0ac3e57c8ce --- /dev/null +++ b/ports/muda/src/accelerator.rs @@ -0,0 +1,871 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! Accelerators describe keyboard shortcuts for menu items. +//! +//! [`KeyAccelerator`s](crate::accelerator::KeyAccelerator) are used to define a keyboard +//! shortcut based on logical keys, which allows expressing shortcuts like `Ctrl++` or `Ctrl+€` +//! that physical key codes cannot represent. +//! For this reason, prefer to use [`KeyAccelerator`s](crate::accelerator::KeyAccelerator) over the older [`Accelerator`s](crate::accelerator::Accelerator). +//! +//! # Examples +//! They can be created directly +//! ```no_run +//! # use muda::accelerator::*; +//! let key_accelerator = KeyAccelerator::new(Some(Modifiers::SHIFT), Key::Character("q".to_owned())); +//! let key_accelerator_without_mods = KeyAccelerator::new(None, Key::Character("q".to_owned())); +//! +//! let accelerator = Accelerator::new(Some(Modifiers::SHIFT), Code::KeyQ); +//! let accelerator_without_mods = Accelerator::new(None, Code::KeyQ); +//! ``` +//! or from `&str`, note that all modifiers +//! have to be listed before the non-modifier key, `shift+alt+KeyQ` is legal, +//! whereas `shift+q+alt` is not. +//! ```no_run +//! # use muda::accelerator::*; +//! let key_accelerator: KeyAccelerator = "shift+alt+KeyQ".parse().unwrap(); +//! // Or alternatively: +//! let key_accelerator: KeyAccelerator = "shift+alt+q".parse().unwrap(); +//! +//! // Or to parse Accelerator +//! let accelerator: Accelerator = "shift+alt+KeyQ".parse().unwrap(); +//! let accelerator: Accelerator = "shift+alt+q".parse().unwrap(); +//! # // This assert exists to ensure a test breaks once the +//! # // statement above about ordering is no longer valid. +//! # assert!("shift+KeyQ+alt".parse::().is_err()); +//! # assert!("shift+KeyQ+alt".parse::().is_err()); +//! ``` + +pub use keyboard_types::{Code, Key, Modifiers}; +use std::{borrow::Borrow, hash::Hash, str::FromStr}; + +#[cfg(target_os = "macos")] +pub const CMD_OR_CTRL: Modifiers = Modifiers::SUPER; +#[cfg(not(target_os = "macos"))] +pub const CMD_OR_CTRL: Modifiers = Modifiers::CONTROL; + +#[derive(thiserror::Error, Debug, PartialEq, Eq)] +pub enum AcceleratorParseError { + #[error("Couldn't recognize \"{0}\" as a valid key for accelerator, if you feel like it should be, please report this to https://github.com/tauri-apps/muda")] + UnsupportedKey(String), + #[error("Found empty token while parsing accelerator: {0}")] + EmptyToken(String), + #[error("Invalid accelerator format: \"{0}\", an accelerator should have the modifiers first and only one main key, for example: \"Shift + Alt + K\"")] + InvalidFormat(String), +} + +/// A keyboard shortcut that consists of an optional combination +/// of modifier keys (provided by [`Modifiers`] and +/// one key ([`Code`]). +/// +/// ## Warning +/// +/// This struct cannot represent all shortcuts found on non-U.S. keyboard layouts and might +/// be deprecated in the future. +/// Please use [`KeyAccelerator`] instead. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Accelerator { + pub(crate) mods: Modifiers, + pub(crate) key: Code, + id: u32, +} + +impl Accelerator { + /// Creates a new accelerator to define keyboard shortcuts throughout your application. + /// Only [`Modifiers::ALT`], [`Modifiers::SHIFT`], [`Modifiers::CONTROL`], and [`Modifiers::SUPER`] + pub fn new(mods: Option, key: Code) -> Self { + let mut mods = mods.unwrap_or_else(Modifiers::empty); + if mods.contains(Modifiers::META) { + mods.remove(Modifiers::META); + mods.insert(Modifiers::SUPER); + } + + let id = Self::generate_hash(mods, key); + + Self { mods, key, id } + } + + fn generate_hash(mods: Modifiers, key: Code) -> u32 { + KeyAccelerator::generate_hash(mods, &code_to_key(key)) + } + + /// Returns the id associated with this accelerator + /// which is a hash of the string representation of modifiers and key within this accelerator. + pub fn id(&self) -> u32 { + self.id + } + + /// Returns the modifier for this accelerator + pub fn modifiers(&self) -> Modifiers { + self.mods + } + + /// Returns the code for this accelerator + pub fn key(&self) -> Code { + self.key + } + + /// Returns `true` if this [`Code`] and [`Modifiers`] matches this `Accelerator`. + pub fn matches(&self, modifiers: impl Borrow, key: impl Borrow) -> bool { + // Should be a const but const bit_or doesn't work here. + let base_mods = Modifiers::SHIFT | Modifiers::CONTROL | Modifiers::ALT | Modifiers::SUPER; + let modifiers = modifiers.borrow(); + let key = key.borrow(); + self.mods == *modifiers & base_mods && self.key == *key + } +} + +impl FromStr for Accelerator { + type Err = AcceleratorParseError; + fn from_str(accelerator_string: &str) -> Result { + parse_accelerator(accelerator_string) + } +} + +impl TryFrom<&str> for Accelerator { + type Error = AcceleratorParseError; + + fn try_from(value: &str) -> Result { + parse_accelerator(value) + } +} + +impl TryFrom for Accelerator { + type Error = AcceleratorParseError; + + fn try_from(value: String) -> Result { + parse_accelerator(&value) + } +} + +fn parse_accelerator(accelerator: &str) -> Result { + let (modifiers_str, code_str) = split_key_and_modifiers(accelerator)?; + let modifiers = parse_modifiers(accelerator, modifiers_str)?; + let code = parse_code(code_str)?; + + Ok(Accelerator::new(Some(modifiers), code)) +} + +fn parse_code(code: &str) -> Result { + use Code::*; + match code.to_uppercase().as_str() { + "BACKQUOTE" | "`" => Ok(Backquote), + "BACKSLASH" | "\\" => Ok(Backslash), + "BRACKETLEFT" | "[" => Ok(BracketLeft), + "BRACKETRIGHT" | "]" => Ok(BracketRight), + "COMMA" | "," => Ok(Comma), + "DIGIT0" | "0" => Ok(Digit0), + "DIGIT1" | "1" => Ok(Digit1), + "DIGIT2" | "2" => Ok(Digit2), + "DIGIT3" | "3" => Ok(Digit3), + "DIGIT4" | "4" => Ok(Digit4), + "DIGIT5" | "5" => Ok(Digit5), + "DIGIT6" | "6" => Ok(Digit6), + "DIGIT7" | "7" => Ok(Digit7), + "DIGIT8" | "8" => Ok(Digit8), + "DIGIT9" | "9" => Ok(Digit9), + "EQUAL" | "=" => Ok(Equal), + "KEYA" | "A" => Ok(KeyA), + "KEYB" | "B" => Ok(KeyB), + "KEYC" | "C" => Ok(KeyC), + "KEYD" | "D" => Ok(KeyD), + "KEYE" | "E" => Ok(KeyE), + "KEYF" | "F" => Ok(KeyF), + "KEYG" | "G" => Ok(KeyG), + "KEYH" | "H" => Ok(KeyH), + "KEYI" | "I" => Ok(KeyI), + "KEYJ" | "J" => Ok(KeyJ), + "KEYK" | "K" => Ok(KeyK), + "KEYL" | "L" => Ok(KeyL), + "KEYM" | "M" => Ok(KeyM), + "KEYN" | "N" => Ok(KeyN), + "KEYO" | "O" => Ok(KeyO), + "KEYP" | "P" => Ok(KeyP), + "KEYQ" | "Q" => Ok(KeyQ), + "KEYR" | "R" => Ok(KeyR), + "KEYS" | "S" => Ok(KeyS), + "KEYT" | "T" => Ok(KeyT), + "KEYU" | "U" => Ok(KeyU), + "KEYV" | "V" => Ok(KeyV), + "KEYW" | "W" => Ok(KeyW), + "KEYX" | "X" => Ok(KeyX), + "KEYY" | "Y" => Ok(KeyY), + "KEYZ" | "Z" => Ok(KeyZ), + "MINUS" | "-" => Ok(Minus), + "PERIOD" | "." => Ok(Period), + "QUOTE" | "'" => Ok(Quote), + "SEMICOLON" | ";" => Ok(Semicolon), + "SLASH" | "/" => Ok(Slash), + "BACKSPACE" => Ok(Backspace), + "CAPSLOCK" => Ok(CapsLock), + "ENTER" => Ok(Enter), + "SPACE" => Ok(Space), + "TAB" => Ok(Tab), + "DELETE" => Ok(Delete), + "END" => Ok(End), + "HOME" => Ok(Home), + "INSERT" => Ok(Insert), + "PAGEDOWN" => Ok(PageDown), + "PAGEUP" => Ok(PageUp), + "PRINTSCREEN" => Ok(PrintScreen), + "SCROLLLOCK" => Ok(ScrollLock), + "ARROWDOWN" | "DOWN" => Ok(ArrowDown), + "ARROWLEFT" | "LEFT" => Ok(ArrowLeft), + "ARROWRIGHT" | "RIGHT" => Ok(ArrowRight), + "ARROWUP" | "UP" => Ok(ArrowUp), + "NUMLOCK" => Ok(NumLock), + "NUMPAD0" | "NUM0" => Ok(Numpad0), + "NUMPAD1" | "NUM1" => Ok(Numpad1), + "NUMPAD2" | "NUM2" => Ok(Numpad2), + "NUMPAD3" | "NUM3" => Ok(Numpad3), + "NUMPAD4" | "NUM4" => Ok(Numpad4), + "NUMPAD5" | "NUM5" => Ok(Numpad5), + "NUMPAD6" | "NUM6" => Ok(Numpad6), + "NUMPAD7" | "NUM7" => Ok(Numpad7), + "NUMPAD8" | "NUM8" => Ok(Numpad8), + "NUMPAD9" | "NUM9" => Ok(Numpad9), + "NUMPADADD" | "NUMADD" | "NUMPADPLUS" | "NUMPLUS" => Ok(NumpadAdd), + "NUMPADDECIMAL" | "NUMDECIMAL" => Ok(NumpadDecimal), + "NUMPADDIVIDE" | "NUMDIVIDE" => Ok(NumpadDivide), + "NUMPADENTER" | "NUMENTER" => Ok(NumpadEnter), + "NUMPADEQUAL" | "NUMEQUAL" => Ok(NumpadEqual), + "NUMPADMULTIPLY" | "NUMMULTIPLY" => Ok(NumpadMultiply), + "NUMPADSUBTRACT" | "NUMSUBTRACT" => Ok(NumpadSubtract), + "ESCAPE" | "ESC" => Ok(Escape), + "F1" => Ok(F1), + "F2" => Ok(F2), + "F3" => Ok(F3), + "F4" => Ok(F4), + "F5" => Ok(F5), + "F6" => Ok(F6), + "F7" => Ok(F7), + "F8" => Ok(F8), + "F9" => Ok(F9), + "F10" => Ok(F10), + "F11" => Ok(F11), + "F12" => Ok(F12), + "AUDIOVOLUMEDOWN" | "VOLUMEDOWN" => Ok(AudioVolumeDown), + "AUDIOVOLUMEUP" | "VOLUMEUP" => Ok(AudioVolumeUp), + "AUDIOVOLUMEMUTE" | "VOLUMEMUTE" => Ok(AudioVolumeMute), + "F13" => Ok(F13), + "F14" => Ok(F14), + "F15" => Ok(F15), + "F16" => Ok(F16), + "F17" => Ok(F17), + "F18" => Ok(F18), + "F19" => Ok(F19), + "F20" => Ok(F20), + "F21" => Ok(F21), + "F22" => Ok(F22), + "F23" => Ok(F23), + "F24" => Ok(F24), + + _ => Err(AcceleratorParseError::UnsupportedKey(code.to_string())), + } +} + +fn code_to_key(code: Code) -> Key { + match code { + Code::KeyA => Key::Character("a".into()), + Code::KeyB => Key::Character("b".into()), + Code::KeyC => Key::Character("c".into()), + Code::KeyD => Key::Character("d".into()), + Code::KeyE => Key::Character("e".into()), + Code::KeyF => Key::Character("f".into()), + Code::KeyG => Key::Character("g".into()), + Code::KeyH => Key::Character("h".into()), + Code::KeyI => Key::Character("i".into()), + Code::KeyJ => Key::Character("j".into()), + Code::KeyK => Key::Character("k".into()), + Code::KeyL => Key::Character("l".into()), + Code::KeyM => Key::Character("m".into()), + Code::KeyN => Key::Character("n".into()), + Code::KeyO => Key::Character("o".into()), + Code::KeyP => Key::Character("p".into()), + Code::KeyQ => Key::Character("q".into()), + Code::KeyR => Key::Character("r".into()), + Code::KeyS => Key::Character("s".into()), + Code::KeyT => Key::Character("t".into()), + Code::KeyU => Key::Character("u".into()), + Code::KeyV => Key::Character("v".into()), + Code::KeyW => Key::Character("w".into()), + Code::KeyX => Key::Character("x".into()), + Code::KeyY => Key::Character("y".into()), + Code::KeyZ => Key::Character("z".into()), + Code::Digit0 => Key::Character("0".into()), + Code::Digit1 => Key::Character("1".into()), + Code::Digit2 => Key::Character("2".into()), + Code::Digit3 => Key::Character("3".into()), + Code::Digit4 => Key::Character("4".into()), + Code::Digit5 => Key::Character("5".into()), + Code::Digit6 => Key::Character("6".into()), + Code::Digit7 => Key::Character("7".into()), + Code::Digit8 => Key::Character("8".into()), + Code::Digit9 => Key::Character("9".into()), + Code::Comma => Key::Character(",".into()), + Code::Minus => Key::Character("-".into()), + Code::Period => Key::Character(".".into()), + Code::Space => Key::Character(" ".into()), + Code::Equal => Key::Character("=".into()), + Code::Semicolon => Key::Character(";".into()), + Code::Slash => Key::Character("/".into()), + Code::Backslash => Key::Character("\\".into()), + Code::Quote => Key::Character("'".into()), + Code::Backquote => Key::Character("`".into()), + Code::BracketLeft => Key::Character("[".into()), + Code::BracketRight => Key::Character("]".into()), + Code::Numpad0 => Key::Character("0".into()), + Code::Numpad1 => Key::Character("1".into()), + Code::Numpad2 => Key::Character("2".into()), + Code::Numpad3 => Key::Character("3".into()), + Code::Numpad4 => Key::Character("4".into()), + Code::Numpad5 => Key::Character("5".into()), + Code::Numpad6 => Key::Character("6".into()), + Code::Numpad7 => Key::Character("7".into()), + Code::Numpad8 => Key::Character("8".into()), + Code::Numpad9 => Key::Character("9".into()), + Code::NumpadAdd => Key::Character("+".into()), + Code::NumpadDecimal => Key::Character(".".into()), + Code::NumpadDivide => Key::Character("/".into()), + Code::NumpadMultiply => Key::Character("*".into()), + Code::NumpadSubtract => Key::Character("-".into()), + Code::NumpadEqual => Key::Character("=".into()), + Code::NumpadEnter => Key::Enter, + Code::Backspace => Key::Backspace, + Code::Tab => Key::Tab, + Code::Enter => Key::Enter, + Code::Escape => Key::Escape, + Code::Delete => Key::Delete, + Code::CapsLock => Key::CapsLock, + Code::Home => Key::Home, + Code::End => Key::End, + Code::PageUp => Key::PageUp, + Code::PageDown => Key::PageDown, + Code::Insert => Key::Insert, + Code::PrintScreen => Key::PrintScreen, + Code::ScrollLock => Key::ScrollLock, + Code::NumLock => Key::NumLock, + Code::Pause => Key::Pause, + Code::ContextMenu => Key::ContextMenu, + Code::ArrowUp => Key::ArrowUp, + Code::ArrowDown => Key::ArrowDown, + Code::ArrowLeft => Key::ArrowLeft, + Code::ArrowRight => Key::ArrowRight, + Code::F1 => Key::F1, + Code::F2 => Key::F2, + Code::F3 => Key::F3, + Code::F4 => Key::F4, + Code::F5 => Key::F5, + Code::F6 => Key::F6, + Code::F7 => Key::F7, + Code::F8 => Key::F8, + Code::F9 => Key::F9, + Code::F10 => Key::F10, + Code::F11 => Key::F11, + Code::F12 => Key::F12, + Code::F13 => Key::F13, + Code::F14 => Key::F14, + Code::F15 => Key::F15, + Code::F16 => Key::F16, + Code::F17 => Key::F17, + Code::F18 => Key::F18, + Code::F19 => Key::F19, + Code::F20 => Key::F20, + Code::F21 => Key::F21, + Code::F22 => Key::F22, + Code::F23 => Key::F23, + Code::F24 => Key::F24, + Code::AudioVolumeDown => Key::AudioVolumeDown, + Code::AudioVolumeUp => Key::AudioVolumeUp, + Code::AudioVolumeMute => Key::AudioVolumeMute, + Code::MediaTrackNext => Key::MediaTrackNext, + Code::MediaTrackPrevious => Key::MediaTrackPrevious, + Code::MediaStop => Key::MediaStop, + Code::MediaPlayPause => Key::MediaPlayPause, + Code::LaunchMail => Key::LaunchMail, + Code::BrowserBack => Key::BrowserBack, + Code::BrowserForward => Key::BrowserForward, + Code::BrowserHome => Key::BrowserHome, + Code::BrowserSearch => Key::BrowserSearch, + Code::BrowserStop => Key::BrowserStop, + Code::BrowserFavorites => Key::BrowserFavorites, + Code::BrowserRefresh => Key::BrowserRefresh, + Code::Convert => Key::Convert, + Code::KanaMode => Key::KanaMode, + Code::NonConvert => Key::NonConvert, + Code::Help => Key::Help, + // Code is unfortunately non-exhaustive, + // which means we need to manually notice and update this list if new items are added to Code. + _ => Key::Unidentified, + } +} + +/// A keyboard shortcut based on logical [`Key`] values. +/// +/// Unlike [`Accelerator`] which uses physical [`Code`] keys, +/// `KeyAccelerator` uses logical [`Key`] values which can represent +/// any character including Unicode characters like `+`, `€`, `{`, etc. +/// +/// # Examples +/// +/// They can be created directly +/// ```no_run +/// # use muda::accelerator::{KeyAccelerator, Modifiers, Key}; +/// let accel = KeyAccelerator::new(Some(Modifiers::CONTROL), Key::Character("+".into())); +/// ``` +/// or converted from an existing [`Accelerator`] +/// ```no_run +/// # use muda::accelerator::{Accelerator, KeyAccelerator, Code, Modifiers}; +/// let old_accel = Accelerator::new(Some(Modifiers::CONTROL), Code::KeyC); +/// let new_accel: KeyAccelerator = old_accel.into(); +/// ``` +/// or parsed from a string, which supports literal character keys +/// ```no_run +/// # use muda::accelerator::KeyAccelerator; +/// let accel: KeyAccelerator = "Ctrl++".parse().unwrap(); +/// let accel2: KeyAccelerator = "Ctrl+€".parse().unwrap(); +/// ``` +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct KeyAccelerator { + pub(crate) mods: Modifiers, + pub(crate) key: Key, + id: u32, +} + +impl KeyAccelerator { + /// Creates a new key accelerator to define keyboard shortcuts throughout your application. + /// Only [`Modifiers::ALT`], [`Modifiers::SHIFT`], [`Modifiers::CONTROL`], and [`Modifiers::SUPER`] + pub fn new(mods: Option, key: Key) -> Self { + let mut mods = mods.unwrap_or_else(Modifiers::empty); + if mods.contains(Modifiers::META) { + mods.remove(Modifiers::META); + mods.insert(Modifiers::SUPER); + } + + let id = Self::generate_hash(mods, &key); + + Self { mods, key, id } + } + + fn generate_hash(mods: Modifiers, key: &Key) -> u32 { + let mut accelerator_str = String::new(); + if mods.contains(Modifiers::SHIFT) { + accelerator_str.push_str("shift+") + } + if mods.contains(Modifiers::CONTROL) { + accelerator_str.push_str("control+") + } + if mods.contains(Modifiers::ALT) { + accelerator_str.push_str("alt+") + } + if mods.contains(Modifiers::SUPER) { + accelerator_str.push_str("super+") + } + accelerator_str.push_str(&format!("{:?}", key)); + + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + accelerator_str.hash(&mut hasher); + std::hash::Hasher::finish(&hasher) as u32 + } + + /// Returns the id associated with this accelerator + /// which is a hash of the string representation of modifiers and key within this accelerator. + pub fn id(&self) -> u32 { + self.id + } + + /// Returns the modifiers for this accelerator. + pub fn modifiers(&self) -> Modifiers { + self.mods + } + + /// Returns the key for this accelerator. + pub fn key(&self) -> &Key { + &self.key + } + + /// Returns `true` if this [`Key`] and [`Modifiers`] matches this `KeyAccelerator`. + pub fn matches(&self, modifiers: impl Borrow, key: impl Borrow) -> bool { + let base_mods = Modifiers::SHIFT | Modifiers::CONTROL | Modifiers::ALT | Modifiers::SUPER; + let modifiers = modifiers.borrow(); + let key = key.borrow(); + self.mods == *modifiers & base_mods && self.key == *key + } +} + +impl From for KeyAccelerator { + fn from(accel: Accelerator) -> Self { + KeyAccelerator::new(Some(accel.mods), code_to_key(accel.key)) + } +} + +impl FromStr for KeyAccelerator { + type Err = AcceleratorParseError; + fn from_str(accelerator_string: &str) -> Result { + parse_key_accelerator(accelerator_string) + } +} + +impl TryFrom<&str> for KeyAccelerator { + type Error = AcceleratorParseError; + + fn try_from(value: &str) -> Result { + parse_key_accelerator(value) + } +} + +impl TryFrom for KeyAccelerator { + type Error = AcceleratorParseError; + + fn try_from(value: String) -> Result { + parse_key_accelerator(&value) + } +} + +fn parse_modifier(accelerator: &str, token: &str) -> Result { + let token = token.trim(); + if token.is_empty() { + return Err(AcceleratorParseError::EmptyToken(accelerator.to_string())); + } + let modifier = match token.to_uppercase().as_str() { + "OPTION" | "ALT" => Modifiers::ALT, + "CONTROL" | "CTRL" => Modifiers::CONTROL, + "COMMAND" | "CMD" | "SUPER" => Modifiers::META, + "SHIFT" => Modifiers::SHIFT, + #[cfg(target_os = "macos")] + "COMMANDORCONTROL" | "COMMANDORCTRL" | "CMDORCTRL" | "CMDORCONTROL" => Modifiers::SUPER, + #[cfg(not(target_os = "macos"))] + "COMMANDORCONTROL" | "COMMANDORCTRL" | "CMDORCTRL" | "CMDORCONTROL" => Modifiers::CONTROL, + _ => { + return Err(AcceleratorParseError::InvalidFormat( + accelerator.to_string(), + )); + } + }; + Ok(modifier) +} + +fn parse_modifiers( + accelerator: &str, + modifiers_str: &str, +) -> Result { + let mut modifiers = Modifiers::empty(); + if !modifiers_str.is_empty() { + for token in modifiers_str.split('+') { + modifiers |= parse_modifier(accelerator, token)?; + } + } + + Ok(modifiers) +} + +// Tries to parse a key string as a [`Code`] first (reusing the existing parser), +// then falls back to treating it as a literal character [`Key`]. +fn parse_key(key: &str) -> Result { + if let Ok(code) = parse_code(key) { + let key = code_to_key(code); + if key != Key::Unidentified { + return Ok(key); + } + } + + let trimmed = key.trim(); + if trimmed.is_empty() { + Err(AcceleratorParseError::UnsupportedKey(key.to_string())) + } else if parse_modifier(key, key).is_ok() { + // The key must not be modifier + Err(AcceleratorParseError::UnsupportedKey(key.into())) + } else { + Ok(Key::Character(trimmed.into())) + } +} + +fn split_key_and_modifiers(accelerator: &str) -> Result<(&str, &str), AcceleratorParseError> { + let accelerator = accelerator.trim(); + if accelerator.is_empty() { + return Err(AcceleratorParseError::InvalidFormat(String::new())); + } + + // Separate modifier part from key part using rfind('+'). + // This correctly handles '+' as the key: "Ctrl++" -> rfind gives the last '+', + // leaving "Ctrl+" as the modifier part and "" as raw key -> key is '+'. + let (modifiers_str, key_str) = match accelerator.rfind('+') { + Some(pos) => { + let raw_key = &accelerator[pos + 1..]; + if raw_key.trim().is_empty() { + // The key is '+' itself; strip the trailing separator '+' from the modifier part + let raw_mods = accelerator[..pos].trim_end_matches('+'); + (raw_mods, "+") + } else { + (&accelerator[..pos], raw_key.trim()) + } + } + None => ("", accelerator), + }; + + Ok((modifiers_str, key_str)) +} + +fn parse_key_accelerator(accelerator: &str) -> Result { + let (modifiers_str, key_str) = split_key_and_modifiers(accelerator)?; + let mods = parse_modifiers(accelerator, modifiers_str)?; + let key = parse_key(key_str)?; + Ok(KeyAccelerator::new(Some(mods), key)) +} + +#[test] +fn test_parse_accelerator() { + macro_rules! assert_parse_accelerator { + ($key:literal, $lrh:expr) => { + let r = parse_accelerator($key).unwrap(); + let l = $lrh; + assert_eq!(r.mods, l.mods); + assert_eq!(r.key, l.key); + }; + } + + assert_parse_accelerator!( + "KeyX", + Accelerator { + mods: Modifiers::empty(), + key: Code::KeyX, + id: 0, + } + ); + + assert_parse_accelerator!( + "CTRL+KeyX", + Accelerator { + mods: Modifiers::CONTROL, + key: Code::KeyX, + id: 0, + } + ); + + assert_parse_accelerator!( + "SHIFT+KeyC", + Accelerator { + mods: Modifiers::SHIFT, + key: Code::KeyC, + id: 0, + } + ); + + assert_parse_accelerator!( + "SHIFT+KeyC", + Accelerator { + mods: Modifiers::SHIFT, + key: Code::KeyC, + id: 0, + } + ); + + assert_parse_accelerator!( + "super+ctrl+SHIFT+alt+ArrowUp", + Accelerator { + mods: Modifiers::SUPER | Modifiers::CONTROL | Modifiers::SHIFT | Modifiers::ALT, + key: Code::ArrowUp, + id: 0, + } + ); + assert_parse_accelerator!( + "Digit5", + Accelerator { + mods: Modifiers::empty(), + key: Code::Digit5, + id: 0, + } + ); + assert_parse_accelerator!( + "KeyG", + Accelerator { + mods: Modifiers::empty(), + key: Code::KeyG, + id: 0, + } + ); + + assert_parse_accelerator!( + "SHiFT+F12", + Accelerator { + mods: Modifiers::SHIFT, + key: Code::F12, + id: 0, + } + ); + + assert_parse_accelerator!( + "CmdOrCtrl+Space", + Accelerator { + #[cfg(target_os = "macos")] + mods: Modifiers::SUPER, + #[cfg(not(target_os = "macos"))] + mods: Modifiers::CONTROL, + key: Code::Space, + id: 0, + } + ); +} + +#[test] +fn test_parse_accelerator_error() { + let cases = [ + ( + "Ctrl+Shift+C+A", + AcceleratorParseError::InvalidFormat("Ctrl+Shift+C+A".into()), + ), + ( + "Ctrl+C+Shift", + AcceleratorParseError::InvalidFormat("Ctrl+C+Shift".into()), + ), + ("Alt", AcceleratorParseError::UnsupportedKey("Alt".into())), + ("Cmd", AcceleratorParseError::UnsupportedKey("Cmd".into())), + ("Ctrl", AcceleratorParseError::UnsupportedKey("Ctrl".into())), + ( + "Super", + AcceleratorParseError::UnsupportedKey("Super".into()), + ), + ("+", AcceleratorParseError::UnsupportedKey("+".into())), + ]; + for (text, err) in cases { + let parsed = text.parse::(); + assert_eq!(parsed, Err(err), "Expected parsing \"{text}\" to error!"); + } +} + +#[test] +fn test_parse_key_accelerator_error() { + let cases = [ + ( + "Ctrl+Shift+C+A", + AcceleratorParseError::InvalidFormat("Ctrl+Shift+C+A".into()), + ), + ( + "Ctrl+C+Shift", + AcceleratorParseError::InvalidFormat("Ctrl+C+Shift".into()), + ), + ("Alt", AcceleratorParseError::UnsupportedKey("Alt".into())), + ("Cmd", AcceleratorParseError::UnsupportedKey("Cmd".into())), + ("Ctrl", AcceleratorParseError::UnsupportedKey("Ctrl".into())), + ( + "Super", + AcceleratorParseError::UnsupportedKey("Super".into()), + ), + ]; + for (text, err) in cases { + let parsed = text.parse::(); + assert_eq!(parsed, Err(err), "Expected parsing \"{text}\" to error!"); + } +} + +#[test] +fn test_equality() { + let h1 = parse_accelerator("Shift+KeyR").unwrap(); + let h2 = parse_accelerator("Shift+KeyR").unwrap(); + let h3 = Accelerator::new(Some(Modifiers::SHIFT), Code::KeyR); + let h4 = parse_accelerator("Alt+KeyR").unwrap(); + let h5 = parse_accelerator("Alt+KeyR").unwrap(); + let h6 = parse_accelerator("KeyR").unwrap(); + + assert!(h1 == h2 && h2 == h3 && h3 != h4 && h4 == h5 && h5 != h6); + assert!( + h1.id() == h2.id() + && h2.id() == h3.id() + && h3.id() != h4.id() + && h4.id() == h5.id() + && h5.id() != h6.id() + ); +} + +#[test] +fn test_parse_key_accelerator() { + // Basic key parsing (reuses Code-based keys) + let cases = [ + ("Ctrl+A", Modifiers::CONTROL, Key::Character("a".into())), + ("Ctrl+KeyA", Modifiers::CONTROL, Key::Character("a".into())), + ("Shift+F12", Modifiers::SHIFT, Key::F12), + // Literal '+' as key + ("Ctrl++", Modifiers::CONTROL, Key::Character("+".into())), + // Multiple modifiers + '+' + ( + "Ctrl+Shift++", + Modifiers::CONTROL | Modifiers::SHIFT, + Key::Character("+".into()), + ), + // Just '+' alone + ("+", Modifiers::empty(), Key::Character("+".into())), + // Unicode character keys + ("Ctrl+€", Modifiers::CONTROL, Key::Character("€".into())), + // CmdOrCtrl works + #[cfg(target_os = "macos")] + ( + "CmdOrCtrl+Space", + Modifiers::SUPER, + Key::Character(" ".into()), + ), + #[cfg(not(target_os = "macos"))] + ( + "CmdOrCtrl+Space", + Modifiers::CONTROL, + Key::Character(" ".into()), + ), + ]; + + for (string, modifiers, key) in cases { + let accelerator: KeyAccelerator = string.parse().expect("Failed to parse KeyAccelerator"); + assert_eq!( + accelerator.mods, modifiers, + "Expected \"{string}\" to produce modifiers: {modifiers:?}" + ); + assert_eq!( + accelerator.key, key, + "Expected \"{string}\" to produce key: {key}" + ); + } +} + +#[test] +fn test_key_accelerator_from_accelerator() { + let cases = [ + ( + Accelerator::new(Some(Modifiers::CONTROL), Code::KeyC), + Key::Character("c".into()), + ), + ( + Accelerator::new(Some(Modifiers::SHIFT), Code::ArrowUp), + Key::ArrowUp, + ), + ]; + + for (accelerator, key) in cases { + let key_accelerator: KeyAccelerator = accelerator.into(); + assert_eq!( + key_accelerator.mods, accelerator.mods, + "Source accelerator: {accelerator:?}" + ); + assert_eq!( + key_accelerator.key, key, + "Source accelerator: {accelerator:?}" + ); + } +} + +#[test] +fn test_key_accelerator_equality() { + let h1: KeyAccelerator = "Shift+R".parse().unwrap(); + let h2: KeyAccelerator = "Shift+R".parse().unwrap(); + let h3 = KeyAccelerator::new(Some(Modifiers::SHIFT), Key::Character("r".into())); + let h4: KeyAccelerator = "Alt+R".parse().unwrap(); + + assert!(h1 == h2 && h2 == h3 && h3 != h4); + assert!(h1.id() == h2.id() && h2.id() == h3.id() && h3.id() != h4.id()); + + // Converted from Accelerator should match parsed KeyAccelerator + let from_code = Accelerator::new(Some(Modifiers::SHIFT), Code::KeyR); + let from_code: KeyAccelerator = from_code.into(); + assert_eq!(from_code, h1); + assert_eq!(from_code.id(), h1.id()); +} diff --git a/ports/muda/src/builders/check.rs b/ports/muda/src/builders/check.rs new file mode 100644 index 000000000000..f539653ef02a --- /dev/null +++ b/ports/muda/src/builders/check.rs @@ -0,0 +1,94 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + accelerator::{Accelerator, KeyAccelerator}, + CheckMenuItem, MenuId, +}; + +/// A builder type for [`CheckMenuItem`] +#[derive(Clone, Debug, Default)] +pub struct CheckMenuItemBuilder { + text: String, + enabled: bool, + checked: bool, + key_accelerator: Option, + id: Option, +} + +impl CheckMenuItemBuilder { + pub fn new() -> Self { + Default::default() + } + + /// Set the id this check menu item. + pub fn id(mut self, id: MenuId) -> Self { + self.id.replace(id); + self + } + + /// Set the text for this check menu item. + /// + /// See [`CheckMenuItem::set_text`] for more info. + pub fn text>(mut self, text: S) -> Self { + self.text = text.into(); + self + } + + /// Enable or disable this menu item. + pub fn enabled(mut self, enabled: bool) -> Self { + self.enabled = enabled; + self + } + + /// Check or uncheck this menu item. + pub fn checked(mut self, checked: bool) -> Self { + self.checked = checked; + self + } + + /// Set this check menu item accelerator. + /// + /// (Note that setting an accelerator will override any existing [.key_accelerator()](Self::key_accelerator)) + pub fn accelerator>( + mut self, + accelerator: Option, + ) -> crate::Result + where + crate::Error: From<>::Error>, + { + self.key_accelerator = accelerator + .map(|a| a.try_into()) + .transpose()? + .map(KeyAccelerator::from); + Ok(self) + } + + /// Set this check menu item accelerator using a [`KeyAccelerator`]. + /// + /// (Note that setting a key_accelerator will override any existing [.accelerator()](Self::accelerator)) + pub fn key_accelerator>( + mut self, + accelerator: Option, + ) -> crate::Result + where + crate::Error: From<>::Error>, + { + self.key_accelerator = accelerator.map(|a| a.try_into()).transpose()?; + Ok(self) + } + + /// Build this check menu item. + pub fn build(self) -> CheckMenuItem { + let item = if let Some(id) = self.id { + CheckMenuItem::with_id(id, self.text, self.enabled, self.checked, None) + } else { + CheckMenuItem::new(self.text, self.enabled, self.checked, None) + }; + if let Some(key_accel) = self.key_accelerator { + let _ = item.set_key_accelerator(Some(key_accel)); + } + item + } +} diff --git a/ports/muda/src/builders/icon.rs b/ports/muda/src/builders/icon.rs new file mode 100644 index 000000000000..7bdfcb1daec3 --- /dev/null +++ b/ports/muda/src/builders/icon.rs @@ -0,0 +1,116 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + accelerator::{Accelerator, KeyAccelerator}, + icon::{Icon, NativeIcon}, + IconMenuItem, MenuId, +}; + +/// A builder type for [`IconMenuItem`] +#[derive(Clone, Debug, Default)] +pub struct IconMenuItemBuilder { + text: String, + enabled: bool, + id: Option, + key_accelerator: Option, + icon: Option, + native_icon: Option, +} + +impl IconMenuItemBuilder { + pub fn new() -> Self { + Default::default() + } + + /// Set the id this icon menu item. + pub fn id(mut self, id: MenuId) -> Self { + self.id.replace(id); + self + } + + /// Set the text for this icon menu item. + /// + /// See [`IconMenuItem::set_text`] for more info. + pub fn text>(mut self, text: S) -> Self { + self.text = text.into(); + self + } + + /// Enable or disable this menu item. + pub fn enabled(mut self, enabled: bool) -> Self { + self.enabled = enabled; + self + } + + /// Set this icon menu item icon. + pub fn icon(mut self, icon: Option) -> Self { + self.icon = icon; + self.native_icon = None; + self + } + + /// Set this icon menu item native icon. + pub fn native_icon(mut self, icon: Option) -> Self { + self.native_icon = icon; + self.icon = None; + self + } + + /// Set this icon menu item accelerator. + /// + /// (Note that setting an accelerator will override any existing [.key_accelerator()](Self::key_accelerator)) + pub fn accelerator>( + mut self, + accelerator: Option, + ) -> crate::Result + where + crate::Error: From<>::Error>, + { + self.key_accelerator = accelerator + .map(|a| a.try_into()) + .transpose()? + .map(KeyAccelerator::from); + Ok(self) + } + + /// Set this icon menu item accelerator using a [`KeyAccelerator`]. + /// + /// (Note that setting a key_accelerator will override any existing [.accelerator()](Self::accelerator)) + pub fn key_accelerator>( + mut self, + accelerator: Option, + ) -> crate::Result + where + crate::Error: From<>::Error>, + { + self.key_accelerator = accelerator.map(|a| a.try_into()).transpose()?; + Ok(self) + } + + /// Build this icon menu item. + pub fn build(self) -> IconMenuItem { + let item = if let Some(id) = self.id { + if self.icon.is_some() { + IconMenuItem::with_id(id, self.text, self.enabled, self.icon, None) + } else { + IconMenuItem::with_id_and_native_icon( + id, + self.text, + self.enabled, + self.native_icon, + None, + ) + } + } else if self.icon.is_some() { + IconMenuItem::new(self.text, self.enabled, self.icon, None) + } else { + IconMenuItem::with_native_icon(self.text, self.enabled, self.native_icon, None) + }; + if let Some(key_accel) = self.key_accelerator { + let _ = item.set_key_accelerator(Some(key_accel)); + } + item + } +} diff --git a/ports/muda/src/builders/mod.rs b/ports/muda/src/builders/mod.rs new file mode 100644 index 000000000000..c5557a028834 --- /dev/null +++ b/ports/muda/src/builders/mod.rs @@ -0,0 +1,16 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! A module containing builder types + +mod check; +mod icon; +mod normal; +mod submenu; + +pub use crate::about_metadata::AboutMetadataBuilder; +pub use check::*; +pub use icon::*; +pub use normal::*; +pub use submenu::*; diff --git a/ports/muda/src/builders/normal.rs b/ports/muda/src/builders/normal.rs new file mode 100644 index 000000000000..0c2aa47b7e6e --- /dev/null +++ b/ports/muda/src/builders/normal.rs @@ -0,0 +1,87 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + accelerator::{Accelerator, KeyAccelerator}, + MenuId, MenuItem, +}; + +/// A builder type for [`MenuItem`] +#[derive(Clone, Debug, Default)] +pub struct MenuItemBuilder { + text: String, + enabled: bool, + id: Option, + key_accelerator: Option, +} + +impl MenuItemBuilder { + pub fn new() -> Self { + Default::default() + } + + /// Set the id this menu item. + pub fn id(mut self, id: MenuId) -> Self { + self.id.replace(id); + self + } + + /// Set the text for this menu item. + /// + /// See [`MenuItem::set_text`] for more info. + pub fn text>(mut self, text: S) -> Self { + self.text = text.into(); + self + } + + /// Enable or disable this menu item. + pub fn enabled(mut self, enabled: bool) -> Self { + self.enabled = enabled; + self + } + + /// Set this menu item accelerator. + /// + /// (Note that setting an accelerator will override any existing [.key_accelerator()](Self::key_accelerator)) + pub fn accelerator>( + mut self, + accelerator: Option, + ) -> crate::Result + where + crate::Error: From<>::Error>, + { + self.key_accelerator = accelerator + .map(|a| a.try_into()) + .transpose()? + .map(KeyAccelerator::from); + Ok(self) + } + + /// Set this menu item accelerator using a [`KeyAccelerator`]. + /// + /// (Note that setting a key_accelerator will override any existing [.accelerator()](Self::accelerator)) + pub fn key_accelerator>( + mut self, + accelerator: Option, + ) -> crate::Result + where + crate::Error: From<>::Error>, + { + self.key_accelerator = accelerator.map(|a| a.try_into()).transpose()?; + Ok(self) + } + + /// Build this menu item. + pub fn build(self) -> MenuItem { + let item = if let Some(id) = self.id { + MenuItem::with_id(id, self.text, self.enabled, None) + } else { + MenuItem::new(self.text, self.enabled, None) + }; + if let Some(key_accel) = self.key_accelerator { + let _ = item.set_key_accelerator(Some(key_accel)); + } + item + } +} diff --git a/ports/muda/src/builders/submenu.rs b/ports/muda/src/builders/submenu.rs new file mode 100644 index 000000000000..cceabbc42b1a --- /dev/null +++ b/ports/muda/src/builders/submenu.rs @@ -0,0 +1,94 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{Icon, IsMenuItem, MenuId, NativeIcon, Submenu}; + +/// A builder type for [`Submenu`] +#[derive(Clone, Default)] +pub struct SubmenuBuilder<'a> { + text: String, + enabled: bool, + id: Option, + items: Vec<&'a dyn IsMenuItem>, + icon: Option, + native_icon: Option, +} + +impl std::fmt::Debug for SubmenuBuilder<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("SubmenuBuilder") + .field("text", &self.text) + .field("enabled", &self.enabled) + .finish() + } +} + +impl<'a> SubmenuBuilder<'a> { + pub fn new() -> Self { + Default::default() + } + + /// Set the id this submenu. + pub fn id(mut self, id: MenuId) -> Self { + self.id.replace(id); + self + } + + /// Set the text for this submenu. + /// + /// See [`Submenu::set_text`] for more info. + pub fn text>(mut self, text: S) -> Self { + self.text = text.into(); + self + } + + /// Enable or disable this submenu. + pub fn enabled(mut self, enabled: bool) -> Self { + self.enabled = enabled; + self + } + + /// Add an item to this submenu. + pub fn item(mut self, item: &'a dyn IsMenuItem) -> Self { + self.items.push(item); + self + } + + /// Add these items to this submenu. + pub fn items(mut self, items: &[&'a dyn IsMenuItem]) -> Self { + self.items.extend_from_slice(items); + self + } + + /// Set an icon for this submenu. + pub fn icon(mut self, icon: Icon) -> Self { + self.icon = Some(icon); + self + } + + /// Set a native icon for this submenu. + pub fn native_icon(mut self, icon: NativeIcon) -> Self { + self.native_icon = Some(icon); + self + } + + /// Build this menu item. + pub fn build(self) -> crate::Result { + let submenu = if let Some(id) = self.id { + Submenu::with_id_and_items(id, self.text, self.enabled, &self.items)? + } else { + Submenu::with_items(self.text, self.enabled, &self.items)? + }; + + if let Some(icon) = self.icon { + submenu.set_icon(Some(icon)); + } + + if let Some(native_icon) = self.native_icon { + submenu.set_native_icon(Some(native_icon)); + } + + Ok(submenu) + } +} diff --git a/ports/muda/src/error.rs b/ports/muda/src/error.rs new file mode 100644 index 000000000000..56d006ab2a9a --- /dev/null +++ b/ports/muda/src/error.rs @@ -0,0 +1,52 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use thiserror::Error; + +pub use crate::accelerator::AcceleratorParseError; + +/// Errors returned by muda. +#[non_exhaustive] +#[derive(Error, Debug)] +pub enum Error { + #[error("This menu item is not a child of this `Menu` or `Submenu`")] + NotAChildOfThisMenu, + #[cfg(windows)] + #[error("This menu has not been initialized for this hwnd`")] + NotInitialized, + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + #[error("This menu has not been initialized for this gtk window`")] + NotInitialized, + #[cfg(windows)] + #[error("This menu has already been initialized for this hwnd`")] + AlreadyInitialized, + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + #[error("This menu has already been initialized for this gtk window`")] + AlreadyInitialized, + #[error(transparent)] + AcceleratorParseError(#[from] AcceleratorParseError), + #[error("Gtk Window doesn't have an application")] + GtkWindowWithoutApplication, +} + +/// Convenient type alias of Result type for muda. +pub type Result = std::result::Result; diff --git a/ports/muda/src/icon.rs b/ports/muda/src/icon.rs new file mode 100644 index 000000000000..0262dfa65bf1 --- /dev/null +++ b/ports/muda/src/icon.rs @@ -0,0 +1,313 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +// taken from https://github.com/rust-windowing/winit/blob/92fdf5ba85f920262a61cee4590f4a11ad5738d1/src/icon.rs + +use crate::platform_impl::PlatformIcon; +use std::{error::Error, fmt, io, mem}; + +#[repr(C)] +#[derive(Debug)] +pub(crate) struct Pixel { + pub(crate) r: u8, + pub(crate) g: u8, + pub(crate) b: u8, + pub(crate) a: u8, +} + +pub(crate) const PIXEL_SIZE: usize = mem::size_of::(); + +#[derive(Debug)] +/// An error produced when using [`Icon::from_rgba`] with invalid arguments. +pub enum BadIcon { + /// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be + /// safely interpreted as 32bpp RGBA pixels. + ByteCountNotDivisibleBy4 { byte_count: usize }, + /// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`. + /// At least one of your arguments is incorrect. + DimensionsVsPixelCount { + width: u32, + height: u32, + width_x_height: usize, + pixel_count: usize, + }, + /// Produced when underlying OS functionality failed to create the icon + OsError(io::Error), + /// Produced when encoding the provided RGBA data as PNG fails + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + PngEncodingError(png::EncodingError), +} + +impl fmt::Display for BadIcon { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + BadIcon::ByteCountNotDivisibleBy4 { byte_count } => write!(f, + "The length of the `rgba` argument ({:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.", + byte_count, + ), + BadIcon::DimensionsVsPixelCount { + width, + height, + width_x_height, + pixel_count, + } => write!(f, + "The specified dimensions ({:?}x{:?}) don't match the number of pixels supplied by the `rgba` argument ({:?}). For those dimensions, the expected pixel count is {:?}.", + width, height, pixel_count, width_x_height, + ), + BadIcon::OsError(e) => write!(f, "OS error when instantiating the icon: {:?}", e), + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + BadIcon::PngEncodingError(e) => { + write!(f, "PNG encoding error when instantiating the icon: {:?}", e) + } + } + } +} + +impl Error for BadIcon { + fn source(&self) -> Option<&(dyn Error + 'static)> { + Some(self) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct RgbaIcon { + pub(crate) rgba: Vec, + pub(crate) width: u32, + pub(crate) height: u32, +} + +/// For platforms which don't have window icons (e.g. web) +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct NoIcon; + +#[allow(dead_code)] // These are not used on every platform +mod constructors { + use super::*; + + impl RgbaIcon { + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + if !rgba.len().is_multiple_of(PIXEL_SIZE) { + return Err(BadIcon::ByteCountNotDivisibleBy4 { + byte_count: rgba.len(), + }); + } + let pixel_count = rgba.len() / PIXEL_SIZE; + if pixel_count != (width * height) as usize { + Err(BadIcon::DimensionsVsPixelCount { + width, + height, + width_x_height: (width * height) as usize, + pixel_count, + }) + } else { + Ok(RgbaIcon { + rgba, + width, + height, + }) + } + } + } + + impl NoIcon { + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + // Create the rgba icon anyway to validate the input + let _ = RgbaIcon::from_rgba(rgba, width, height)?; + Ok(NoIcon) + } + } +} + +/// An icon used for the window titlebar, taskbar, etc. +#[derive(Clone)] +pub struct Icon { + pub(crate) inner: PlatformIcon, +} + +impl fmt::Debug for Icon { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + fmt::Debug::fmt(&self.inner, formatter) + } +} + +impl Icon { + /// Creates an icon from 32bpp RGBA data. + /// + /// The length of `rgba` must be divisible by 4, and `width * height` must equal + /// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error. + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + Ok(Icon { + inner: PlatformIcon::from_rgba(rgba, width, height)?, + }) + } + + /// Create an icon from a file path. + /// + /// Specify `size` to load a specific icon size from the file, or `None` to load the default + /// icon size from the file. + /// + /// In cases where the specified size does not exist in the file, Windows may perform scaling + /// to get an icon of the desired size. + #[cfg(windows)] + pub fn from_path>( + path: P, + size: Option<(u32, u32)>, + ) -> Result { + let win_icon = PlatformIcon::from_path(path, size)?; + Ok(Icon { inner: win_icon }) + } + + /// Create an icon from a resource embedded in this executable or library. + /// + /// Specify `size` to load a specific icon size from the file, or `None` to load the default + /// icon size from the file. + /// + /// In cases where the specified size does not exist in the file, Windows may perform scaling + /// to get an icon of the desired size. + #[cfg(windows)] + pub fn from_resource(ordinal: u16, size: Option<(u32, u32)>) -> Result { + let win_icon = PlatformIcon::from_resource(ordinal, size)?; + Ok(Icon { inner: win_icon }) + } +} + +/// A native Icon to be used for the menu item +/// +/// ## Platform-specific: +/// +/// - **Windows / Linux**: Unsupported. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum NativeIcon { + /// An add item template image. + Add, + /// Advanced preferences toolbar icon for the preferences window. + Advanced, + /// A Bluetooth template image. + Bluetooth, + /// Bookmarks image suitable for a template. + Bookmarks, + /// A caution image. + Caution, + /// A color panel toolbar icon. + ColorPanel, + /// A column view mode template image. + ColumnView, + /// A computer icon. + Computer, + /// An enter full-screen mode template image. + EnterFullScreen, + /// Permissions for all users. + Everyone, + /// An exit full-screen mode template image. + ExitFullScreen, + /// A cover flow view mode template image. + FlowView, + /// A folder image. + Folder, + /// A burnable folder icon. + FolderBurnable, + /// A smart folder icon. + FolderSmart, + /// A link template image. + FollowLinkFreestanding, + /// A font panel toolbar icon. + FontPanel, + /// A `go back` template image. + GoLeft, + /// A `go forward` template image. + GoRight, + /// Home image suitable for a template. + Home, + /// An iChat Theater template image. + IChatTheater, + /// An icon view mode template image. + IconView, + /// An information toolbar icon. + Info, + /// A template image used to denote invalid data. + InvalidDataFreestanding, + /// A generic left-facing triangle template image. + LeftFacingTriangle, + /// A list view mode template image. + ListView, + /// A locked padlock template image. + LockLocked, + /// An unlocked padlock template image. + LockUnlocked, + /// A horizontal dash, for use in menus. + MenuMixedState, + /// A check mark template image, for use in menus. + MenuOnState, + /// A MobileMe icon. + MobileMe, + /// A drag image for multiple items. + MultipleDocuments, + /// A network icon. + Network, + /// A path button template image. + Path, + /// General preferences toolbar icon for the preferences window. + PreferencesGeneral, + /// A Quick Look template image. + QuickLook, + /// A refresh template image. + RefreshFreestanding, + /// A refresh template image. + Refresh, + /// A remove item template image. + Remove, + /// A reveal contents template image. + RevealFreestanding, + /// A generic right-facing triangle template image. + RightFacingTriangle, + /// A share view template image. + Share, + /// A slideshow template image. + Slideshow, + /// A badge for a `smart` item. + SmartBadge, + /// Small green indicator, similar to iChat’s available image. + StatusAvailable, + /// Small clear indicator. + StatusNone, + /// Small yellow indicator, similar to iChat’s idle image. + StatusPartiallyAvailable, + /// Small red indicator, similar to iChat’s unavailable image. + StatusUnavailable, + /// A stop progress template image. + StopProgressFreestanding, + /// A stop progress button template image. + StopProgress, + /// An image of the empty trash can. + TrashEmpty, + /// An image of the full trash can. + TrashFull, + /// Permissions for a single user. + User, + /// User account toolbar icon for the preferences window. + UserAccounts, + /// Permissions for a group of users. + UserGroup, + /// Permissions for guests. + UserGuest, +} diff --git a/ports/muda/src/items/check.rs b/ports/muda/src/items/check.rs new file mode 100644 index 000000000000..67c76931b304 --- /dev/null +++ b/ports/muda/src/items/check.rs @@ -0,0 +1,150 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.inner +// SPDX-License-Identifier: MIT + +use std::{cell::RefCell, mem, rc::Rc}; + +use crate::{ + accelerator::{Accelerator, KeyAccelerator}, + sealed::IsMenuItemBase, + IsMenuItem, MenuId, MenuItemKind, +}; + +/// A check menu item inside a [`Menu`] or [`Submenu`] +/// and usually contains a text and a check mark or a similar toggle +/// that corresponds to a checked and unchecked states. +/// +/// [`Menu`]: crate::Menu +/// [`Submenu`]: crate::Submenu +#[derive(Clone)] +pub struct CheckMenuItem { + pub(crate) id: Rc, + pub(crate) inner: Rc>, +} + +impl IsMenuItemBase for CheckMenuItem {} +impl IsMenuItem for CheckMenuItem { + fn kind(&self) -> MenuItemKind { + MenuItemKind::Check(self.clone()) + } + + fn id(&self) -> &MenuId { + self.id() + } + + fn into_id(self) -> MenuId { + self.into_id() + } +} + +impl CheckMenuItem { + /// Create a new check menu item. + /// + /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic + /// for this check menu item. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn new>( + text: S, + enabled: bool, + checked: bool, + accelerator: Option, + ) -> Self { + let item = crate::platform_impl::MenuChild::new_check( + text.as_ref(), + enabled, + checked, + accelerator.map(KeyAccelerator::from), + None, + ); + Self { + id: Rc::new(item.id().clone()), + inner: Rc::new(RefCell::new(item)), + } + } + + /// Create a new check menu item with the specified id. + /// + /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic + /// for this check menu item. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn with_id, S: AsRef>( + id: I, + text: S, + enabled: bool, + checked: bool, + accelerator: Option, + ) -> Self { + let id = id.into(); + Self { + id: Rc::new(id.clone()), + inner: Rc::new(RefCell::new(crate::platform_impl::MenuChild::new_check( + text.as_ref(), + enabled, + checked, + accelerator.map(KeyAccelerator::from), + Some(id), + ))), + } + } + + /// Returns a unique identifier associated with this submenu. + pub fn id(&self) -> &MenuId { + &self.id + } + + /// Get the text for this check menu item. + pub fn text(&self) -> String { + self.inner.borrow().text() + } + + /// Set the text for this check menu item. `text` could optionally contain + /// an `&` before a character to assign this character as the mnemonic + /// for this check menu item. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn set_text>(&self, text: S) { + self.inner.borrow_mut().set_text(text.as_ref()) + } + + /// Get whether this check menu item is enabled or not. + pub fn is_enabled(&self) -> bool { + self.inner.borrow().is_enabled() + } + + /// Enable or disable this check menu item. + pub fn set_enabled(&self, enabled: bool) { + self.inner.borrow_mut().set_enabled(enabled) + } + + /// Set this check menu item accelerator. + /// + /// (Note that setting an accelerator will override any existing [.set_key_accelerator()](Self::set_key_accelerator)) + pub fn set_accelerator(&self, accelerator: Option) -> crate::Result<()> { + self.inner + .borrow_mut() + .set_key_accelerator(accelerator.map(KeyAccelerator::from)) + } + + /// Set this check menu item accelerator using a [`KeyAccelerator`]. + /// + /// (Note that setting a key_accelerator will override any existing [.set_accelerator()](Self::set_accelerator)) + pub fn set_key_accelerator(&self, accelerator: Option) -> crate::Result<()> { + self.inner.borrow_mut().set_key_accelerator(accelerator) + } + + /// Get whether this check menu item is checked or not. + pub fn is_checked(&self) -> bool { + self.inner.borrow().is_checked() + } + + /// Check or Uncheck this check menu item. + pub fn set_checked(&self, checked: bool) { + self.inner.borrow_mut().set_checked(checked) + } + + /// Convert this menu item into its menu ID. + pub fn into_id(mut self) -> MenuId { + // Note: `Rc::into_inner` is available from Rust 1.70 + if let Some(id) = Rc::get_mut(&mut self.id) { + mem::take(id) + } else { + self.id().clone() + } + } +} diff --git a/ports/muda/src/items/compat.rs b/ports/muda/src/items/compat.rs new file mode 100644 index 000000000000..34fc1f121b4c --- /dev/null +++ b/ports/muda/src/items/compat.rs @@ -0,0 +1,63 @@ +use std::sync::Arc; + +use arc_swap::ArcSwap; + +use crate::AboutMetadata; + +#[derive(Debug, Clone)] +pub struct CompatStandardItem { + pub id: String, + pub label: String, + pub enabled: bool, + pub icon: Option>, + pub about_metadata: Option, +} + +#[derive(Debug, Clone)] +pub struct CompatCheckmarkItem { + pub id: String, + pub label: String, + pub enabled: bool, + pub checked: bool, +} + +#[derive(Debug, Clone)] +pub struct CompatSubMenuItem { + pub label: String, + pub enabled: bool, + pub submenu: Vec>>, +} + +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone)] +pub enum CompatMenuItem { + Standard(CompatStandardItem), + Checkmark(CompatCheckmarkItem), + SubMenu(CompatSubMenuItem), + Separator, +} + +impl From for CompatMenuItem { + fn from(item: CompatStandardItem) -> Self { + CompatMenuItem::Standard(item) + } +} + +impl From for CompatMenuItem { + fn from(item: CompatCheckmarkItem) -> Self { + CompatMenuItem::Checkmark(item) + } +} + +impl From for CompatMenuItem { + fn from(item: CompatSubMenuItem) -> Self { + CompatMenuItem::SubMenu(item) + } +} + +pub(crate) fn strip_mnemonic(text: impl AsRef) -> String { + text.as_ref() + .replace("&&", "[~~]") + .replace('&', "") + .replace("[~~]", "&") +} diff --git a/ports/muda/src/items/icon.rs b/ports/muda/src/items/icon.rs new file mode 100644 index 000000000000..d1ce54321946 --- /dev/null +++ b/ports/muda/src/items/icon.rs @@ -0,0 +1,210 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.inner +// SPDX-License-Identifier: MIT + +use std::{cell::RefCell, mem, rc::Rc}; + +use crate::{ + accelerator::{Accelerator, KeyAccelerator}, + icon::{Icon, NativeIcon}, + sealed::IsMenuItemBase, + IsMenuItem, MenuId, MenuItemKind, +}; + +/// An icon menu item inside a [`Menu`] or [`Submenu`] +/// and usually contains an icon and a text. +/// +/// [`Menu`]: crate::Menu +/// [`Submenu`]: crate::Submenu +#[derive(Clone)] +pub struct IconMenuItem { + pub(crate) id: Rc, + pub(crate) inner: Rc>, +} + +impl IsMenuItemBase for IconMenuItem {} +impl IsMenuItem for IconMenuItem { + fn kind(&self) -> MenuItemKind { + MenuItemKind::Icon(self.clone()) + } + + fn id(&self) -> &MenuId { + self.id() + } + + fn into_id(self) -> MenuId { + self.into_id() + } +} + +impl IconMenuItem { + /// Create a new icon menu item. + /// + /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic + /// for this icon menu item. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn new>( + text: S, + enabled: bool, + icon: Option, + accelerator: Option, + ) -> Self { + let item = crate::platform_impl::MenuChild::new_icon( + text.as_ref(), + enabled, + icon, + accelerator.map(KeyAccelerator::from), + None, + ); + Self { + id: Rc::new(item.id().clone()), + inner: Rc::new(RefCell::new(item)), + } + } + + /// Create a new icon menu item with the specified id. + /// + /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic + /// for this icon menu item. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn with_id, S: AsRef>( + id: I, + text: S, + enabled: bool, + icon: Option, + accelerator: Option, + ) -> Self { + let id = id.into(); + Self { + id: Rc::new(id.clone()), + inner: Rc::new(RefCell::new(crate::platform_impl::MenuChild::new_icon( + text.as_ref(), + enabled, + icon, + accelerator.map(KeyAccelerator::from), + Some(id), + ))), + } + } + + /// Create a new icon menu item but with a native icon. + /// + /// See [`IconMenuItem::new`] for more info. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux**: Unsupported. + pub fn with_native_icon>( + text: S, + enabled: bool, + native_icon: Option, + accelerator: Option, + ) -> Self { + let item = crate::platform_impl::MenuChild::new_native_icon( + text.as_ref(), + enabled, + native_icon, + accelerator.map(KeyAccelerator::from), + None, + ); + Self { + id: Rc::new(item.id().clone()), + inner: Rc::new(RefCell::new(item)), + } + } + + /// Create a new icon menu item but with the specified id and a native icon. + /// + /// See [`IconMenuItem::new`] for more info. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux**: Unsupported. + pub fn with_id_and_native_icon, S: AsRef>( + id: I, + text: S, + enabled: bool, + native_icon: Option, + accelerator: Option, + ) -> Self { + let id = id.into(); + Self { + id: Rc::new(id.clone()), + inner: Rc::new(RefCell::new( + crate::platform_impl::MenuChild::new_native_icon( + text.as_ref(), + enabled, + native_icon, + accelerator.map(KeyAccelerator::from), + Some(id), + ), + )), + } + } + + /// Returns a unique identifier associated with this submenu. + pub fn id(&self) -> &MenuId { + &self.id + } + + /// Get the text for this check menu item. + pub fn text(&self) -> String { + self.inner.borrow().text() + } + + /// Set the text for this check menu item. `text` could optionally contain + /// an `&` before a character to assign this character as the mnemonic + /// for this check menu item. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn set_text>(&self, text: S) { + self.inner.borrow_mut().set_text(text.as_ref()) + } + + /// Get whether this check menu item is enabled or not. + pub fn is_enabled(&self) -> bool { + self.inner.borrow().is_enabled() + } + + /// Enable or disable this check menu item. + pub fn set_enabled(&self, enabled: bool) { + self.inner.borrow_mut().set_enabled(enabled) + } + + /// Set this icon menu item accelerator. + /// + /// (Note that setting an accelerator will override any existing [.set_key_accelerator()](Self::set_key_accelerator)) + pub fn set_accelerator(&self, accelerator: Option) -> crate::Result<()> { + self.inner + .borrow_mut() + .set_key_accelerator(accelerator.map(KeyAccelerator::from)) + } + + /// Set this icon menu item accelerator using a [`KeyAccelerator`]. + /// + /// (Note that setting a key_accelerator will override any existing [.set_accelerator()](Self::set_accelerator)) + pub fn set_key_accelerator(&self, accelerator: Option) -> crate::Result<()> { + self.inner.borrow_mut().set_key_accelerator(accelerator) + } + + /// Change this menu item icon or remove it. + pub fn set_icon(&self, icon: Option) { + self.inner.borrow_mut().set_icon(icon) + } + + /// Change this menu item icon to a native image or remove it. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux**: Unsupported. + pub fn set_native_icon(&self, _icon: Option) { + #[cfg(target_os = "macos")] + self.inner.borrow_mut().set_native_icon(_icon) + } + + /// Convert this menu item into its menu ID. + pub fn into_id(mut self) -> MenuId { + // Note: `Rc::into_inner` is available from Rust 1.70 + if let Some(id) = Rc::get_mut(&mut self.id) { + mem::take(id) + } else { + self.id().clone() + } + } +} diff --git a/ports/muda/src/items/mod.rs b/ports/muda/src/items/mod.rs new file mode 100644 index 000000000000..eb1153d74b07 --- /dev/null +++ b/ports/muda/src/items/mod.rs @@ -0,0 +1,90 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +mod check; +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] +mod compat; +mod icon; +mod normal; +mod predefined; +mod submenu; + +pub use check::*; +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] +pub use compat::*; +pub use icon::*; +pub use normal::*; +pub use predefined::*; +pub use submenu::*; + +#[cfg(test)] +mod test { + use crate::{CheckMenuItem, IconMenuItem, MenuId, MenuItem, PredefinedMenuItem, Submenu}; + + #[test] + #[cfg_attr( + all( + miri, + not(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + )) + ), + ignore + )] + fn it_returns_same_id() { + let id = MenuId::new("1"); + assert_eq!(id, MenuItem::with_id(id.clone(), "", true, None).id()); + assert_eq!(id, Submenu::with_id(id.clone(), "", true).id()); + assert_eq!( + id, + CheckMenuItem::with_id(id.clone(), "", true, true, None).id() + ); + assert_eq!( + id, + IconMenuItem::with_id(id.clone(), "", true, None, None).id() + ); + } + + #[test] + #[cfg_attr( + all( + miri, + not(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + )) + ), + ignore + )] + fn test_convert_from_id_and_into_id() { + let id = "TEST ID"; + let expected = MenuId(id.to_string()); + + let item = CheckMenuItem::with_id(id, "test", true, true, None); + assert_eq!(item.id(), &expected); + assert_eq!(item.into_id(), expected); + + let item = IconMenuItem::with_id(id, "test", true, None, None); + assert_eq!(item.id(), &expected); + assert_eq!(item.into_id(), expected); + + let item = MenuItem::with_id(id, "test", true, None); + assert_eq!(item.id(), &expected); + assert_eq!(item.into_id(), expected); + + let item = Submenu::with_id(id, "test", true); + assert_eq!(item.id(), &expected); + assert_eq!(item.into_id(), expected); + + let item = PredefinedMenuItem::separator(); + assert_eq!(item.id().clone(), item.into_id()); + } +} diff --git a/ports/muda/src/items/normal.rs b/ports/muda/src/items/normal.rs new file mode 100644 index 000000000000..581dc524dd1f --- /dev/null +++ b/ports/muda/src/items/normal.rs @@ -0,0 +1,126 @@ +use std::{cell::RefCell, mem, rc::Rc}; + +use crate::{ + accelerator::{Accelerator, KeyAccelerator}, + sealed::IsMenuItemBase, + IsMenuItem, MenuId, MenuItemKind, +}; + +/// A menu item inside a [`Menu`] or [`Submenu`] and contains only text. +/// +/// [`Menu`]: crate::Menu +/// [`Submenu`]: crate::Submenu +#[derive(Clone)] +pub struct MenuItem { + pub(crate) id: Rc, + pub(crate) inner: Rc>, +} + +impl IsMenuItemBase for MenuItem {} +impl IsMenuItem for MenuItem { + fn kind(&self) -> MenuItemKind { + MenuItemKind::MenuItem(self.clone()) + } + + fn id(&self) -> &MenuId { + self.id() + } + + fn into_id(self) -> MenuId { + self.into_id() + } +} + +impl MenuItem { + /// Create a new menu item. + /// + /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic + /// for this menu item. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn new>(text: S, enabled: bool, accelerator: Option) -> Self { + let item = crate::platform_impl::MenuChild::new( + text.as_ref(), + enabled, + accelerator.map(KeyAccelerator::from), + None, + ); + Self { + id: Rc::new(item.id().clone()), + inner: Rc::new(RefCell::new(item)), + } + } + + /// Create a new menu item with the specified id. + /// + /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic + /// for this menu item. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn with_id, S: AsRef>( + id: I, + text: S, + enabled: bool, + accelerator: Option, + ) -> Self { + let id = id.into(); + Self { + id: Rc::new(id.clone()), + inner: Rc::new(RefCell::new(crate::platform_impl::MenuChild::new( + text.as_ref(), + enabled, + accelerator.map(KeyAccelerator::from), + Some(id), + ))), + } + } + + /// Returns a unique identifier associated with this menu item. + pub fn id(&self) -> &MenuId { + &self.id + } + + /// Set the text for this menu item. + pub fn text(&self) -> String { + self.inner.borrow().text() + } + + /// Set the text for this menu item. `text` could optionally contain + /// an `&` before a character to assign this character as the mnemonic + /// for this menu item. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn set_text>(&self, text: S) { + self.inner.borrow_mut().set_text(text.as_ref()) + } + + /// Get whether this menu item is enabled or not. + pub fn is_enabled(&self) -> bool { + self.inner.borrow().is_enabled() + } + + /// Enable or disable this menu item. + pub fn set_enabled(&self, enabled: bool) { + self.inner.borrow_mut().set_enabled(enabled) + } + + /// Set this menu item accelerator. + /// + /// (Note that setting an accelerator will override any existing [.set_key_accelerator()](Self::set_key_accelerator)) + pub fn set_accelerator(&self, accelerator: Option) -> crate::Result<()> { + self.inner + .borrow_mut() + .set_key_accelerator(accelerator.map(KeyAccelerator::from)) + } + + /// Set this menu item accelerator using a [`KeyAccelerator`]. + /// + /// (Note that setting a key_accelerator will override any existing [.set_accelerator()](Self::set_accelerator)) + pub fn set_key_accelerator(&self, accelerator: Option) -> crate::Result<()> { + self.inner.borrow_mut().set_key_accelerator(accelerator) + } + + /// Convert this menu item into its menu ID. + pub fn into_id(mut self) -> MenuId { + // Note: `Rc::into_inner` is available from Rust 1.70 + if let Some(id) = Rc::get_mut(&mut self.id) { + mem::take(id) + } else { + self.id().clone() + } + } +} diff --git a/ports/muda/src/items/predefined.rs b/ports/muda/src/items/predefined.rs new file mode 100644 index 000000000000..acb02831ac69 --- /dev/null +++ b/ports/muda/src/items/predefined.rs @@ -0,0 +1,343 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.inner +// SPDX-License-Identifier: MIT + +use std::{cell::RefCell, mem, rc::Rc}; + +use crate::{ + accelerator::{Accelerator, CMD_OR_CTRL}, + sealed::IsMenuItemBase, + AboutMetadata, IsMenuItem, MenuId, MenuItemKind, +}; +use keyboard_types::{Code, Modifiers}; + +/// A predefined (native) menu item which has a predefined behavior by the OS or by this crate. +#[derive(Clone)] +pub struct PredefinedMenuItem { + pub(crate) id: Rc, + pub(crate) inner: Rc>, +} + +impl IsMenuItemBase for PredefinedMenuItem {} +impl IsMenuItem for PredefinedMenuItem { + fn kind(&self) -> MenuItemKind { + MenuItemKind::Predefined(self.clone()) + } + + fn id(&self) -> &MenuId { + self.id() + } + + fn into_id(self) -> MenuId { + self.into_id() + } +} + +impl PredefinedMenuItem { + /// Separator menu item + pub fn separator() -> PredefinedMenuItem { + PredefinedMenuItem::new::<&str>(PredefinedMenuItemType::Separator, None) + } + + /// Copy menu item + pub fn copy(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::Copy, text) + } + + /// Cut menu item + pub fn cut(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::Cut, text) + } + + /// Paste menu item + pub fn paste(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::Paste, text) + } + + /// SelectAll menu item + pub fn select_all(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::SelectAll, text) + } + + /// Undo menu item + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn undo(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::Undo, text) + } + /// Redo menu item + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn redo(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::Redo, text) + } + + /// Minimize window menu item + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn minimize(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::Minimize, text) + } + + /// Maximize window menu item + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn maximize(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::Maximize, text) + } + + /// Fullscreen menu item + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn fullscreen(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::Fullscreen, text) + } + + /// Hide window menu item + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn hide(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::Hide, text) + } + + /// Hide other windows menu item + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn hide_others(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::HideOthers, text) + } + + /// Show all app windows menu item + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn show_all(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::ShowAll, text) + } + + /// Close window menu item + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn close_window(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::CloseWindow, text) + } + + /// Quit app menu item + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn quit(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::Quit, text) + } + + /// About app menu item + pub fn about(text: Option<&str>, metadata: Option) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::About(metadata), text) + } + + /// Services menu item + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn services(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::Services, text) + } + + /// 'Bring all to front' menu item + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux:** Unsupported. + pub fn bring_all_to_front(text: Option<&str>) -> PredefinedMenuItem { + PredefinedMenuItem::new(PredefinedMenuItemType::BringAllToFront, text) + } + + fn new>(item: PredefinedMenuItemType, text: Option) -> Self { + let item = crate::platform_impl::MenuChild::new_predefined( + item, + text.map(|t| t.as_ref().to_string()), + ); + Self { + id: Rc::new(item.id().clone()), + inner: Rc::new(RefCell::new(item)), + } + } + + /// Returns a unique identifier associated with this predefined menu item. + pub fn id(&self) -> &MenuId { + &self.id + } + + /// Get the text for this predefined menu item. + pub fn text(&self) -> String { + self.inner.borrow().text() + } + + /// Set the text for this predefined menu item. + pub fn set_text>(&self, text: S) { + self.inner.borrow_mut().set_text(text.as_ref()) + } + + /// Convert this menu item into its menu ID. + pub fn into_id(mut self) -> MenuId { + // Note: `Rc::into_inner` is available from Rust 1.70 + if let Some(id) = Rc::get_mut(&mut self.id) { + mem::take(id) + } else { + self.id().clone() + } + } +} + +#[test] +fn test_about_metadata() { + assert_eq!( + AboutMetadata { + ..Default::default() + } + .full_version(), + None + ); + + assert_eq!( + AboutMetadata { + version: Some("Version: 1.inner".into()), + ..Default::default() + } + .full_version(), + Some("Version: 1.inner".into()) + ); + + assert_eq!( + AboutMetadata { + version: Some("Version: 1.inner".into()), + short_version: Some("Universal".into()), + ..Default::default() + } + .full_version(), + Some("Version: 1.inner (Universal)".into()) + ); +} + +#[derive(Debug, Clone, Default)] +#[non_exhaustive] +#[allow(clippy::large_enum_variant)] +pub(crate) enum PredefinedMenuItemType { + Separator, + Copy, + Cut, + Paste, + SelectAll, + Undo, + Redo, + Minimize, + Maximize, + Fullscreen, + Hide, + HideOthers, + ShowAll, + CloseWindow, + Quit, + About(Option), + Services, + BringAllToFront, + #[default] + None, +} + +impl PredefinedMenuItemType { + pub(crate) fn text(&self) -> &str { + match self { + PredefinedMenuItemType::Separator => "", + PredefinedMenuItemType::Copy => "&Copy", + PredefinedMenuItemType::Cut => "Cu&t", + PredefinedMenuItemType::Paste => "&Paste", + PredefinedMenuItemType::SelectAll => "Select &All", + PredefinedMenuItemType::Undo => "Undo", + PredefinedMenuItemType::Redo => "Redo", + PredefinedMenuItemType::Minimize => "&Minimize", + #[cfg(target_os = "macos")] + PredefinedMenuItemType::Maximize => "Zoom", + #[cfg(not(target_os = "macos"))] + PredefinedMenuItemType::Maximize => "Ma&ximize", + PredefinedMenuItemType::Fullscreen => "Toggle Full Screen", + PredefinedMenuItemType::Hide => "&Hide", + PredefinedMenuItemType::HideOthers => "Hide Others", + PredefinedMenuItemType::ShowAll => "Show All", + #[cfg(windows)] + PredefinedMenuItemType::CloseWindow => "Close", + #[cfg(not(windows))] + PredefinedMenuItemType::CloseWindow => "C&lose Window", + #[cfg(windows)] + PredefinedMenuItemType::Quit => "&Exit", + #[cfg(not(windows))] + PredefinedMenuItemType::Quit => "&Quit", + PredefinedMenuItemType::About(_) => "&About", + PredefinedMenuItemType::Services => "Services", + PredefinedMenuItemType::BringAllToFront => "Bring All to Front", + PredefinedMenuItemType::None => "", + } + } + + pub(crate) fn accelerator(&self) -> Option { + match self { + PredefinedMenuItemType::Copy => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyC)), + PredefinedMenuItemType::Cut => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyX)), + PredefinedMenuItemType::Paste => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyV)), + PredefinedMenuItemType::Undo => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyZ)), + #[cfg(target_os = "macos")] + PredefinedMenuItemType::Redo => Some(Accelerator::new( + Some(CMD_OR_CTRL | Modifiers::SHIFT), + Code::KeyZ, + )), + #[cfg(not(target_os = "macos"))] + PredefinedMenuItemType::Redo => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyY)), + PredefinedMenuItemType::SelectAll => { + Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyA)) + } + PredefinedMenuItemType::Minimize => { + Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyM)) + } + #[cfg(target_os = "macos")] + PredefinedMenuItemType::Fullscreen => Some(Accelerator::new( + Some(Modifiers::META | Modifiers::CONTROL), + Code::KeyF, + )), + PredefinedMenuItemType::Hide => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyH)), + PredefinedMenuItemType::HideOthers => Some(Accelerator::new( + Some(CMD_OR_CTRL | Modifiers::ALT), + Code::KeyH, + )), + #[cfg(target_os = "macos")] + PredefinedMenuItemType::CloseWindow => { + Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyW)) + } + #[cfg(not(target_os = "macos"))] + PredefinedMenuItemType::CloseWindow => { + Some(Accelerator::new(Some(Modifiers::ALT), Code::F4)) + } + #[cfg(target_os = "macos")] + PredefinedMenuItemType::Quit => Some(Accelerator::new(Some(CMD_OR_CTRL), Code::KeyQ)), + _ => None, + } + } +} diff --git a/ports/muda/src/items/submenu.rs b/ports/muda/src/items/submenu.rs new file mode 100644 index 000000000000..af8e97858f3b --- /dev/null +++ b/ports/muda/src/items/submenu.rs @@ -0,0 +1,328 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.inner +// SPDX-License-Identifier: MIT + +use std::{cell::RefCell, mem, rc::Rc}; + +use crate::{ + dpi::Position, sealed::IsMenuItemBase, util::AddOp, ContextMenu, Icon, IsMenuItem, MenuId, + MenuItemKind, NativeIcon, +}; + +/// A menu that can be added to a [`Menu`] or another [`Submenu`]. +/// +/// [`Menu`]: crate::Menu +#[derive(Clone)] +pub struct Submenu { + pub(crate) id: Rc, + pub(crate) inner: Rc>, +} + +impl IsMenuItemBase for Submenu {} +impl IsMenuItem for Submenu { + fn kind(&self) -> MenuItemKind { + MenuItemKind::Submenu(self.clone()) + } + + fn id(&self) -> &MenuId { + self.id() + } + + fn into_id(self) -> MenuId { + self.into_id() + } +} + +impl Submenu { + /// Create a new submenu. + /// + /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic + /// for this submenu. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn new>(text: S, enabled: bool) -> Self { + let submenu = crate::platform_impl::MenuChild::new_submenu(text.as_ref(), enabled, None); + Self { + id: Rc::new(submenu.id().clone()), + inner: Rc::new(RefCell::new(submenu)), + } + } + + /// Create a new submenu with the specified id. + /// + /// - `text` could optionally contain an `&` before a character to assign this character as the mnemonic + /// for this submenu. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn with_id, S: AsRef>(id: I, text: S, enabled: bool) -> Self { + let id = id.into(); + + Self { + id: Rc::new(id.clone()), + inner: Rc::new(RefCell::new(crate::platform_impl::MenuChild::new_submenu( + text.as_ref(), + enabled, + Some(id), + ))), + } + } + + /// Creates a new submenu with given `items`. It calls [`Submenu::new`] and [`Submenu::append_items`] internally. + pub fn with_items>( + text: S, + enabled: bool, + items: &[&dyn IsMenuItem], + ) -> crate::Result { + let menu = Self::new(text, enabled); + menu.append_items(items)?; + Ok(menu) + } + + /// Creates a new submenu with the specified id and given `items`. It calls [`Submenu::new`] and [`Submenu::append_items`] internally. + pub fn with_id_and_items, S: AsRef>( + id: I, + text: S, + enabled: bool, + items: &[&dyn IsMenuItem], + ) -> crate::Result { + let menu = Self::with_id(id, text, enabled); + menu.append_items(items)?; + Ok(menu) + } + + /// Returns a unique identifier associated with this submenu. + pub fn id(&self) -> &MenuId { + &self.id + } + + /// Add a menu item to the end of this menu. + pub fn append(&self, item: &dyn IsMenuItem) -> crate::Result<()> { + self.inner.borrow_mut().add_menu_item(item, AddOp::Append) + } + + /// Add menu items to the end of this submenu. It calls [`Submenu::append`] in a loop. + pub fn append_items(&self, items: &[&dyn IsMenuItem]) -> crate::Result<()> { + for item in items { + self.append(*item)? + } + + Ok(()) + } + + /// Add a menu item to the beginning of this submenu. + pub fn prepend(&self, item: &dyn IsMenuItem) -> crate::Result<()> { + self.inner + .borrow_mut() + .add_menu_item(item, AddOp::Insert(0)) + } + + /// Add menu items to the beginning of this submenu. + /// It calls [`Menu::prepend`](crate::Menu::prepend) on the first element and + /// passes the rest to [`Menu::insert_items`](crate::Menu::insert_items) with position of `1`. + pub fn prepend_items(&self, items: &[&dyn IsMenuItem]) -> crate::Result<()> { + self.insert_items(items, 0) + } + + /// Insert a menu item at the specified `position` in the submenu. + pub fn insert(&self, item: &dyn IsMenuItem, position: usize) -> crate::Result<()> { + self.inner + .borrow_mut() + .add_menu_item(item, AddOp::Insert(position)) + } + + /// Insert menu items at the specified `position` in the submenu. + pub fn insert_items(&self, items: &[&dyn IsMenuItem], position: usize) -> crate::Result<()> { + for (i, item) in items.iter().enumerate() { + self.insert(*item, position + i)? + } + + Ok(()) + } + + /// Remove a menu item from this submenu. + pub fn remove(&self, item: &dyn IsMenuItem) -> crate::Result<()> { + self.inner.borrow_mut().remove(item) + } + + /// Remove the menu item at the specified position from this submenu and returns it. + pub fn remove_at(&self, position: usize) -> Option { + let mut items = self.items(); + if items.len() > position { + let item = items.remove(position); + let _ = self.remove(item.as_ref()); + Some(item) + } else { + None + } + } + + /// Returns a list of menu items that has been added to this submenu. + pub fn items(&self) -> Vec { + self.inner.borrow().items() + } + + /// Get the text for this submenu. + pub fn text(&self) -> String { + self.inner.borrow().text() + } + + /// Set the text for this submenu. `text` could optionally contain + /// an `&` before a character to assign this character as the mnemonic + /// for this submenu. To display a `&` without assigning a mnemenonic, use `&&`. + pub fn set_text>(&self, text: S) { + self.inner.borrow_mut().set_text(text.as_ref()) + } + + /// Get whether this submenu is enabled or not. + pub fn is_enabled(&self) -> bool { + self.inner.borrow().is_enabled() + } + + /// Enable or disable this submenu. + pub fn set_enabled(&self, enabled: bool) { + self.inner.borrow_mut().set_enabled(enabled) + } + + /// Set this submenu as the Window menu for the application on macOS. + /// This will cause macOS to automatically add window-switching items and + /// certain other items to the menu. + /// + /// Must be called after adding this submenu to [`Menu`](crate::Menu) + /// and after calling [`Menu::init_for_nsapp`](crate::Menu::init_for_nsapp) on that menu. + /// + /// + /// # Note + /// + /// Because a [`Submenu`] can be added multiple times to the same [`Menu`](crate::Menu) + /// this method will set the first instance of this submenu as the Window menu for the application. + /// + /// It is not recommended to add the same submenu multiple times to the same menu, but if you do, be aware of this behavior. + #[cfg(target_os = "macos")] + pub fn set_as_windows_menu_for_nsapp(&self) { + self.inner.borrow_mut().set_as_windows_menu_for_nsapp() + } + + /// Set this submenu as the Help menu for the application on macOS. + /// This will cause macOS to automatically add a search box to the menu. + /// + /// Must be called after adding this submenu to [`Menu`](crate::Menu) + /// and after calling [`Menu::init_for_nsapp`](crate::Menu::init_for_nsapp) on that menu. + /// + /// If no menu is set as the Help menu, macOS will automatically use any menu + /// which has a title matching the localized word "Help". + /// + /// # Note + /// + /// Because a [`Submenu`] can be added multiple times to the same [`Menu`](crate::Menu) + /// this method will set the first instance of this submenu as the Help menu for the application. + /// + /// It is not recommended to add the same submenu multiple times to the same menu, but if you do, be aware of this behavior. + #[cfg(target_os = "macos")] + pub fn set_as_help_menu_for_nsapp(&self) { + self.inner.borrow_mut().set_as_help_menu_for_nsapp() + } + + /// Convert this submenu into its menu ID. + pub fn into_id(mut self) -> MenuId { + // Note: `Rc::into_inner` is available from Rust 1.70 + if let Some(id) = Rc::get_mut(&mut self.id) { + mem::take(id) + } else { + self.id().clone() + } + } + + /// Change this menu item icon or remove it. + pub fn set_icon(&self, icon: Option) { + self.inner.borrow_mut().set_icon(icon) + } + + /// Change this menu item icon to a native image or remove it. + /// + /// ## Platform-specific: + /// + /// - **Windows / Linux**: Unsupported. + pub fn set_native_icon(&self, _icon: Option) { + #[cfg(target_os = "macos")] + self.inner.borrow_mut().set_native_icon(_icon) + } +} + +impl ContextMenu for Submenu { + #[cfg(target_os = "windows")] + fn hpopupmenu(&self) -> isize { + self.inner.borrow().hpopupmenu() + } + + #[cfg(target_os = "windows")] + unsafe fn show_context_menu_for_hwnd(&self, hwnd: isize, position: Option) -> bool { + self.inner + .borrow_mut() + .show_context_menu_for_hwnd(hwnd, position) + } + + #[cfg(target_os = "windows")] + unsafe fn attach_menu_subclass_for_hwnd(&self, hwnd: isize) { + self.inner.borrow().attach_menu_subclass_for_hwnd(hwnd) + } + + #[cfg(target_os = "windows")] + unsafe fn detach_menu_subclass_from_hwnd(&self, hwnd: isize) { + self.inner.borrow().detach_menu_subclass_from_hwnd(hwnd) + } + + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + fn show_context_menu_for_gtk_window( + &self, + w: >k::Window, + position: Option, + ) -> bool { + self.inner + .borrow_mut() + .show_context_menu_for_gtk_window(w, position) + } + + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + fn gtk_context_menu(&self) -> gtk::PopoverMenu { + self.inner.borrow_mut().gtk_context_menu() + } + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + fn compat_items(&self) -> Vec>> { + self.inner.borrow().compat_items() + } + + #[cfg(target_os = "macos")] + unsafe fn show_context_menu_for_nsview( + &self, + view: *const std::ffi::c_void, + position: Option, + ) -> bool { + self.inner + .borrow_mut() + .show_context_menu_for_nsview(view, position) + } + + #[cfg(target_os = "macos")] + fn ns_menu(&self) -> *mut std::ffi::c_void { + self.inner.borrow().ns_menu() + } + + fn as_submenu(&self) -> Option<&Submenu> { + Some(self) + } +} diff --git a/ports/muda/src/lib.rs b/ports/muda/src/lib.rs new file mode 100644 index 000000000000..5257a2e64408 --- /dev/null +++ b/ports/muda/src/lib.rs @@ -0,0 +1,551 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![allow(clippy::uninlined_format_args)] + +//! muda is a Menu Utilities library for Desktop Applications. +//! +//! # Platforms supported: +//! +//! - Windows +//! - macOS +//! - Linux (gtk Only) +//! +//! # Platform-specific notes: +//! +//! - On macOS, menus can only be used from the main thread, and most +//! functionality will panic if you try to use it from any other thread. +//! +//! - On Windows, accelerators don't work unless the win32 message loop calls +//! [`TranslateAcceleratorW`](https://docs.rs/windows-sys/latest/windows_sys/Win32/UI/WindowsAndMessaging/fn.TranslateAcceleratorW.html). +//! See [`Menu::init_for_hwnd`](https://docs.rs/muda/latest/x86_64-pc-windows-msvc/muda/struct.Menu.html#method.init_for_hwnd) for more details +//! +//! # Dependencies (Linux Only) +//! +//! `gtk` is used for menus and `libxdo` is used to make the predefined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work. Be sure to install following packages before building: +//! +//! #### Arch Linux / Manjaro: +//! +//! ```sh +//! pacman -S gtk3 xdotool +//! ``` +//! +//! #### Debian / Ubuntu: +//! +//! ```sh +//! sudo apt install libgtk-3-dev libxdo-dev +//! ``` +//! +//! # Example +//! +//! Create the menu and add your items +//! +//! ```no_run +//! # use muda::{Menu, Submenu, MenuItem, accelerator::{Code, Modifiers, Accelerator}, PredefinedMenuItem}; +//! let menu = Menu::new(); +//! let menu_item2 = MenuItem::new("Menu item #2", false, None); +//! let submenu = Submenu::with_items( +//! "Submenu Outer", +//! true, +//! &[ +//! &MenuItem::new( +//! "Menu item #1", +//! true, +//! Some(Accelerator::new(Some(Modifiers::ALT), Code::KeyD)), +//! ), +//! &PredefinedMenuItem::separator(), +//! &menu_item2, +//! &MenuItem::new("Menu item #3", true, None), +//! &PredefinedMenuItem::separator(), +//! &Submenu::with_items( +//! "Submenu Inner", +//! true, +//! &[ +//! &MenuItem::new("Submenu item #1", true, None), +//! &PredefinedMenuItem::separator(), +//! &menu_item2, +//! ], +//! ).unwrap(), +//! ], +//! ); +//! ``` +//! +//! Then add your root menu to a Window on Windows and Linux +//! or use it as your global app menu on macOS +//! +//! ```no_run +//! # let menu = muda::Menu::new(); +//! # let window_hwnd = 0; +//! # #[cfg(any( +//! target_os = "linux", +//! target_os = "dragonfly", +//! target_os = "freebsd", +//! target_os = "netbsd", +//! target_os = "openbsd" +//! ))] +//! # let gtk_window = gtk::Window::builder().build(); +//! # #[cfg(any( +//! target_os = "linux", +//! target_os = "dragonfly", +//! target_os = "freebsd", +//! target_os = "netbsd", +//! target_os = "openbsd" +//! ))] +//! # let vertical_gtk_box = gtk::Box::new(gtk::Orientation::Vertical, 0); +//! // --snip-- +//! #[cfg(target_os = "windows")] +//! unsafe { menu.init_for_hwnd(window_hwnd) }; +//! #[cfg(any( +//! target_os = "linux", +//! target_os = "dragonfly", +//! target_os = "freebsd", +//! target_os = "netbsd", +//! target_os = "openbsd" +//! ))] +//! menu.init_for_gtk_window(>k_window, Some(&vertical_gtk_box)); +//! #[cfg(target_os = "macos")] +//! menu.init_for_nsapp(); +//! ``` +//! +//! # Context menus (Popup menus) +//! +//! You can also use a [`Menu`] or a [`Submenu`] show a context menu. +//! +//! ```no_run +//! use muda::ContextMenu; +//! # let menu = muda::Menu::new(); +//! # let window_hwnd = 0; +//! # #[cfg(any( +//! target_os = "linux", +//! target_os = "dragonfly", +//! target_os = "freebsd", +//! target_os = "netbsd", +//! target_os = "openbsd" +//! ))] +//! # let gtk_window = gtk::Window::builder().build(); +//! # #[cfg(target_os = "macos")] +//! # let nsview = std::ptr::null(); +//! // --snip-- +//! let position = muda::dpi::PhysicalPosition { x: 100., y: 120. }; +//! #[cfg(target_os = "windows")] +//! unsafe { menu.show_context_menu_for_hwnd(window_hwnd, Some(position.into())) }; +//! #[cfg(any( +//! target_os = "linux", +//! target_os = "dragonfly", +//! target_os = "freebsd", +//! target_os = "netbsd", +//! target_os = "openbsd" +//! ))] +//! menu.show_context_menu_for_gtk_window(>k_window, Some(position.into())); +//! #[cfg(target_os = "macos")] +//! unsafe { menu.show_context_menu_for_nsview(nsview, Some(position.into())) }; +//! ``` +//! # Processing menu events +//! +//! You can use [`MenuEvent::receiver`] to get a reference to the [`MenuEventReceiver`] +//! which you can use to listen to events when a menu item is activated +//! ```no_run +//! # use muda::MenuEvent; +//! # +//! # let save_item: muda::MenuItem = unsafe { std::mem::zeroed() }; +//! if let Ok(event) = MenuEvent::receiver().try_recv() { +//! match event.id { +//! id if id == save_item.id() => { +//! println!("Save menu item activated"); +//! }, +//! _ => {} +//! } +//! } +//! ``` +//! +//! ### Note for [winit] or [tao] users: +//! +//! You should use [`MenuEvent::set_event_handler`] and forward +//! the menu events to the event loop by using [`EventLoopProxy`] +//! so that the event loop is awakened on each menu event. +//! +//! ```no_run +//! # use tao::event_loop::EventLoopBuilder; +//! enum UserEvent { +//! MenuEvent(muda::MenuEvent) +//! } +//! +//! let event_loop = EventLoopBuilder::::with_user_event().build(); +//! +//! let proxy = event_loop.create_proxy(); +//! muda::MenuEvent::set_event_handler(Some(move |event| { +//! proxy.send_event(UserEvent::MenuEvent(event)); +//! })); +//! ``` +//! +//! [`EventLoopProxy`]: https://docs.rs/winit/latest/winit/event_loop/struct.EventLoopProxy.html +//! [winit]: https://docs.rs/winit +//! [tao]: https://docs.rs/tao + +use crossbeam_channel::{unbounded, Receiver, Sender}; +use once_cell::sync::{Lazy, OnceCell}; + +pub mod about_metadata; +pub mod accelerator; +mod builders; +mod error; +mod icon; +mod items; +mod menu; +mod menu_id; +mod platform_impl; +mod util; + +pub use about_metadata::AboutMetadata; +pub use builders::*; +pub use dpi; +pub use error::*; +pub use icon::{BadIcon, Icon, NativeIcon}; +pub use items::*; +pub use menu::*; +pub use menu_id::MenuId; + +/// An enumeration of all available menu types, useful to match against +/// the items returned from [`Menu::items`] or [`Submenu::items`] +#[derive(Clone)] +pub enum MenuItemKind { + MenuItem(MenuItem), + Submenu(Submenu), + Predefined(PredefinedMenuItem), + Check(CheckMenuItem), + Icon(IconMenuItem), +} + +impl MenuItemKind { + /// Returns a unique identifier associated with this menu item. + pub fn id(&self) -> &MenuId { + match self { + MenuItemKind::MenuItem(i) => i.id(), + MenuItemKind::Submenu(i) => i.id(), + MenuItemKind::Predefined(i) => i.id(), + MenuItemKind::Check(i) => i.id(), + MenuItemKind::Icon(i) => i.id(), + } + } + + /// Casts this item to a [`MenuItem`], and returns `None` if it wasn't. + pub fn as_menuitem(&self) -> Option<&MenuItem> { + match self { + MenuItemKind::MenuItem(i) => Some(i), + _ => None, + } + } + + /// Casts this item to a [`MenuItem`], and panics if it wasn't. + pub fn as_menuitem_unchecked(&self) -> &MenuItem { + match self { + MenuItemKind::MenuItem(i) => i, + _ => panic!("Not a MenuItem"), + } + } + + /// Casts this item to a [`Submenu`], and returns `None` if it wasn't. + pub fn as_submenu(&self) -> Option<&Submenu> { + match self { + MenuItemKind::Submenu(i) => Some(i), + _ => None, + } + } + + /// Casts this item to a [`Submenu`], and panics if it wasn't. + pub fn as_submenu_unchecked(&self) -> &Submenu { + match self { + MenuItemKind::Submenu(i) => i, + _ => panic!("Not a Submenu"), + } + } + + /// Casts this item to a [`PredefinedMenuItem`], and returns `None` if it wasn't. + pub fn as_predefined_menuitem(&self) -> Option<&PredefinedMenuItem> { + match self { + MenuItemKind::Predefined(i) => Some(i), + _ => None, + } + } + + /// Casts this item to a [`PredefinedMenuItem`], and panics if it wasn't. + pub fn as_predefined_menuitem_unchecked(&self) -> &PredefinedMenuItem { + match self { + MenuItemKind::Predefined(i) => i, + _ => panic!("Not a PredefinedMenuItem"), + } + } + + /// Casts this item to a [`CheckMenuItem`], and returns `None` if it wasn't. + pub fn as_check_menuitem(&self) -> Option<&CheckMenuItem> { + match self { + MenuItemKind::Check(i) => Some(i), + _ => None, + } + } + + /// Casts this item to a [`CheckMenuItem`], and panics if it wasn't. + pub fn as_check_menuitem_unchecked(&self) -> &CheckMenuItem { + match self { + MenuItemKind::Check(i) => i, + _ => panic!("Not a CheckMenuItem"), + } + } + + /// Casts this item to a [`IconMenuItem`], and returns `None` if it wasn't. + pub fn as_icon_menuitem(&self) -> Option<&IconMenuItem> { + match self { + MenuItemKind::Icon(i) => Some(i), + _ => None, + } + } + + /// Casts this item to a [`IconMenuItem`], and panics if it wasn't. + pub fn as_icon_menuitem_unchecked(&self) -> &IconMenuItem { + match self { + MenuItemKind::Icon(i) => i, + _ => panic!("Not an IconMenuItem"), + } + } + + /// Convert this item into its menu ID. + pub fn into_id(self) -> MenuId { + match self { + MenuItemKind::MenuItem(i) => i.into_id(), + MenuItemKind::Submenu(i) => i.into_id(), + MenuItemKind::Predefined(i) => i.into_id(), + MenuItemKind::Check(i) => i.into_id(), + MenuItemKind::Icon(i) => i.into_id(), + } + } +} + +/// A trait that defines a generic item in a menu, which may be one of [`MenuItemKind`] +pub trait IsMenuItem: sealed::IsMenuItemBase { + /// Returns a [`MenuItemKind`] associated with this item. + fn kind(&self) -> MenuItemKind; + /// Returns a unique identifier associated with this menu item. + fn id(&self) -> &MenuId; + /// Convert this menu item into its menu ID. + fn into_id(self) -> MenuId; +} + +mod sealed { + pub trait IsMenuItemBase {} +} + +#[derive(Debug, PartialEq, PartialOrd, Clone, Copy, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub(crate) enum MenuItemType { + #[default] + MenuItem, + Submenu, + Predefined, + Check, + Icon, +} + +/// A helper trait with methods to help creating a context menu. +pub trait ContextMenu { + /// Get the popup [`HMENU`] for this menu. + /// + /// The returned [`HMENU`] is valid as long as the `ContextMenu` is. + /// + /// [`HMENU`]: windows_sys::Win32::UI::WindowsAndMessaging::HMENU + #[cfg(target_os = "windows")] + fn hpopupmenu(&self) -> isize; + + /// Shows this menu as a context menu inside a win32 window. + /// + /// - `position` is relative to the window top-left corner, if `None`, the cursor position is used. + /// + /// Returns `true` if menu tracking ended because an item was selected, and `false` if menu tracking was cancelled for any reason. + /// + /// # Safety + /// + /// The `hwnd` must be a valid window HWND. + #[cfg(target_os = "windows")] + unsafe fn show_context_menu_for_hwnd( + &self, + hwnd: isize, + position: Option, + ) -> bool; + + /// Attach the menu subclass handler to the given hwnd + /// so you can receive events from that window using [MenuEvent::receiver] + /// + /// This can be used along with [`ContextMenu::hpopupmenu`] when implementing a tray icon menu. + /// + /// # Safety + /// + /// The `hwnd` must be a valid window HWND. + #[cfg(target_os = "windows")] + unsafe fn attach_menu_subclass_for_hwnd(&self, hwnd: isize); + + /// Remove the menu subclass handler from the given hwnd + /// + /// The view must be a pointer to a valid `NSView`. + /// + /// # Safety + /// + /// The `hwnd` must be a valid window HWND. + #[cfg(target_os = "windows")] + unsafe fn detach_menu_subclass_from_hwnd(&self, hwnd: isize); + + /// Shows this menu as a context menu inside a [`gtk::Window`] + /// + /// - `position` is relative to the window top-left corner, if `None`, the cursor position is used. + /// + /// Returns `true` if menu tracking ended because an item was selected or clicked outside the menu to dismiss it. + /// + /// Returns `false` if menu tracking was cancelled for any reason. + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + fn show_context_menu_for_gtk_window( + &self, + w: >k::Window, + position: Option, + ) -> bool; + + /// Get the underlying gtk menu reserved for context menus. + /// + /// The returned [`gtk::PopoverMenu`] is valid as long as the `ContextMenu` is. + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + fn gtk_context_menu(&self) -> gtk::PopoverMenu; + + /// Shows this menu as a context menu for the specified `NSView`. + /// + /// - `position` is relative to the window top-left corner, if `None`, the cursor position is used. + /// + /// Returns `true` if menu tracking ended because an item was selected, and `false` if menu tracking was cancelled for any reason. + /// + /// # Safety + /// + /// The view must be a pointer to a valid `NSView`. + #[cfg(target_os = "macos")] + unsafe fn show_context_menu_for_nsview( + &self, + view: *const std::ffi::c_void, + position: Option, + ) -> bool; + + /// Get the underlying NSMenu reserved for context menus. + /// + /// The returned pointer is valid for as long as the `ContextMenu` is. If + /// you need it to be alive for longer, retain it. + #[cfg(target_os = "macos")] + fn ns_menu(&self) -> *mut std::ffi::c_void; + + /// Cast this context menu to a [`Menu`], and returns `None` if it wasn't. + fn as_menu(&self) -> Option<&Menu> { + None + } + + /// Casts this context menu to a [`Menu`], and panics if it wasn't. + fn as_menu_unchecked(&self) -> &Menu { + self.as_menu().expect("Not a Menu") + } + + /// Cast this context menu to a [`Submenu`], and returns `None` if it wasn't. + fn as_submenu(&self) -> Option<&Submenu> { + None + } + + /// Casts this context menu to a [`Submenu`], and panics if it wasn't. + fn as_submenu_unchecked(&self) -> &Menu { + self.as_menu().expect("Not a Submenu") + } + + /// Returns a GTK-agnostic menu representation for Linux KSNI tray menus. + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + fn compat_items(&self) -> Vec>>; +} + +/// Describes a menu event emitted when a menu item is activated +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct MenuEvent { + /// Id of the menu item which triggered this event + pub id: MenuId, +} + +/// A receiver that could be used to listen to menu events. +pub type MenuEventReceiver = Receiver; +type MenuEventHandler = Box; + +static MENU_CHANNEL: Lazy<(Sender, MenuEventReceiver)> = Lazy::new(unbounded); +static MENU_EVENT_HANDLER: OnceCell> = OnceCell::new(); +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] +static MENU_UPDATE_CHANNEL: Lazy<(Sender<()>, Receiver<()>)> = Lazy::new(unbounded); + +impl MenuEvent { + /// Returns the id of the menu item which triggered this event + pub fn id(&self) -> &MenuId { + &self.id + } + + /// Gets a reference to the event channel's [`MenuEventReceiver`] + /// which can be used to listen for menu events. + /// + /// ## Note + /// + /// This will not receive any events if [`MenuEvent::set_event_handler`] has been called with a `Some` value. + pub fn receiver<'a>() -> &'a MenuEventReceiver { + &MENU_CHANNEL.1 + } + + /// Set a handler to be called for new events. Useful for implementing custom event sender. + /// + /// ## Note + /// + /// Calling this function with a `Some` value, + /// will not send new events to the channel associated with [`MenuEvent::receiver`] + pub fn set_event_handler(f: Option) { + if let Some(f) = f { + let _ = MENU_EVENT_HANDLER.set(Some(Box::new(f))); + } else { + let _ = MENU_EVENT_HANDLER.set(None); + } + } + + pub(crate) fn send(event: MenuEvent) { + if let Some(handler) = MENU_EVENT_HANDLER.get_or_init(|| None) { + handler(event); + } else { + let _ = MENU_CHANNEL.0.send(event); + } + } +} + +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] +pub fn recv_menu_update() -> std::result::Result<(), crossbeam_channel::RecvError> { + MENU_UPDATE_CHANNEL.1.recv() +} + +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] +pub fn send_menu_update() { + let _ = MENU_UPDATE_CHANNEL.0.send(()); +} + +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] +pub fn send_menu_event(event: MenuEvent) { + MenuEvent::send(event); +} diff --git a/ports/muda/src/menu.rs b/ports/muda/src/menu.rs new file mode 100644 index 000000000000..765b2fc09dfc --- /dev/null +++ b/ports/muda/src/menu.rs @@ -0,0 +1,521 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.inner +// SPDX-License-Identifier: MIT + +use std::{cell::RefCell, rc::Rc}; + +use crate::{dpi::Position, util::AddOp, ContextMenu, IsMenuItem, MenuId, MenuItemKind}; + +/// A root menu that can be added to a Window on Windows and Linux +/// and used as the app global menu on macOS. +#[derive(Clone)] +pub struct Menu { + id: Rc, + inner: Rc>, +} + +impl Default for Menu { + fn default() -> Self { + Self::new() + } +} + +impl Menu { + /// Creates a new menu. + pub fn new() -> Self { + let menu = crate::platform_impl::Menu::new(None); + Self { + id: Rc::new(menu.id().clone()), + inner: Rc::new(RefCell::new(menu)), + } + } + + /// Creates a new menu with the specified id. + pub fn with_id>(id: I) -> Self { + let id = id.into(); + Self { + id: Rc::new(id.clone()), + inner: Rc::new(RefCell::new(crate::platform_impl::Menu::new(Some(id)))), + } + } + + /// Creates a new menu with given `items`. It calls [`Menu::new`] and [`Menu::append_items`] internally. + pub fn with_items(items: &[&dyn IsMenuItem]) -> crate::Result { + let menu = Self::new(); + menu.append_items(items)?; + Ok(menu) + } + + /// Creates a new menu with the specified id and given `items`. It calls [`Menu::new`] and [`Menu::append_items`] internally. + pub fn with_id_and_items>( + id: I, + items: &[&dyn IsMenuItem], + ) -> crate::Result { + let menu = Self::with_id(id); + menu.append_items(items)?; + Ok(menu) + } + + /// Returns a unique identifier associated with this menu. + pub fn id(&self) -> &MenuId { + &self.id + } + + /// Add a menu item to the end of this menu. + /// + /// ## Platform-specific: + /// + /// - **macOS:** Only [`Submenu`] can be added to the menu + /// + /// [`Submenu`]: crate::Submenu + pub fn append(&self, item: &dyn IsMenuItem) -> crate::Result<()> { + self.inner.borrow_mut().add_menu_item(item, AddOp::Append) + } + + /// Add menu items to the end of this menu. It calls [`Menu::append`] in a loop internally. + /// + /// ## Platform-specific: + /// + /// - **macOS:** Only [`Submenu`] can be added to the menu + /// + /// [`Submenu`]: crate::Submenu + pub fn append_items(&self, items: &[&dyn IsMenuItem]) -> crate::Result<()> { + for item in items { + self.append(*item)? + } + + Ok(()) + } + + /// Add a menu item to the beginning of this menu. + /// + /// ## Platform-specific: + /// + /// - **macOS:** Only [`Submenu`] can be added to the menu + /// + /// [`Submenu`]: crate::Submenu + pub fn prepend(&self, item: &dyn IsMenuItem) -> crate::Result<()> { + self.inner + .borrow_mut() + .add_menu_item(item, AddOp::Insert(0)) + } + + /// Add menu items to the beginning of this menu. It calls [`Menu::insert_items`] with position of `0` internally. + /// + /// ## Platform-specific: + /// + /// - **macOS:** Only [`Submenu`] can be added to the menu + /// + /// [`Submenu`]: crate::Submenu + pub fn prepend_items(&self, items: &[&dyn IsMenuItem]) -> crate::Result<()> { + self.insert_items(items, 0) + } + + /// Insert a menu item at the specified `position` in the menu. + /// + /// ## Platform-specific: + /// + /// - **macOS:** Only [`Submenu`] can be added to the menu + /// + /// [`Submenu`]: crate::Submenu + pub fn insert(&self, item: &dyn IsMenuItem, position: usize) -> crate::Result<()> { + self.inner + .borrow_mut() + .add_menu_item(item, AddOp::Insert(position)) + } + + /// Insert menu items at the specified `position` in the menu. + /// + /// ## Platform-specific: + /// + /// - **macOS:** Only [`Submenu`] can be added to the menu + /// + /// [`Submenu`]: crate::Submenu + pub fn insert_items(&self, items: &[&dyn IsMenuItem], position: usize) -> crate::Result<()> { + for (i, item) in items.iter().enumerate() { + self.insert(*item, position + i)? + } + + Ok(()) + } + + /// Remove a menu item from this menu. + pub fn remove(&self, item: &dyn IsMenuItem) -> crate::Result<()> { + self.inner.borrow_mut().remove(item) + } + + /// Remove the menu item at the specified position from this menu and returns it. + pub fn remove_at(&self, position: usize) -> Option { + let mut items = self.items(); + if items.len() > position { + let item = items.remove(position); + let _ = self.remove(item.as_ref()); + Some(item) + } else { + None + } + } + + /// Returns a list of menu items that has been added to this menu. + pub fn items(&self) -> Vec { + self.inner.borrow().items() + } + + /// Adds this menu to a [`gtk::Window`] + /// + /// - `container`: this is an optional parameter to specify a container for the [`gtk::MenuBar`], + /// it is highly recommended to pass a container, otherwise the menubar will be added directly to the window, + /// which is usually not the desired behavior. + /// If using a [`gtk::Box`] as a container, it is added using [`Box::pack_start(menubar, false, false, 0)`](gtk::prelude::BoxExt::pack_start) then + /// reordered to be the first child of [`gtk::Box`] using [`Box::reorder_child(menubar, 0)`](gtk::prelude::BoxExt::reorder_child). + /// + /// ## Example: + /// ```no_run + /// let window = gtk::Window::builder().build(); + /// let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0); + /// let menu = muda::Menu::new(); + /// // -- snip, add your menu items -- + /// menu.init_for_gtk_window(&window, Some(&vbox)); + /// // then proceed to add your widgets to the `vbox` + /// ``` + /// + /// ## Panics: + /// + /// Panics if the gtk event loop hasn't been initialized on the thread. + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + pub fn init_for_gtk_window(&self, window: &W, container: Option<&C>) -> crate::Result<()> + where + W: gtk::prelude::IsA, + W: gtk::prelude::IsA, + C: gtk::prelude::IsA, + { + self.inner + .borrow_mut() + .init_for_gtk_window(window, container) + } + + /// Adds this menu to a win32 window. + /// + /// # Safety + /// + /// The `hwnd` must be a valid window HWND. + /// + /// ## Note about accelerators: + /// + /// For accelerators to work, the event loop needs to call + /// [`TranslateAcceleratorW`](windows_sys::Win32::UI::WindowsAndMessaging::TranslateAcceleratorW) + /// with the [`HACCEL`](windows_sys::Win32::UI::WindowsAndMessaging::HACCEL) returned from [`Menu::haccel`] + /// + /// #### Example: + /// ```no_run + /// # use muda::Menu; + /// # use windows_sys::Win32::UI::WindowsAndMessaging::{MSG, GetMessageW, TranslateMessage, DispatchMessageW, TranslateAcceleratorW}; + /// let menu = Menu::new(); + /// unsafe { + /// let mut msg: MSG = std::mem::zeroed(); + /// while GetMessageW(&mut msg, std::ptr::null_mut(), 0, 0) == 1 { + /// let translated = TranslateAcceleratorW(msg.hwnd, menu.haccel() as _, &msg as *const _); + /// if translated != 1{ + /// TranslateMessage(&msg); + /// DispatchMessageW(&msg); + /// } + /// } + /// } + /// ``` + #[cfg(target_os = "windows")] + pub unsafe fn init_for_hwnd(&self, hwnd: isize) -> crate::Result<()> { + self.inner.borrow_mut().init_for_hwnd(hwnd) + } + + /// Adds this menu to a win32 window using the specified theme. + /// + /// See [Menu::init_for_hwnd] for more info. + /// + /// Note that the theme only affects the menu bar itself and not submenus or context menu. + /// + /// # Safety + /// + /// The `hwnd` must be a valid window HWND. + #[cfg(target_os = "windows")] + pub unsafe fn init_for_hwnd_with_theme( + &self, + hwnd: isize, + theme: MenuTheme, + ) -> crate::Result<()> { + self.inner + .borrow_mut() + .init_for_hwnd_with_theme(hwnd, theme) + } + + /// Set a theme for the menu bar on this window. + /// + /// Note that the theme only affects the menu bar itself and not submenus or context menu. + /// + /// # Safety + /// + /// The `hwnd` must be a valid window HWND. + #[cfg(target_os = "windows")] + pub unsafe fn set_theme_for_hwnd(&self, hwnd: isize, theme: MenuTheme) -> crate::Result<()> { + self.inner.borrow().set_theme_for_hwnd(hwnd, theme) + } + + /// Returns The [`HACCEL`](windows_sys::Win32::UI::WindowsAndMessaging::HACCEL) associated with this menu + /// It can be used with [`TranslateAcceleratorW`](windows_sys::Win32::UI::WindowsAndMessaging::TranslateAcceleratorW) + /// in the event loop to enable accelerators + /// + /// The returned [`HACCEL`](windows_sys::Win32::UI::WindowsAndMessaging::HACCEL) is valid as long as the [Menu] is. + #[cfg(target_os = "windows")] + pub fn haccel(&self) -> isize { + self.inner.borrow_mut().haccel() + } + + /// Removes this menu from a [`gtk::Window`] + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + pub fn remove_for_gtk_window(&self, window: &W) -> crate::Result<()> + where + W: gtk::prelude::IsA, + W: gtk::prelude::IsA, + { + self.inner.borrow_mut().remove_for_gtk_window(window) + } + + /// Removes this menu from a win32 window + /// + /// # Safety + /// + /// The `hwnd` must be a valid window HWND. + #[cfg(target_os = "windows")] + pub unsafe fn remove_for_hwnd(&self, hwnd: isize) -> crate::Result<()> { + self.inner.borrow_mut().remove_for_hwnd(hwnd) + } + + /// Hides this menu from a [`gtk::Window`] + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + pub fn hide_for_gtk_window(&self, window: &W) -> crate::Result<()> + where + W: gtk::prelude::IsA, + W: gtk::prelude::IsA, + { + self.inner.borrow_mut().hide_for_gtk_window(window) + } + + /// Hides this menu from a win32 window + /// + /// # Safety + /// + /// The `hwnd` must be a valid window HWND. + #[cfg(target_os = "windows")] + pub unsafe fn hide_for_hwnd(&self, hwnd: isize) -> crate::Result<()> { + self.inner.borrow().hide_for_hwnd(hwnd) + } + + /// Shows this menu on a [`gtk::Window`] + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + pub fn show_for_gtk_window(&self, window: &W) -> crate::Result<()> + where + W: gtk::prelude::IsA, + W: gtk::prelude::IsA, + { + self.inner.borrow_mut().show_for_gtk_window(window) + } + + /// Shows this menu on a win32 window + /// + /// # Safety + /// + /// The `hwnd` must be a valid window HWND. + #[cfg(target_os = "windows")] + pub unsafe fn show_for_hwnd(&self, hwnd: isize) -> crate::Result<()> { + self.inner.borrow().show_for_hwnd(hwnd) + } + + /// Returns whether this menu visible on a [`gtk::Window`] + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + pub fn is_visible_on_gtk_window(&self, window: &W) -> bool + where + W: gtk::prelude::IsA, + W: gtk::prelude::IsA, + { + self.inner.borrow().is_visible_on_gtk_window(window) + } + + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + /// Returns the [`gtk::PopoverMenuBar`] that is associated with this window if it exists. + /// This is useful to get information about the menubar for example its height. + pub fn gtk_menubar_for_gtk_window(self, window: &W) -> Option + where + W: gtk::prelude::IsA, + { + self.inner.borrow().gtk_menubar_for_gtk_window(window) + } + + /// Returns whether this menu visible on a on a win32 window + /// + /// # Safety + /// + /// The `hwnd` must be a valid window HWND. + #[cfg(target_os = "windows")] + pub unsafe fn is_visible_on_hwnd(&self, hwnd: isize) -> bool { + self.inner.borrow().is_visible_on_hwnd(hwnd) + } + + /// Adds this menu to an NSApp. + #[cfg(target_os = "macos")] + pub fn init_for_nsapp(&self) { + self.inner.borrow_mut().init_for_nsapp() + } + + /// Removes this menu from an NSApp. + #[cfg(target_os = "macos")] + pub fn remove_for_nsapp(&self) { + self.inner.borrow_mut().remove_for_nsapp() + } +} + +impl ContextMenu for Menu { + #[cfg(target_os = "windows")] + fn hpopupmenu(&self) -> isize { + self.inner.borrow().hpopupmenu() + } + + #[cfg(target_os = "windows")] + unsafe fn show_context_menu_for_hwnd(&self, hwnd: isize, position: Option) -> bool { + self.inner + .borrow_mut() + .show_context_menu_for_hwnd(hwnd, position) + } + + #[cfg(target_os = "windows")] + unsafe fn attach_menu_subclass_for_hwnd(&self, hwnd: isize) { + self.inner.borrow().attach_menu_subclass_for_hwnd(hwnd) + } + + #[cfg(target_os = "windows")] + unsafe fn detach_menu_subclass_from_hwnd(&self, hwnd: isize) { + self.inner.borrow().detach_menu_subclass_from_hwnd(hwnd) + } + + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + fn show_context_menu_for_gtk_window( + &self, + window: >k::Window, + position: Option, + ) -> bool { + self.inner + .borrow_mut() + .show_context_menu_for_gtk_window(window, position) + } + + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + fn gtk_context_menu(&self) -> gtk::PopoverMenu { + self.inner.borrow_mut().gtk_context_menu() + } + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + fn compat_items(&self) -> Vec>> { + self.inner.borrow().compat_items() + } + + #[cfg(target_os = "macos")] + unsafe fn show_context_menu_for_nsview( + &self, + view: *const std::ffi::c_void, + position: Option, + ) -> bool { + self.inner + .borrow_mut() + .show_context_menu_for_nsview(view, position) + } + + #[cfg(target_os = "macos")] + fn ns_menu(&self) -> *mut std::ffi::c_void { + self.inner.borrow().ns_menu() + } + + fn as_menu(&self) -> Option<&Menu> { + Some(self) + } +} + +/// The window menu bar theme +#[cfg(windows)] +#[repr(usize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum MenuTheme { + Dark = 0, + Light = 1, + Auto = 2, +} diff --git a/ports/muda/src/menu_id.rs b/ports/muda/src/menu_id.rs new file mode 100644 index 000000000000..6c98f5c0e805 --- /dev/null +++ b/ports/muda/src/menu_id.rs @@ -0,0 +1,85 @@ +use std::{convert::Infallible, str::FromStr}; + +/// An unique id that is associated with a menu or a menu item. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct MenuId(pub String); + +impl MenuId { + /// Create a new menu id. + pub fn new>(id: S) -> Self { + Self(id.as_ref().to_string()) + } +} + +impl AsRef for MenuId { + fn as_ref(&self) -> &str { + self.0.as_ref() + } +} + +impl From for MenuId { + fn from(value: T) -> Self { + Self(value.to_string()) + } +} + +impl FromStr for MenuId { + type Err = Infallible; + + fn from_str(s: &str) -> std::result::Result { + Ok(Self::new(s)) + } +} + +impl PartialEq<&str> for MenuId { + fn eq(&self, other: &&str) -> bool { + self.0 == *other + } +} + +impl PartialEq<&str> for &MenuId { + fn eq(&self, other: &&str) -> bool { + self.0 == *other + } +} + +impl PartialEq for MenuId { + fn eq(&self, other: &String) -> bool { + self.0 == *other + } +} + +impl PartialEq for &MenuId { + fn eq(&self, other: &String) -> bool { + self.0 == *other + } +} + +impl PartialEq<&String> for MenuId { + fn eq(&self, other: &&String) -> bool { + self.0 == **other + } +} + +impl PartialEq<&MenuId> for MenuId { + fn eq(&self, other: &&MenuId) -> bool { + other.0 == self.0 + } +} + +#[cfg(test)] +mod test { + use crate::MenuId; + + #[test] + fn is_eq() { + assert_eq!(MenuId::new("t"), "t",); + assert_eq!(MenuId::new("t"), String::from("t")); + assert_eq!(MenuId::new("t"), &String::from("t")); + assert_eq!(MenuId::new("t"), MenuId::new("t")); + assert_eq!(MenuId::new("t"), &MenuId::new("t")); + assert_eq!(&MenuId::new("t"), &MenuId::new("t")); + assert_eq!(MenuId::new("t").as_ref(), "t"); + } +} diff --git a/ports/muda/src/platform_impl/gtk/about_dialog.rs b/ports/muda/src/platform_impl/gtk/about_dialog.rs new file mode 100644 index 000000000000..357ae5942455 --- /dev/null +++ b/ports/muda/src/platform_impl/gtk/about_dialog.rs @@ -0,0 +1,103 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! Thread-safe AboutDialog wrapper for ksni tray support. +//! +//! This module provides an AboutDialog that can be safely called from +//! any thread (including ksni's DBus thread) by dispatching to the +//! GTK main thread. + +use gtk4::prelude::GtkWindowExt; + +use crate::AboutMetadata; + +/// A thread-safe wrapper around the GTK AboutDialog. +/// +/// This can be safely called from any thread, including the ksni DBus thread. +/// The `show()` method dispatches to the GTK main thread internally. +#[derive(Debug, Clone)] +pub struct AboutDialog { + metadata: AboutMetadata, +} + +impl AboutDialog { + /// Creates a new AboutDialog with the given metadata. + pub fn new(metadata: AboutMetadata) -> Self { + Self { metadata } + } + + /// Creates a new AboutDialog from compat metadata (for ksni use). + /// + /// This is useful when you have a `CompatAboutMetadata` from the compat layer. + + /// Shows the about dialog. + /// + /// This method is safe to call from any thread - it dispatches + /// to the GTK main thread internally using `glib::MainContext::default().invoke()`. + pub fn show(&self) { + let metadata = self.metadata.clone(); + + gtk4::glib::MainContext::default().invoke(move || { + let dialog = gtk4::AboutDialog::new(); + + // Set dialog properties from metadata + if let Some(ref name) = metadata.name { + dialog.set_program_name(Some(name)); + } + + if let Some(ref version) = metadata.version { + dialog.set_version(Some(version)); + } + + if let Some(ref short_version) = metadata.short_version { + // GTK4 doesn't have a separate short version, but we can include it + // in the version string if both are set + if metadata.version.is_some() { + // Version is already set, we could append short_version but + // GTK4's AboutDialog handles this differently than macOS + let _ = short_version; // Acknowledge unused on GTK4 + } else { + dialog.set_version(Some(short_version)); + } + } + + if let Some(ref copyright) = metadata.copyright { + dialog.set_copyright(Some(copyright)); + } + + if let Some(ref comments) = metadata.comments { + dialog.set_comments(Some(comments)); + } + + if let Some(ref license) = metadata.license { + dialog.set_license(Some(license)); + } + + if let Some(ref website) = metadata.website { + dialog.set_website(Some(website)); + } + + if let Some(ref website_label) = metadata.website_label { + dialog.set_website_label(website_label); + } + + if let Some(ref authors) = metadata.authors { + let authors_strs: Vec<&str> = authors.iter().map(|s| s.as_str()).collect(); + dialog.set_authors(&authors_strs); + } + + // Note: credits in muda is Option, not used directly in GTK4 + // The credits field is primarily for macOS + let _ = &metadata.credits; + + // Present the dialog + dialog.present(); + }); + } + + /// Returns a reference to the metadata. + pub fn metadata(&self) -> &AboutMetadata { + &self.metadata + } +} diff --git a/ports/muda/src/platform_impl/gtk/accelerator.rs b/ports/muda/src/platform_impl/gtk/accelerator.rs new file mode 100644 index 000000000000..f4f9f2d2309d --- /dev/null +++ b/ports/muda/src/platform_impl/gtk/accelerator.rs @@ -0,0 +1,58 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use keyboard_types::{Key, Modifiers}; + +use crate::accelerator::KeyAccelerator; + +impl KeyAccelerator { + /// Render as a GTK accelerator string, e.g. `c`. + /// + /// The result is parseable by `gtk::accelerator_parse` and accepted by + /// `gio::prelude::ActionMapExt::set_accels_for_action`. + pub fn to_gtk(&self) -> String { + let mut gtk = modifiers_to_gtk(self.modifiers()); + gtk.push_str(&key_to_gtk(self.key())); + gtk + } +} + +fn modifiers_to_gtk(mods: Modifiers) -> String { + let mut gtk = String::new(); + + if mods.contains(Modifiers::SHIFT) { + gtk.push_str(""); + } + if mods.contains(Modifiers::CONTROL) { + gtk.push_str(""); + } + if mods.contains(Modifiers::ALT) { + gtk.push_str(""); + } + if mods.contains(Modifiers::META) { + gtk.push_str(""); + } + gtk +} + +fn key_to_gtk(key: &Key) -> String { + match key { + // A single character maps straight to its GDK key name, except + // space, which GDK names rather than prints. + Key::Character(c) if c == " " => "space".to_string(), + Key::Character(c) => c.to_lowercase(), + // Named keys whose GDK name differs from the W3C name. + Key::Enter => "Return".to_string(), + Key::ArrowUp => "Up".to_string(), + Key::ArrowDown => "Down".to_string(), + Key::ArrowLeft => "Left".to_string(), + Key::ArrowRight => "Right".to_string(), + Key::Backspace => "BackSpace".to_string(), + Key::PageUp => "Page_Up".to_string(), + Key::PageDown => "Page_Down".to_string(), + // Escape, Delete, Tab, Home, End, Insert, F-keys, and space + // already match the GDK name that `accelerator_parse` understands. + other => other.to_string(), + } +} diff --git a/ports/muda/src/platform_impl/gtk/icon.rs b/ports/muda/src/platform_impl/gtk/icon.rs new file mode 100644 index 000000000000..ba321b0ba013 --- /dev/null +++ b/ports/muda/src/platform_impl/gtk/icon.rs @@ -0,0 +1,53 @@ +// Copyright 2014-2021 The winit contributors +// Copyright 2021-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 + +use crate::icon::BadIcon; + +/// An icon used for the window titlebar, taskbar, etc. +/// +/// Stores raw PNG bytes to be `Send + Sync` safe. The GTK `BytesIcon` +/// is created lazily when needed on the GTK main thread. +#[derive(Debug, Clone)] +pub struct PlatformIcon { + png_data: Vec, +} + +// PlatformIcon is Send + Sync because it only contains Vec +// The BytesIcon is created lazily on the GTK main thread when needed +unsafe impl Send for PlatformIcon {} +unsafe impl Sync for PlatformIcon {} + +impl PlatformIcon { + /// Creates an `Icon` from 32bpp RGBA data. + /// + /// The length of `rgba` must be divisible by 4, and `width * height` must equal + /// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error. + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + let mut png_data = Vec::with_capacity(rgba.len()); + + let mut encoder = png::Encoder::new(&mut png_data, width, height); + encoder.set_color(png::ColorType::Rgba); + encoder.set_depth(png::BitDepth::Eight); + let mut writer = encoder.write_header().map_err(BadIcon::PngEncodingError)?; + writer + .write_image_data(&rgba) + .map_err(BadIcon::PngEncodingError)?; + writer.finish().map_err(BadIcon::PngEncodingError)?; + + Ok(Self { png_data }) + } + + /// Creates a GTK `BytesIcon` from the stored PNG data. + /// + /// This should only be called on the GTK main thread. + pub fn to_bytes_icon(&self) -> gtk::gio::BytesIcon { + let bytes = gtk::glib::Bytes::from(&self.png_data); + gtk::gio::BytesIcon::new(&bytes) + } + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + pub(crate) fn png_data(&self) -> Vec { + self.png_data.clone() + } +} diff --git a/ports/muda/src/platform_impl/gtk/mnemonic.rs b/ports/muda/src/platform_impl/gtk/mnemonic.rs new file mode 100644 index 000000000000..012e5db37a75 --- /dev/null +++ b/ports/muda/src/platform_impl/gtk/mnemonic.rs @@ -0,0 +1,72 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +/// Converts from muda mnemonic to gtk mnemonic +/// +/// gtk uses underline (_) for mnemonic +/// and two underlines (__) to escape it into a single underline +/// while we use (&) and (&&), so we have to do a few conversions +pub fn to_gtk_mnemonic>(string: S) -> String { + string + .as_ref() + // escape underlines + .replace("_", "__") + // perserve && + .replace("&&", "[~~]") + // transfrom & -> _ + .replace('&', "_") + // revert back && to unsecaped & + .replace("[~~]", "&") +} + +/// Converts from gtk mnemonic to muda mnemonic +/// +/// gtk uses underline (_) for mnemonic +/// and two underlines (__) to escape it into a single underline +/// while we use (&) and (&&), so we have to do a few conversions +#[cfg(test)] +pub fn from_gtk_mnemonic>(string: S) -> String { + string + .as_ref() + // transform escaped & to unescaped && + .replace("&", "&&") + // perserve __ + .replace("__", "[~~]") + // transfrom _ -> & + .replace('_', "&") + // revert back __ to unescaped _ + .replace("[~~]", "_") +} + +#[cfg(test)] +mod tests { + use crate::platform_impl::platform::mnemonic::{from_gtk_mnemonic, to_gtk_mnemonic}; + + #[test] + fn it_converts() { + assert_eq!(to_gtk_mnemonic("H&ello"), "H_ello"); + assert_eq!(to_gtk_mnemonic("H&&ello"), "H&ello"); + assert_eq!(to_gtk_mnemonic("H&&&ello"), "H&_ello"); + assert_eq!(to_gtk_mnemonic("H_ello"), "H__ello"); + assert_eq!(to_gtk_mnemonic("H__ello"), "H____ello"); + } + + #[test] + fn it_converts_back() { + let str = "H&ello"; + assert_eq!(from_gtk_mnemonic(to_gtk_mnemonic(str)), str); + + let str = "H&&ello"; + assert_eq!(from_gtk_mnemonic(to_gtk_mnemonic(str)), str); + + let str = "H&&&ello"; + assert_eq!(from_gtk_mnemonic(to_gtk_mnemonic(str)), str); + + let str = "H_ello"; + assert_eq!(from_gtk_mnemonic(to_gtk_mnemonic(str)), str); + + let str = "H__ello"; + assert_eq!(from_gtk_mnemonic(to_gtk_mnemonic(str)), str); + } +} diff --git a/ports/muda/src/platform_impl/gtk/mod.rs b/ports/muda/src/platform_impl/gtk/mod.rs new file mode 100644 index 000000000000..7d8164d2d86b --- /dev/null +++ b/ports/muda/src/platform_impl/gtk/mod.rs @@ -0,0 +1,1473 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +mod accelerator; +mod icon; +mod mnemonic; + +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] +use std::sync::Arc; +use std::{ + cell::RefCell, + collections::{hash_map::Entry, HashMap}, + rc::Rc, +}; + +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] +use arc_swap::ArcSwap; +use dpi::Position; +use gtk::{gdk::Rectangle, gio, prelude::*}; +pub(crate) use icon::PlatformIcon; +use mnemonic::to_gtk_mnemonic; + +use crate::{ + accelerator::KeyAccelerator, + util::{AddOp, Counter}, + Icon, IsMenuItem, MenuEvent, MenuId, MenuItemKind, MenuItemType, NativeIcon, + PredefinedMenuItemType, +}; + +static COUNTER: Counter = Counter::new(); + +const DEFAULT_ACTION_GROUP: &str = "muda"; +const ACTION_GROUP_DATA_KEY: &str = "mudaActionGroup"; + +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] +fn compat_placeholder() -> Arc> { + Arc::new(ArcSwap::from_pointee(crate::CompatMenuItem::Separator)) +} + +enum GtkMenuBar { + MenuBar { + widget: gtk::PopoverMenuBar, + menu: gio::Menu, + app: gtk::Application, + }, + ContextMenu { + widget: gtk::PopoverMenu, + menu: gio::Menu, + app: gtk::Application, + }, +} + +impl GtkMenuBar { + fn new(app: gtk::Application) -> Self { + let menu = gio::Menu::new(); + let widget = gtk::PopoverMenuBar::from_model(Some(&menu)); + Self::MenuBar { widget, menu, app } + } + + fn new_context(app: gtk::Application) -> Self { + let menu = gio::Menu::new(); + let widget = gtk::PopoverMenu::from_model(Some(&menu)); + Self::ContextMenu { widget, menu, app } + } + + fn application(&self) -> >k::Application { + match self { + GtkMenuBar::MenuBar { app, .. } => app, + GtkMenuBar::ContextMenu { app, .. } => app, + } + } + + fn menu_bar(&self) -> >k::PopoverMenuBar { + match self { + GtkMenuBar::MenuBar { widget, .. } => widget, + _ => unreachable!("This is a bug report to https://github.com/tauri-apps/muda"), + } + } + + fn context_menu(&self) -> >k::PopoverMenu { + match self { + GtkMenuBar::ContextMenu { widget, .. } => widget, + _ => unreachable!("This is a bug report to https://github.com/tauri-apps/muda"), + } + } + + fn menu(&self) -> &gio::Menu { + match self { + GtkMenuBar::MenuBar { menu, .. } => menu, + GtkMenuBar::ContextMenu { menu, .. } => menu, + } + } + + /// Bind a widget to a `custom` slot in the generated menu. + /// + /// GTK4's `PopoverMenu` does not render icons set on a `gio::MenuItem`. + /// To show one we mark the model item with a `custom` attribute and + /// attach the real icon+label widget here; the binding reaches slots in + /// nested submenus too, so a single call per item is enough. + fn add_custom_child(&self, id: &str, widget: &impl IsA) { + match self { + GtkMenuBar::MenuBar { widget: w, .. } => { + w.add_child(widget, id); + } + GtkMenuBar::ContextMenu { widget: w, .. } => { + w.add_child(widget, id); + } + } + } +} + +/// Build the icon + label row shown in place of a default menu item. +/// +/// A flat `Button` carrying the model item's action, so activating it fires +/// the same `MenuEvent` a normal row would and `PopoverMenu` closes on click. +fn custom_menu_row(icon: &crate::icon::Icon, label: &str, action: &str) -> gtk::Button { + let row = gtk::Box::new(gtk::Orientation::Horizontal, 8); + let image = gtk::Image::from_gicon(&icon.inner.to_bytes_icon()); + image.set_pixel_size(16); + let label = gtk::Label::new(Some(&strip_mnemonic(label))); + label.set_xalign(0.0); + label.set_hexpand(true); + row.append(&image); + row.append(&label); + + let button = gtk::Button::builder() + .child(&row) + .has_frame(false) + .action_name(action) + .build(); + button.add_css_class("model"); + button +} + +fn strip_mnemonic(text: &str) -> String { + text.replace("__", "\u{0}") + .replace('_', "") + .replace('\u{0}', "_") +} + +pub struct Menu { + id: MenuId, + instances: HashMap, + ctx_menu_id: u32, + children: Vec>>, +} + +impl Menu { + pub fn new(id: Option) -> Self { + Self { + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + instances: HashMap::new(), + ctx_menu_id: COUNTER.next(), + children: Vec::new(), + } + } + + pub fn id(&self) -> &MenuId { + &self.id + } + + pub fn add_menu_item(&mut self, item: &dyn IsMenuItem, op: AddOp) -> crate::Result<()> { + match op { + AddOp::Append => self.children.push(item.child()), + AddOp::Insert(i) => self.children.insert(i, item.child()), + } + + for (menu_id, menu_bar) in &self.instances { + let parent_menu = menu_bar.menu(); + let gtk_item = + item.make_gtk_menu_item(menu_bar.application(), *menu_id, parent_menu)?; + match op { + AddOp::Append => parent_menu.append_item(>k_item), + AddOp::Insert(position) => parent_menu.insert_item(position as i32, >k_item), + } + } + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + crate::send_menu_update(); + + Ok(()) + } + + pub fn add_menu_item_with_id(&mut self, item: &dyn IsMenuItem, id: u32) -> crate::Result<()> { + for (menu_id, menu_bar) in self.instances.iter().filter(|m| *m.0 == id) { + let parent_menu = menu_bar.menu(); + let gtk_item = + item.make_gtk_menu_item(menu_bar.application(), *menu_id, parent_menu)?; + parent_menu.append_item(>k_item); + } + + Ok(()) + } + + /// Attach the icon+label widgets for every `custom` slot in the tree to + /// the given instance. Run after the instance's model is fully built. + fn bind_custom_children(&self, menu_bar: &GtkMenuBar) { + fn walk(children: &[Rc>], menu_bar: &GtkMenuBar) { + for child in children { + let child = child.borrow(); + if let Some((id, row)) = child.custom_child() { + menu_bar.add_custom_child(&id, &row); + } + walk(&child.children, menu_bar); + } + } + walk(&self.children, menu_bar); + } + + pub fn remove(&mut self, item: &dyn IsMenuItem) -> crate::Result<()> { + let child = item.child(); + let child_id = child.borrow().id().clone(); + + // Find position of item in children + let position = self + .children + .iter() + .position(|c| c.borrow().id() == &child_id); + + let Some(position) = position else { + return Err(crate::Error::NotAChildOfThisMenu); + }; + + // Remove from all GIO menus at the same position + for (menu_id, menu_bar) in &self.instances { + menu_bar.menu().remove(position as i32); + // Clean up the item's instances for this menu + item.child().borrow_mut().instances.remove(menu_id); + } + + // Remove from children + self.children.remove(position); + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + crate::send_menu_update(); + + Ok(()) + } + + pub fn items(&self) -> Vec { + self.children + .iter() + .map(|c| c.borrow().kind(c.clone())) + .collect() + } + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + pub fn compat_items(&self) -> Vec>> { + self.children + .iter() + .map(|child| child.borrow().compat_child()) + .collect() + } + + pub fn init_for_gtk_window( + &mut self, + window: &W, + container: Option<&C>, + ) -> crate::Result<()> + where + W: gtk::prelude::IsA, + W: gtk::prelude::IsA, + C: gtk::prelude::IsA, + { + let id = window.as_ptr() as u32; + + let Some(app) = window.application() else { + return Err(crate::Error::GtkWindowWithoutApplication); + }; + + // This is the first time this method has been called on this window + // so we need to create the menubar + if let Entry::Vacant(e) = self.instances.entry(id) { + e.insert(GtkMenuBar::new(app.clone())); + } else { + return Err(crate::Error::AlreadyInitialized); + } + + let action_group = action_group_from_app(&app); + window.insert_action_group(DEFAULT_ACTION_GROUP, Some(&action_group)); + + for item in self.items() { + self.add_menu_item_with_id(item.as_ref(), id)?; + } + + self.bind_custom_children(&self.instances[&id]); + + let menu_bar = self.instances[&id].menu_bar(); + + // add the menubar to the specified widget, otherwise to the window + if let Some(container) = container { + if container.type_().name() == "GtkBox" { + let gtk_box = container.dynamic_cast_ref::().unwrap(); + gtk_box.prepend(menu_bar); + } else if container.type_().name() == "GtkFixed" { + let gtk_box = container.dynamic_cast_ref::().unwrap(); + gtk_box.put(menu_bar, 0., 0.); + } else if container.type_().name() == "GtkStack" { + let gtk_box = container.dynamic_cast_ref::().unwrap(); + gtk_box.add_child(menu_bar); + } + } else { + window.set_child(Some(menu_bar)); + } + + // show the menu bar + menu_bar.set_visible(true); + + Ok(()) + } + + pub fn remove_for_gtk_window(&mut self, window: &W) -> crate::Result<()> + where + W: gtk::prelude::IsA, + W: gtk::prelude::IsA, + { + let id = window.as_ptr() as u32; + + let Some(menu_bar) = self.instances.remove(&id) else { + return Err(crate::Error::NotInitialized); + }; + + window.insert_action_group(DEFAULT_ACTION_GROUP, None::<&gio::SimpleActionGroup>); + + // Unparent the menu bar widget to remove it from the window + menu_bar.menu_bar().unparent(); + + // Clean up children instances for this menu + for child in &self.children { + child.borrow_mut().instances.remove(&id); + } + + Ok(()) + } + + pub fn hide_for_gtk_window(&self, window: &W) -> crate::Result<()> + where + W: gtk::prelude::IsA, + { + let id = window.as_ptr() as u32; + let Some(menu_bar) = self.instances.get(&id) else { + return Err(crate::Error::NotInitialized); + }; + menu_bar.menu_bar().set_visible(false); + Ok(()) + } + + pub fn show_for_gtk_window(&self, window: &W) -> crate::Result<()> + where + W: gtk::prelude::IsA, + { + let id = window.as_ptr() as u32; + let Some(menu_bar) = self.instances.get(&id) else { + return Err(crate::Error::NotInitialized); + }; + menu_bar.menu_bar().set_visible(true); + Ok(()) + } + + #[cfg(target_os = "linux")] + pub fn is_visible_on_gtk_window(&self, window: &W) -> bool + where + W: gtk::prelude::IsA, + { + let id = window.as_ptr() as u32; + self.instances + .get(&id) + .map(|m| m.menu_bar().is_visible()) + .unwrap_or(false) + } + + pub fn gtk_menubar_for_gtk_window(&self, window: &W) -> Option + where + W: gtk::prelude::IsA, + { + let id = window.as_ptr() as u32; + self.instances.get(&id).map(|m| m.menu_bar().clone()) + } + + pub fn gtk_context_menu(&mut self) -> gtk::PopoverMenu { + if !self.instances.contains_key(&self.ctx_menu_id) { + let app = gio::Application::default() + .and_downcast::() + .expect("`gtk_context_menu` requires a running `gtk::Application`"); + let menu = GtkMenuBar::new_context(app); + self.instances.insert(self.ctx_menu_id, menu); + for item in self.items() { + let _ = self.add_menu_item_with_id(item.as_ref(), self.ctx_menu_id); + } + self.bind_custom_children(&self.instances[&self.ctx_menu_id]); + } + self.instances + .get(&self.ctx_menu_id) + .unwrap() + .context_menu() + .clone() + } + + pub fn show_context_menu_for_gtk_window( + &mut self, + window: >k::Window, + position: Option, + ) -> bool { + let Some(app) = window.application() else { + return false; // TODO: better error + }; + + // Rebuild the context instance every time so it reflects the current + // labels, icons, and checked state rather than a stale first build. + self.instances.remove(&self.ctx_menu_id); + + { + let action_group = action_group_from_app(&app); + window.insert_action_group(DEFAULT_ACTION_GROUP, Some(&action_group)); + + let menu = GtkMenuBar::new_context(app); + + self.instances.insert(self.ctx_menu_id, menu); + + for item in self.items() { + let _ = self.add_menu_item_with_id(item.as_ref(), self.ctx_menu_id); + } + self.bind_custom_children(&self.instances[&self.ctx_menu_id]); + } + + let (x, y) = match position { + Some(p) => p.to_logical::(window.scale_factor() as _).into(), + None => get_cursor_pos(window), + }; + + // SAFETY: it is guaranteed to exist due to the check above + let menu = self.instances.get(&self.ctx_menu_id).unwrap(); + let context_menu = menu.context_menu(); + + if context_menu.parent().is_some() { + context_menu.unparent(); + } + context_menu.set_parent(window); + + context_menu.popup(); + context_menu.set_pointing_to(Some(&Rectangle::new(x, y, 0, 0))); + + true + } +} + +#[derive(Clone)] +enum GtkMenuChild { + Item { + item: gio::MenuItem, + app: gtk::Application, + parent_menu: gio::Menu, + }, + Submenu { + id: u32, + item: gio::MenuItem, + menu: gio::Menu, + app: gtk::Application, + parent_menu: gio::Menu, + }, + ContextMenu { + id: u32, + widget: gtk::PopoverMenu, + menu: gio::Menu, + app: gtk::Application, + }, +} + +impl GtkMenuChild { + fn id(&self) -> u32 { + match self { + GtkMenuChild::Submenu { id, .. } => *id, + GtkMenuChild::ContextMenu { id, .. } => *id, + _ => unreachable!("This is a bug report to https://github.com/tauri-apps/muda"), + } + } + + fn application(&self) -> >k::Application { + match self { + GtkMenuChild::Submenu { app, .. } => app, + GtkMenuChild::ContextMenu { app, .. } => app, + GtkMenuChild::Item { app, .. } => app, + } + } + + fn parent_menu(&self) -> &gio::Menu { + match self { + GtkMenuChild::Item { parent_menu, .. } => parent_menu, + GtkMenuChild::Submenu { parent_menu, .. } => parent_menu, + _ => unreachable!("This is a bug report to https://github.com/tauri-apps/muda"), + } + } + + fn menu(&self) -> &gio::Menu { + match self { + GtkMenuChild::Submenu { menu, .. } => menu, + GtkMenuChild::ContextMenu { menu, .. } => menu, + _ => unreachable!("This is a bug report to https://github.com/tauri-apps/muda"), + } + } + + fn context_menu(&self) -> >k::PopoverMenu { + match self { + GtkMenuChild::ContextMenu { widget, .. } => widget, + _ => unreachable!("This is a bug report to https://github.com/tauri-apps/muda"), + } + } +} + +pub struct MenuChild { + id: MenuId, + text: String, + enabled: bool, + key_accelerator: Option, + + checked: bool, + + icon: Option, + + predefined_item_type: Option, + + type_: MenuItemType, + + instances: HashMap>, + ctx_menu_id: u32, + children: Vec>>, + + action: Option, + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + compat: Arc>, +} + +#[cfg(all(feature = "linux-ksni", target_os = "linux"))] +impl MenuChild { + pub(crate) fn compat_child(&self) -> Arc> { + self.sync_compat(); + self.compat.clone() + } + + pub(crate) fn compat_items(&self) -> Vec>> { + self.children + .iter() + .map(|child| child.borrow().compat_child()) + .collect() + } + + fn sync_compat(&self) { + self.compat.store(Arc::new(self.to_compat_item())); + } + + fn to_compat_item(&self) -> crate::CompatMenuItem { + let label = crate::strip_mnemonic(&self.text); + match self.type_ { + MenuItemType::Check => crate::CompatCheckmarkItem { + id: self.id.0.clone(), + label, + enabled: self.enabled, + checked: self.is_checked(), + } + .into(), + MenuItemType::Submenu => crate::CompatSubMenuItem { + label, + enabled: self.enabled, + submenu: self.compat_items(), + } + .into(), + MenuItemType::Predefined => match self.predefined_item_type.as_ref() { + Some(PredefinedMenuItemType::Separator) => crate::CompatMenuItem::Separator, + Some(PredefinedMenuItemType::About(metadata)) => crate::CompatStandardItem { + id: self.id.0.clone(), + label, + enabled: self.enabled, + icon: None, + about_metadata: metadata.clone(), + } + .into(), + _ => crate::CompatStandardItem { + id: self.id.0.clone(), + label, + enabled: self.enabled, + icon: None, + about_metadata: None, + } + .into(), + }, + MenuItemType::Icon | MenuItemType::MenuItem => crate::CompatStandardItem { + id: self.id.0.clone(), + label, + enabled: self.enabled, + icon: self.icon.as_ref().map(|icon| icon.inner.png_data()), + about_metadata: None, + } + .into(), + } + } + + fn notify_compat_changed(&self) { + self.sync_compat(); + crate::send_menu_update(); + } +} + +impl MenuChild { + pub fn new_submenu(text: &str, enabled: bool, id: Option) -> Self { + Self { + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + text: text.to_string(), + enabled, + checked: false, + icon: None, + key_accelerator: None, + predefined_item_type: None, + type_: MenuItemType::Submenu, + ctx_menu_id: COUNTER.next(), + instances: HashMap::new(), + children: Vec::new(), + action: None, + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + compat: compat_placeholder(), + } + } + + fn create_gtk_item_for_submenu( + &mut self, + app: >k::Application, + menu_id: u32, + parent_menu: &gio::Menu, + ) -> crate::Result { + let menu = gio::Menu::new(); + let item = gio::MenuItem::new_submenu(Some(&to_gtk_mnemonic(&self.text)), &menu); + item.set_detailed_action(&self.detailed_action()); + + if self.action.is_none() { + let action_group = action_group_from_app(app); + + let action = gio::SimpleAction::new(self.id.as_ref(), None); + action.connect_activate(|_, _| ()); + action.set_enabled(self.enabled); + action_group.add_action(&action); + + self.action = Some(action); + } + + let id = COUNTER.next(); + let child = GtkMenuChild::Submenu { + item: item.clone(), + menu, + id, + app: app.clone(), + parent_menu: parent_menu.clone(), + }; + + self.instances.entry(menu_id).or_default().push(child); + + for item in self.items() { + self.add_menu_item_with_id(item.as_ref(), id)?; + } + + Ok(item) + } + + pub fn add_menu_item(&mut self, item: &dyn IsMenuItem, op: AddOp) -> crate::Result<()> { + match op { + AddOp::Append => self.children.push(item.child()), + AddOp::Insert(i) => self.children.insert(i, item.child()), + } + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + self.notify_compat_changed(); + + for menus in self.instances.values() { + for gtk_child in menus { + let parent_menu = gtk_child.menu(); + let gtk_item = + item.make_gtk_menu_item(gtk_child.application(), gtk_child.id(), parent_menu)?; + + match op { + AddOp::Append => parent_menu.append_item(>k_item), + AddOp::Insert(position) => parent_menu.insert_item(position as i32, >k_item), + } + } + } + + Ok(()) + } + + pub fn add_menu_item_with_id(&self, item: &dyn IsMenuItem, id: u32) -> crate::Result<()> { + for menus in self.instances.values() { + for gtk_child in menus.iter().filter(|m| m.id() == id) { + let parent_menu = gtk_child.menu(); + let gtk_item = + item.make_gtk_menu_item(gtk_child.application(), gtk_child.id(), parent_menu)?; + parent_menu.append_item(>k_item); + } + } + + Ok(()) + } + + pub fn remove(&mut self, item: &dyn IsMenuItem) -> crate::Result<()> { + let child = item.child(); + let child_id = child.borrow().id().clone(); + + // Find position of item in children + let position = self + .children + .iter() + .position(|c| c.borrow().id() == &child_id); + + let Some(position) = position else { + return Err(crate::Error::NotAChildOfThisMenu); + }; + + // Remove from all submenu GIO menus at the same position + for menus in self.instances.values() { + for gtk_child in menus { + // Get the submenu's gio::Menu and remove at position + gtk_child.menu().remove(position as i32); + } + } + + // Clean up the item's instances + // For submenus, we need to clear instances that belong to this submenu's children + let child_ref = item.child(); + let mut item_child = child_ref.borrow_mut(); + for menus in self.instances.values() { + for gtk_child in menus { + item_child.instances.remove(>k_child.id()); + } + } + + // Remove from children + self.children.remove(position); + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + self.notify_compat_changed(); + + Ok(()) + } + + pub fn items(&self) -> Vec { + self.children + .iter() + .map(|c| c.borrow().kind(c.clone())) + .collect() + } + + pub fn gtk_context_menu(&mut self) -> gtk::PopoverMenu { + if !self.instances.contains_key(&self.ctx_menu_id) { + let app = gio::Application::default() + .and_downcast::() + .expect("`gtk_context_menu` requires a running `gtk::Application`"); + let menu = gio::Menu::new(); + let widget = gtk::PopoverMenu::from_model(Some(&menu)); + let menu = GtkMenuChild::ContextMenu { + id: self.ctx_menu_id, + widget, + menu, + app, + }; + self.instances.insert(self.ctx_menu_id, vec![menu]); + for item in self.items() { + let _ = self.add_menu_item_with_id(item.as_ref(), self.ctx_menu_id); + } + } + self.instances + .get(&self.ctx_menu_id) + .unwrap() + .first() + .unwrap() + .context_menu() + .clone() + } + + pub fn show_context_menu_for_gtk_window( + &mut self, + window: >k::Window, + position: Option, + ) -> bool { + let Some(app) = window.application() else { + return false; // TODO: better error + }; + + if !self.instances.contains_key(&self.ctx_menu_id) { + let menu = gio::Menu::new(); + let widget = gtk::PopoverMenu::from_model(Some(&menu)); + + let action_group = action_group_from_app(&app); + window.insert_action_group(DEFAULT_ACTION_GROUP, Some(&action_group)); + + let menu = GtkMenuChild::ContextMenu { + id: self.ctx_menu_id, + widget, + menu, + app, + }; + + self.instances.insert(self.ctx_menu_id, vec![menu]); + + for item in self.items() { + let _ = self.add_menu_item_with_id(item.as_ref(), self.ctx_menu_id); + } + } + + // SAFETY: it is guaranteed to exist due to the check above + let menus = self.instances.get(&self.ctx_menu_id).unwrap(); + let menu = menus.first().unwrap(); + + let (x, y) = match position { + Some(p) => p.to_logical::(window.scale_factor() as _).into(), + None => get_cursor_pos(window), + }; + + let context_menu = menu.context_menu(); + + if context_menu.parent().is_some() { + context_menu.unparent(); + } + context_menu.set_parent(window); + + context_menu.popup(); + context_menu.set_pointing_to(Some(&Rectangle::new(x, y, 0, 0))); + + true + } +} + +impl MenuChild { + pub fn new( + text: &str, + enabled: bool, + key_accelerator: Option, + id: Option, + ) -> Self { + Self { + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + text: text.to_string(), + enabled, + key_accelerator, + icon: None, + checked: false, + predefined_item_type: None, + type_: MenuItemType::MenuItem, + ctx_menu_id: 0, + instances: HashMap::new(), + children: Vec::new(), + action: None, + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + compat: compat_placeholder(), + } + } + + fn create_gtk_item_for_menu_item( + &mut self, + app: >k::Application, + menu_id: u32, + parent_menu: &gio::Menu, + ) -> crate::Result { + let detailed_action = self.detailed_action(); + let item = gio::MenuItem::new(Some(&to_gtk_mnemonic(&self.text)), Some(&detailed_action)); + + if let Some(accelerator) = &self.key_accelerator { + app.set_accels_for_action(&detailed_action, &[&accelerator.to_gtk()]); + } + + if self.action.is_none() { + let action_group = action_group_from_app(app); + + let action = gio::SimpleAction::new(self.id.as_ref(), None); + let id = self.id.clone(); + action.connect_activate(move |_, _| MenuEvent::send(MenuEvent { id: id.clone() })); + action.set_enabled(self.enabled); + action_group.add_action(&action); + + self.action = Some(action); + } + + let child = GtkMenuChild::Item { + item: item.clone(), + app: app.clone(), + parent_menu: parent_menu.clone(), + }; + self.instances.entry(menu_id).or_default().push(child); + + Ok(item) + } + + pub fn id(&self) -> &MenuId { + &self.id + } + + fn detailed_action(&self) -> String { + format!("{DEFAULT_ACTION_GROUP}.{}", self.id.as_ref()) + } + + pub fn item_type(&self) -> &MenuItemType { + &self.type_ + } + + pub fn text(&self) -> String { + self.text.clone() + } + + pub fn set_text(&mut self, text: &str) { + self.text = text.to_string(); + + // GIO MenuItems are immutable after insertion, so we need to remove and reinsert + let detailed_action = self.detailed_action(); + + for children in self.instances.values_mut() { + for child in children.iter_mut() { + let parent_menu = child.parent_menu(); + + // Find position of this item in parent menu by matching action name + let mut position = None; + for i in 0..parent_menu.n_items() { + if let Some(action) = parent_menu.item_attribute_value(i, "action", None) { + if let Some(action_str) = action.str() { + if action_str == detailed_action { + position = Some(i); + break; + } + } + } + } + + if let Some(pos) = position { + // Remove old item + parent_menu.remove(pos); + + // Create new item with updated text + let new_item = gio::MenuItem::new( + Some(&to_gtk_mnemonic(&self.text)), + Some(&detailed_action), + ); + + // Copy icon if present + if let Some(icon) = &self.icon { + new_item.set_icon(&icon.inner.to_bytes_icon()); + } + + // Insert at same position + parent_menu.insert_item(pos, &new_item); + + // Update stored reference + match child { + GtkMenuChild::Item { item, .. } => *item = new_item, + GtkMenuChild::Submenu { item, .. } => *item = new_item, + _ => {} + } + } + } + } + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + self.notify_compat_changed(); + } + + pub fn is_enabled(&self) -> bool { + self.enabled + } + + pub fn set_enabled(&mut self, enabled: bool) { + self.enabled = enabled; + + if let Some(action) = self.action.as_ref() { + action.set_enabled(enabled); + } + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + self.notify_compat_changed(); + } + + pub fn set_key_accelerator( + &mut self, + accelerator: Option, + ) -> crate::Result<()> { + self.key_accelerator = accelerator.clone(); + + let detailed_action = self.detailed_action(); + let accelerator = accelerator.map(|a| a.to_gtk()); + let accelerator = accelerator.as_deref().map(|a| [a]).unwrap_or_default(); + for item in self.instances.values().flat_map(|v| v.iter()) { + let app = item.application(); + app.set_accels_for_action(&detailed_action, accelerator.as_slice()); + } + + Ok(()) + } +} + +impl MenuChild { + pub fn new_predefined(item_type: PredefinedMenuItemType, text: Option) -> Self { + Self { + id: MenuId(COUNTER.next().to_string()), + text: text.unwrap_or_else(|| item_type.text().to_string()), + enabled: true, + key_accelerator: item_type.accelerator().map(KeyAccelerator::from), + icon: None, + checked: false, + predefined_item_type: Some(item_type), + type_: MenuItemType::Predefined, + ctx_menu_id: 0, + instances: HashMap::new(), + children: Vec::new(), + action: None, + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + compat: compat_placeholder(), + } + } +} + +impl MenuChild { + pub fn new_check( + text: &str, + enabled: bool, + checked: bool, + key_accelerator: Option, + id: Option, + ) -> Self { + Self { + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + text: text.to_string(), + enabled, + key_accelerator, + icon: None, + checked, + predefined_item_type: None, + type_: MenuItemType::Check, + ctx_menu_id: 0, + instances: HashMap::new(), + children: Vec::new(), + action: None, + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + compat: compat_placeholder(), + } + } + + fn create_gtk_item_for_check_menu_item( + &mut self, + app: >k::Application, + menu_id: u32, + parent_menu: &gio::Menu, + ) -> crate::Result { + let detailed_action = self.detailed_action(); + let item = gio::MenuItem::new(Some(&to_gtk_mnemonic(&self.text)), Some(&detailed_action)); + + if let Some(accelerator) = &self.key_accelerator { + app.set_accels_for_action(&detailed_action, &[&accelerator.to_gtk()]); + } + + if self.action.is_none() { + let action_group = action_group_from_app(app); + + let state = &self.checked.to_variant(); + let action = gio::SimpleAction::new_stateful(self.id.as_ref(), None, state); + let id = self.id.clone(); + action.connect_state_notify(move |_| MenuEvent::send(MenuEvent { id: id.clone() })); + action.set_enabled(self.enabled); + action_group.add_action(&action); + + self.action = Some(action); + } + + let child = GtkMenuChild::Item { + item: item.clone(), + app: app.clone(), + parent_menu: parent_menu.clone(), + }; + self.instances.entry(menu_id).or_default().push(child); + + Ok(item) + } + + pub fn is_checked(&self) -> bool { + self.action + .as_ref() + .and_then(|action| action.state()) + .and_then(|s| s.get()) + .unwrap_or(self.checked) + } + + pub fn set_checked(&mut self, checked: bool) { + self.checked = checked; + + if let Some(action) = self.action.as_ref() { + action.set_state(&checked.to_variant()); + } + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + self.notify_compat_changed(); + } +} + +impl MenuChild { + pub fn new_icon( + text: &str, + enabled: bool, + icon: Option, + key_accelerator: Option, + id: Option, + ) -> Self { + Self { + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + text: text.to_string(), + enabled, + key_accelerator, + icon, + checked: false, + predefined_item_type: None, + type_: MenuItemType::Icon, + ctx_menu_id: 0, + instances: HashMap::new(), + children: Vec::new(), + action: None, + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + compat: compat_placeholder(), + } + } + + pub fn new_native_icon( + text: &str, + enabled: bool, + _icon: Option, + key_accelerator: Option, + id: Option, + ) -> Self { + Self { + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + text: text.to_string(), + enabled, + key_accelerator, + icon: None, + checked: false, + predefined_item_type: None, + type_: MenuItemType::Icon, + ctx_menu_id: 0, + instances: HashMap::new(), + children: Vec::new(), + action: None, + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + compat: compat_placeholder(), + } + } + + fn create_gtk_item_for_icon_menu_item( + &mut self, + app: >k::Application, + menu_id: u32, + parent_menu: &gio::Menu, + ) -> crate::Result { + let detailed_action = self.detailed_action(); + let item = gio::MenuItem::new(Some(&to_gtk_mnemonic(&self.text)), Some(&detailed_action)); + + if let Some(accelerator) = &self.key_accelerator { + app.set_accels_for_action(&detailed_action, &[&accelerator.to_gtk()]); + } + + // GTK4's PopoverMenu ignores icons set on the model item, so mark + // this row as custom and render the icon ourselves via `add_child`. + if self.icon.is_some() { + item.set_attribute_value("custom", Some(&self.id.as_ref().to_variant())); + } + + if self.action.is_none() { + let action_group = action_group_from_app(app); + + let action = gio::SimpleAction::new(self.id.as_ref(), None); + let id = self.id.clone(); + action.connect_activate(move |_, _| MenuEvent::send(MenuEvent { id: id.clone() })); + action.set_enabled(self.enabled); + action_group.add_action(&action); + + self.action = Some(action); + } + + let child = GtkMenuChild::Item { + item: item.clone(), + app: app.clone(), + parent_menu: parent_menu.clone(), + }; + self.instances.entry(menu_id).or_default().push(child); + + Ok(item) + } + + /// The `custom` slot id and rendered row for an icon item, if any. + fn custom_child(&self) -> Option<(String, gtk::Button)> { + let icon = self.icon.as_ref()?; + Some(( + self.id.as_ref().to_string(), + custom_menu_row(icon, &self.text, &self.detailed_action()), + )) + } + + fn create_gtk_item_for_predefined_menu_item( + &mut self, + app: >k::Application, + menu_id: u32, + parent_menu: &gio::Menu, + ) -> crate::Result { + let predefined_item_type = self.predefined_item_type.clone().unwrap(); + + let (label, action_name) = match &predefined_item_type { + // Separator - create an empty section label (GIO way of doing separators) + PredefinedMenuItemType::Separator => { + // For separators, we return an item with no action that acts as a visual break + // In GIO menus, true separators are done via sections, but this provides a fallback + let item = gio::MenuItem::new(None, None); + let child = GtkMenuChild::Item { + item: item.clone(), + app: app.clone(), + parent_menu: parent_menu.clone(), + }; + self.instances.entry(menu_id).or_default().push(child); + return Ok(item); + } + + // Clipboard actions (widget-scoped, work on focused text widgets) + PredefinedMenuItemType::Copy => (self.text.clone(), "clipboard.copy"), + PredefinedMenuItemType::Cut => (self.text.clone(), "clipboard.cut"), + PredefinedMenuItemType::Paste => (self.text.clone(), "clipboard.paste"), + PredefinedMenuItemType::SelectAll => (self.text.clone(), "selection.select-all"), + + // Text actions (widget-scoped, work on focused text widgets) + PredefinedMenuItemType::Undo => (self.text.clone(), "text.undo"), + PredefinedMenuItemType::Redo => (self.text.clone(), "text.redo"), + + // Window actions (built-in on GtkWindow) + PredefinedMenuItemType::Minimize => (self.text.clone(), "window.minimize"), + PredefinedMenuItemType::Maximize => (self.text.clone(), "window.toggle-maximized"), + PredefinedMenuItemType::CloseWindow => (self.text.clone(), "window.close"), + + // Fullscreen - no built-in GAction, need custom action + PredefinedMenuItemType::Fullscreen => { + let action_name = format!("{DEFAULT_ACTION_GROUP}.{}_fullscreen", self.id.as_ref()); + + if self.action.is_none() { + let action_group = action_group_from_app(app); + let action = + gio::SimpleAction::new(&format!("{}_fullscreen", self.id.as_ref()), None); + action.connect_activate(|_, _| { + // Get the focused window and toggle fullscreen + if let Some(app) = gio::Application::default() { + if let Some(app) = app.downcast_ref::() { + if let Some(window) = app.active_window() { + if window.is_fullscreen() { + window.unfullscreen(); + } else { + window.fullscreen(); + } + } + } + } + }); + action_group.add_action(&action); + self.action = Some(action); + } + + let item = + gio::MenuItem::new(Some(&to_gtk_mnemonic(&self.text)), Some(&action_name)); + let child = GtkMenuChild::Item { + item: item.clone(), + app: app.clone(), + parent_menu: parent_menu.clone(), + }; + self.instances.entry(menu_id).or_default().push(child); + return Ok(item); + } + + // About - custom action showing AboutDialog + PredefinedMenuItemType::About(metadata) => { + let action_name = format!("{DEFAULT_ACTION_GROUP}.{}_about", self.id.as_ref()); + + if self.action.is_none() { + let action_group = action_group_from_app(app); + let metadata = metadata.clone(); + let action = + gio::SimpleAction::new(&format!("{}_about", self.id.as_ref()), None); + action.connect_activate(move |_, _| { + if let Some(metadata) = &metadata { + let dialog = gtk::AboutDialog::new(); + dialog.set_modal(true); + + if let Some(name) = &metadata.name { + dialog.set_program_name(Some(name.as_str())); + } + if let Some(version) = &metadata.full_version() { + dialog.set_version(Some(version.as_str())); + } + if let Some(authors) = &metadata.authors { + let authors_refs: Vec<&str> = + authors.iter().map(|s| s.as_str()).collect(); + dialog.set_authors(&authors_refs); + } + if let Some(comments) = &metadata.comments { + dialog.set_comments(Some(comments)); + } + if let Some(copyright) = &metadata.copyright { + dialog.set_copyright(Some(copyright)); + } + if let Some(license) = &metadata.license { + dialog.set_license(Some(license)); + } + if let Some(website) = &metadata.website { + dialog.set_website(Some(website)); + } + if let Some(website_label) = &metadata.website_label { + dialog.set_website_label(website_label); + } + + // Set transient parent if possible + if let Some(app) = gio::Application::default() { + if let Some(app) = app.downcast_ref::() { + if let Some(window) = app.active_window() { + dialog.set_transient_for(Some(&window)); + } + } + } + + dialog.present(); + } + }); + action_group.add_action(&action); + self.action = Some(action); + } + + let item = + gio::MenuItem::new(Some(&to_gtk_mnemonic(&self.text)), Some(&action_name)); + let child = GtkMenuChild::Item { + item: item.clone(), + app: app.clone(), + parent_menu: parent_menu.clone(), + }; + self.instances.entry(menu_id).or_default().push(child); + return Ok(item); + } + + // Unsupported on Linux (matches GTK3 behavior) + PredefinedMenuItemType::Quit + | PredefinedMenuItemType::Hide + | PredefinedMenuItemType::HideOthers + | PredefinedMenuItemType::ShowAll + | PredefinedMenuItemType::Services + | PredefinedMenuItemType::BringAllToFront + | PredefinedMenuItemType::None => { + unreachable!("Predefined menu item type not supported on Linux") + } + }; + + // Create menu item pointing to the action + let item = gio::MenuItem::new(Some(&to_gtk_mnemonic(&label)), Some(action_name)); + + let child = GtkMenuChild::Item { + item: item.clone(), + app: app.clone(), + parent_menu: parent_menu.clone(), + }; + self.instances.entry(menu_id).or_default().push(child); + + Ok(item) + } + + pub fn set_icon(&mut self, icon: Option) { + self.icon = icon; + + // GIO MenuItems are immutable after insertion, so we need to remove and reinsert + let detailed_action = self.detailed_action(); + + for children in self.instances.values_mut() { + for child in children.iter_mut() { + let parent_menu = child.parent_menu(); + + // Find position of this item in parent menu by matching action name + let mut position = None; + for i in 0..parent_menu.n_items() { + if let Some(action) = parent_menu.item_attribute_value(i, "action", None) { + if let Some(action_str) = action.str() { + if action_str == detailed_action { + position = Some(i); + break; + } + } + } + } + + if let Some(pos) = position { + // Remove old item + parent_menu.remove(pos); + + // Create new item with updated icon + let new_item = gio::MenuItem::new( + Some(&to_gtk_mnemonic(&self.text)), + Some(&detailed_action), + ); + + // Set icon if present + if let Some(icon) = &self.icon { + new_item.set_icon(&icon.inner.to_bytes_icon()); + } + + // Insert at same position + parent_menu.insert_item(pos, &new_item); + + // Update stored reference + match child { + GtkMenuChild::Item { item, .. } => *item = new_item, + GtkMenuChild::Submenu { item, .. } => *item = new_item, + _ => {} + } + } + } + } + + #[cfg(all(feature = "linux-ksni", target_os = "linux"))] + self.notify_compat_changed(); + } +} + +impl dyn IsMenuItem + '_ { + fn make_gtk_menu_item( + &self, + app: >k::Application, + menu_id: u32, + parent_menu: &gio::Menu, + ) -> crate::Result { + let kind = self.kind(); + let mut child = kind.child_mut(); + match child.item_type() { + MenuItemType::Submenu => child.create_gtk_item_for_submenu(app, menu_id, parent_menu), + MenuItemType::MenuItem => { + child.create_gtk_item_for_menu_item(app, menu_id, parent_menu) + } + MenuItemType::Check => { + child.create_gtk_item_for_check_menu_item(app, menu_id, parent_menu) + } + MenuItemType::Icon => { + child.create_gtk_item_for_icon_menu_item(app, menu_id, parent_menu) + } + MenuItemType::Predefined => { + child.create_gtk_item_for_predefined_menu_item(app, menu_id, parent_menu) + } + } + } +} + +/// Returns and creates the action group on this application if necessary. +fn action_group_from_app(app: >k::Application) -> gio::SimpleActionGroup { + let action_group = unsafe { app.data::(ACTION_GROUP_DATA_KEY) }; + + let action_group = if let Some(action_group) = action_group { + unsafe { action_group.as_ref() }.clone() + } else { + let action_group = gio::SimpleActionGroup::new(); + unsafe { app.set_data(ACTION_GROUP_DATA_KEY, action_group.clone()) }; + action_group + }; + + action_group +} + +fn get_cursor_pos(window: >k::Window) -> (i32, i32) { + WidgetExt::display(window) + .default_seat() + .and_then(|s| s.pointer()) + .map(|p| { + let (_, x, y) = p.surface_at_position(); + (x as _, y as _) + }) + .unwrap_or_default() +} diff --git a/ports/muda/src/platform_impl/macos/accelerator.rs b/ports/muda/src/platform_impl/macos/accelerator.rs new file mode 100644 index 000000000000..bf96f6633d80 --- /dev/null +++ b/ports/muda/src/platform_impl/macos/accelerator.rs @@ -0,0 +1,76 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use keyboard_types::{Key, Modifiers}; +use objc2_app_kit::NSEventModifierFlags; + +use crate::accelerator::{AcceleratorParseError, KeyAccelerator}; + +impl KeyAccelerator { + /// Return the string value of this hotkey, without modifiers. + pub(crate) fn key_equivalent(&self) -> Result { + Ok(match &self.key { + Key::Character(s) => s.clone(), + Key::Tab => "⇥".into(), + Key::Escape => "\u{001b}".into(), + Key::Enter => "\u{000d}".into(), + Key::Backspace => "\u{0008}".into(), + Key::Delete => "\u{007f}".into(), + Key::Insert => "\u{F727}".into(), + Key::Home => "\u{F729}".into(), + Key::End => "\u{F72B}".into(), + Key::PageUp => "\u{F72C}".into(), + Key::PageDown => "\u{F72D}".into(), + Key::PrintScreen => "\u{F72E}".into(), + Key::ScrollLock => "\u{F72F}".into(), + Key::ArrowUp => "\u{F700}".into(), + Key::ArrowDown => "\u{F701}".into(), + Key::ArrowLeft => "\u{F702}".into(), + Key::ArrowRight => "\u{F703}".into(), + Key::F1 => "\u{F704}".into(), + Key::F2 => "\u{F705}".into(), + Key::F3 => "\u{F706}".into(), + Key::F4 => "\u{F707}".into(), + Key::F5 => "\u{F708}".into(), + Key::F6 => "\u{F709}".into(), + Key::F7 => "\u{F70A}".into(), + Key::F8 => "\u{F70B}".into(), + Key::F9 => "\u{F70C}".into(), + Key::F10 => "\u{F70D}".into(), + Key::F11 => "\u{F70E}".into(), + Key::F12 => "\u{F70F}".into(), + Key::F13 => "\u{F710}".into(), + Key::F14 => "\u{F711}".into(), + Key::F15 => "\u{F712}".into(), + Key::F16 => "\u{F713}".into(), + Key::F17 => "\u{F714}".into(), + Key::F18 => "\u{F715}".into(), + Key::F19 => "\u{F716}".into(), + Key::F20 => "\u{F717}".into(), + Key::F21 => "\u{F718}".into(), + Key::F22 => "\u{F719}".into(), + Key::F23 => "\u{F71A}".into(), + Key::F24 => "\u{F71B}".into(), + key => return Err(AcceleratorParseError::UnsupportedKey(format!("{:?}", key))), + }) + } + + /// Return the modifiers of this hotkey, as an NSEventModifierFlags bitflag. + pub(crate) fn modifier_mask(&self) -> NSEventModifierFlags { + let mut flags = NSEventModifierFlags::empty(); + if self.mods.contains(Modifiers::SHIFT) { + flags.insert(NSEventModifierFlags::Shift); + } + if self.mods.contains(Modifiers::SUPER) { + flags.insert(NSEventModifierFlags::Command); + } + if self.mods.contains(Modifiers::ALT) { + flags.insert(NSEventModifierFlags::Option); + } + if self.mods.contains(Modifiers::CONTROL) { + flags.insert(NSEventModifierFlags::Control); + } + flags + } +} diff --git a/ports/muda/src/platform_impl/macos/icon.rs b/ports/muda/src/platform_impl/macos/icon.rs new file mode 100644 index 000000000000..94b1a8e4fdfb --- /dev/null +++ b/ports/muda/src/platform_impl/macos/icon.rs @@ -0,0 +1,64 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use objc2::{rc::Retained, AllocAnyThread}; +use objc2_app_kit::NSImage; +use objc2_core_foundation::CGFloat; +use objc2_foundation::{NSData, NSSize}; + +use crate::icon::{BadIcon, RgbaIcon}; +use std::io::Cursor; + +#[derive(Debug, Clone)] +pub struct PlatformIcon(RgbaIcon); + +impl PlatformIcon { + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + Ok(PlatformIcon(RgbaIcon::from_rgba(rgba, width, height)?)) + } + + pub fn get_size(&self) -> (u32, u32) { + (self.0.width, self.0.height) + } + + pub fn to_png(&self) -> Vec { + let mut png = Vec::new(); + + { + let mut encoder = + png::Encoder::new(Cursor::new(&mut png), self.0.width as _, self.0.height as _); + encoder.set_color(png::ColorType::Rgba); + encoder.set_depth(png::BitDepth::Eight); + + let mut writer = encoder.write_header().unwrap(); + writer.write_image_data(&self.0.rgba).unwrap(); + } + + png + } + + pub fn to_nsimage(&self, fixed_height: Option) -> Retained { + let (width, height) = self.get_size(); + let icon = self.to_png(); + + let (icon_width, icon_height) = match fixed_height { + Some(fixed_height) => { + let icon_height: CGFloat = fixed_height as CGFloat; + let icon_width: CGFloat = (width as CGFloat) / (height as CGFloat / icon_height); + + (icon_width, icon_height) + } + + None => (width as CGFloat, height as CGFloat), + }; + + let nsdata = NSData::with_bytes(&icon); + + let nsimage = NSImage::initWithData(NSImage::alloc(), &nsdata).unwrap(); + let new_size = NSSize::new(icon_width, icon_height); + unsafe { nsimage.setSize(new_size) }; + + nsimage + } +} diff --git a/ports/muda/src/platform_impl/macos/mod.rs b/ports/muda/src/platform_impl/macos/mod.rs new file mode 100644 index 000000000000..56e370cf5a4d --- /dev/null +++ b/ports/muda/src/platform_impl/macos/mod.rs @@ -0,0 +1,1283 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +mod accelerator; +mod icon; +mod util; + +pub(crate) use icon::PlatformIcon; + +use std::{ + cell::{Cell, RefCell}, + collections::HashMap, + ffi::c_void, + ptr, + rc::Rc, +}; + +use objc2::{ + define_class, msg_send, + rc::Retained, + runtime::{AnyObject, NSObjectProtocol, ProtocolObject, Sel}, + sel, DeclaredClass, MainThreadOnly, Message, +}; +use objc2_app_kit::{ + NSAboutPanelOptionApplicationIcon, NSAboutPanelOptionApplicationName, + NSAboutPanelOptionApplicationVersion, NSAboutPanelOptionCredits, NSAboutPanelOptionVersion, + NSApplication, NSControlStateValueOff, NSControlStateValueOn, NSEvent, NSEventModifierFlags, + NSImage, NSImageName, NSMenu, NSMenuDelegate, NSMenuItem, NSRunningApplication, NSView, +}; +use objc2_foundation::{ + ns_string, MainThreadMarker, NSAttributedString, NSDictionary, NSInteger, NSObject, NSPoint, + NSSize, NSString, +}; + +use self::util::strip_mnemonic; +use crate::{ + accelerator::KeyAccelerator, + dpi::{LogicalPosition, Position}, + icon::{Icon, NativeIcon}, + items::*, + util::{AddOp, Counter}, + IsMenuItem, MenuEvent, MenuId, MenuItemKind, MenuItemType, +}; + +static COUNTER: Counter = Counter::new(); + +/// https://developer.apple.com/documentation/appkit/nsapplication/1428479-orderfrontstandardaboutpanelwith#discussion +#[allow(non_upper_case_globals)] +const NSAboutPanelOptionCopyright: &str = "Copyright"; + +define_class!( + /// A delegate for NSMenu that stores the menu id as an instance variable, + /// so that we can identify it later. Like when calling `set_as_windows_menu_for_nsapp`. + #[unsafe(super(NSObject))] + #[name = "MudaMenuDelegate"] + #[thread_kind = MainThreadOnly] + #[ivars = u32] + struct MudaMenuDelegate; + + unsafe impl NSObjectProtocol for MudaMenuDelegate {} + unsafe impl NSMenuDelegate for MudaMenuDelegate {} +); + +impl MudaMenuDelegate { + fn new(mtm: MainThreadMarker, menu_id: u32) -> Retained { + let this = mtm.alloc().set_ivars(menu_id); + unsafe { msg_send![super(this), init] } + } + + fn menu_id(&self) -> u32 { + *self.ivars() + } +} + +#[derive(Clone)] +struct NsMenuRef( + u32, + Retained, + /// Prevent deallocation — NSMenu's delegate is a weak reference. + #[allow(dead_code)] + Retained, +); + +impl NsMenuRef { + fn new(mtm: MainThreadMarker, id: u32, ns_menu: Retained) -> Self { + let delegate = MudaMenuDelegate::new(mtm, id); + unsafe { + ns_menu.setDelegate(Some(ProtocolObject::from_ref(&*delegate))); + } + Self(id, ns_menu, delegate) + } +} + +impl std::fmt::Debug for NsMenuRef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("NsMenuRef") + .field(&self.0) + .field(&self.1) + .finish() + } +} + +impl Drop for NsMenuRef { + fn drop(&mut self) { + unsafe { self.1.cancelTrackingWithoutAnimation() }; + } +} + +#[derive(Debug)] +pub struct Menu { + id: MenuId, + ns_menu: NsMenuRef, + children: Vec>>, +} + +impl Drop for Menu { + fn drop(&mut self) { + for child in &self.children { + let mut child_ = child.borrow_mut(); + child_.ns_menu_items.remove(&self.ns_menu.0); + if child_.item_type == MenuItemType::Submenu { + child_.ns_menus.as_mut().unwrap().remove(&self.ns_menu.0); + } + } + } +} + +impl Menu { + pub fn new(id: Option) -> Self { + let mtm = + MainThreadMarker::new().expect("`muda::Menu` can only be created on the main thread"); + let ns_menu = NSMenu::new(mtm); + unsafe { ns_menu.setAutoenablesItems(false) }; + Self { + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + ns_menu: NsMenuRef::new(mtm, COUNTER.next(), ns_menu), + children: Vec::new(), + } + } + + pub fn id(&self) -> &MenuId { + &self.id + } + + pub fn add_menu_item(&mut self, item: &dyn crate::IsMenuItem, op: AddOp) -> crate::Result<()> { + let ns_menu_item = item.make_ns_item_for_menu(self.ns_menu.0)?; + let child = item.child(); + + unsafe { + match op { + AddOp::Append => { + self.ns_menu.1.addItem(&ns_menu_item); + self.children.push(child); + } + AddOp::Insert(position) => { + self.ns_menu + .1 + .insertItem_atIndex(&ns_menu_item, position as NSInteger); + self.children.insert(position, child); + } + } + } + + Ok(()) + } + + pub fn remove(&mut self, item: &dyn crate::IsMenuItem) -> crate::Result<()> { + // get child + let child = { + let index = self + .children + .iter() + .position(|e| e.borrow().id == item.id()) + .ok_or(crate::Error::NotAChildOfThisMenu)?; + self.children.remove(index) + }; + + let mut child_ = child.borrow_mut(); + + if child_.item_type == MenuItemType::Submenu { + let menu_id = &self.ns_menu.0; + let menus = child_.ns_menus.as_ref().unwrap().get(menu_id).cloned(); + if let Some(menus) = menus { + for menu in menus { + for item in child_.items() { + child_.remove_inner(item.as_ref(), false, Some(menu.0))?; + } + } + } + child_.ns_menus.as_mut().unwrap().remove(menu_id); + } + + // remove each NSMenuItem from the NSMenu + if let Some(ns_menu_items) = child_.ns_menu_items.remove(&self.ns_menu.0) { + for item in ns_menu_items { + unsafe { self.ns_menu.1.removeItem(&item) }; + } + } + + Ok(()) + } + + pub fn items(&self) -> Vec { + self.children + .iter() + .map(|c| c.borrow().kind(c.clone())) + .collect() + } + + pub fn init_for_nsapp(&self) { + let mtm = MainThreadMarker::from(&*self.ns_menu.1); + let app = NSApplication::sharedApplication(mtm); + app.setMainMenu(Some(&self.ns_menu.1)); + } + + pub fn remove_for_nsapp(&self) { + let mtm = MainThreadMarker::from(&*self.ns_menu.1); + let app = NSApplication::sharedApplication(mtm); + app.setMainMenu(None); + } + + pub unsafe fn show_context_menu_for_nsview( + &self, + view: *const c_void, + position: Option, + ) -> bool { + // SAFETY: Upheld by caller + show_context_menu(&self.ns_menu.1, view, position) + } + + pub fn ns_menu(&self) -> *mut std::ffi::c_void { + Retained::as_ptr(&self.ns_menu.1) as _ + } +} + +/// A generic child in a menu +#[derive(Debug, Default)] +pub struct MenuChild { + // shared fields between submenus and menu items + item_type: MenuItemType, + id: MenuId, + text: String, + enabled: bool, + + ns_menu_items: HashMap>>, + + // menu item fields + key_accelerator: Option, + + // predefined menu item fields + predefined_item_type: Option, + + // check menu item fields + checked: Cell, + + // icon menu item fields + icon: Option, + native_icon: Option, + + // submenu fields + pub children: Option>>>, + ns_menus: Option>>, + ns_menu: Option, +} + +impl Drop for MenuChild { + fn drop(&mut self) { + fn drop_children(id: u32, children: &Vec>>) { + for child in children { + let mut child_ = child.borrow_mut(); + child_.ns_menu_items.remove(&id); + + if child_.item_type == MenuItemType::Submenu { + if let Some(menus) = child_.ns_menus.as_mut().unwrap().remove(&id) { + for menu in menus { + drop_children(menu.0, child_.children.as_ref().unwrap()); + } + } + } + } + } + + if self.item_type == MenuItemType::Submenu { + for menus in self.ns_menus.as_ref().unwrap().values() { + for menu in menus { + drop_children(menu.0, self.children.as_ref().unwrap()) + } + } + + if let Some(menu) = &self.ns_menu { + drop_children(menu.0, self.children.as_ref().unwrap()); + } + } + } +} + +/// Constructors +impl MenuChild { + pub fn new( + text: &str, + enabled: bool, + key_accelerator: Option, + id: Option, + ) -> Self { + Self { + item_type: MenuItemType::MenuItem, + text: strip_mnemonic(text), + enabled, + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + key_accelerator, + checked: Cell::new(false), + children: None, + icon: None, + native_icon: None, + ns_menu: None, + ns_menu_items: HashMap::new(), + ns_menus: None, + predefined_item_type: None, + } + } + + pub fn new_submenu(text: &str, enabled: bool, id: Option) -> Self { + let mtm = if cfg!(test) { + unsafe { MainThreadMarker::new_unchecked() } + } else { + MainThreadMarker::new() + .expect("`muda::MenuChild` can only be created on the main thread") + }; + Self { + item_type: MenuItemType::Submenu, + text: strip_mnemonic(text), + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + enabled, + children: Some(Vec::new()), + ns_menu: Some({ + let menu = NSMenu::new(mtm); + unsafe { menu.setAutoenablesItems(false) }; + NsMenuRef::new(mtm, COUNTER.next(), menu) + }), + key_accelerator: None, + checked: Cell::new(false), + icon: None, + native_icon: None, + ns_menu_items: HashMap::new(), + ns_menus: Some(HashMap::new()), + predefined_item_type: None, + } + } + + pub(crate) fn new_predefined(item_type: PredefinedMenuItemType, text: Option) -> Self { + let text = strip_mnemonic(text.unwrap_or_else(|| { + // Gets the app's name from `NSRunningApplication::localizedName`. + let app_name = || unsafe { + let app = NSRunningApplication::currentApplication(); + app.localizedName().unwrap_or_default() + }; + + match item_type { + PredefinedMenuItemType::About(_) => { + format!("About {}", app_name()).trim().to_string() + } + PredefinedMenuItemType::Hide => format!("Hide {}", app_name()).trim().to_string(), + PredefinedMenuItemType::Quit => format!("Quit {}", app_name()).trim().to_string(), + _ => item_type.text().to_string(), + } + })); + + Self { + item_type: MenuItemType::Predefined, + text, + enabled: true, + id: MenuId(COUNTER.next().to_string()), + key_accelerator: item_type.accelerator().map(KeyAccelerator::from), + predefined_item_type: Some(item_type), + checked: Cell::new(false), + children: None, + icon: None, + native_icon: None, + ns_menu: None, + ns_menu_items: HashMap::new(), + ns_menus: None, + } + } + + pub fn new_check( + text: &str, + enabled: bool, + checked: bool, + key_accelerator: Option, + id: Option, + ) -> Self { + Self { + item_type: MenuItemType::Check, + text: text.to_string(), + enabled, + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + key_accelerator, + checked: Cell::new(checked), + children: None, + icon: None, + native_icon: None, + ns_menu: None, + ns_menu_items: HashMap::new(), + ns_menus: None, + predefined_item_type: None, + } + } + + pub fn new_icon( + text: &str, + enabled: bool, + icon: Option, + key_accelerator: Option, + id: Option, + ) -> Self { + Self { + item_type: MenuItemType::Icon, + text: text.to_string(), + enabled, + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + icon, + key_accelerator, + checked: Cell::new(false), + children: None, + native_icon: None, + ns_menu: None, + ns_menu_items: HashMap::new(), + ns_menus: None, + predefined_item_type: None, + } + } + + pub fn new_native_icon( + text: &str, + enabled: bool, + native_icon: Option, + key_accelerator: Option, + id: Option, + ) -> Self { + Self { + item_type: MenuItemType::Icon, + text: text.to_string(), + enabled, + id: id.unwrap_or_else(|| MenuId(COUNTER.next().to_string())), + native_icon, + key_accelerator, + checked: Cell::new(false), + children: None, + icon: None, + ns_menu: None, + ns_menu_items: HashMap::new(), + ns_menus: None, + predefined_item_type: None, + } + } +} + +/// Shared methods +impl MenuChild { + pub(crate) fn item_type(&self) -> MenuItemType { + self.item_type + } + + pub fn id(&self) -> &MenuId { + &self.id + } + + pub fn text(&self) -> String { + self.text.clone() + } + + pub fn set_text(&mut self, text: &str) { + self.text = strip_mnemonic(text); + unsafe { + let title = NSString::from_str(&self.text); + for ns_items in self.ns_menu_items.values() { + for ns_item in ns_items { + ns_item.setTitle(&title); + if let Some(submenu) = ns_item.submenu() { + submenu.setTitle(&title); + } + } + } + } + } + + pub fn is_enabled(&self) -> bool { + self.enabled + } + + pub fn set_enabled(&mut self, enabled: bool) { + self.enabled = enabled; + for ns_items in self.ns_menu_items.values() { + for ns_item in ns_items { + unsafe { ns_item.setEnabled(enabled) }; + } + } + } + + pub fn set_key_accelerator( + &mut self, + key_accelerator: Option, + ) -> crate::Result<()> { + let key_equivalent = key_accelerator + .as_ref() + .map(KeyAccelerator::key_equivalent) + .transpose()?; + + if let Some(key_equivalent) = key_equivalent { + let key_equivalent = NSString::from_str(key_equivalent.as_str()); + + let modifier_mask = key_accelerator + .as_ref() + .map(KeyAccelerator::modifier_mask) + .unwrap_or_else(NSEventModifierFlags::empty); + + for ns_items in self.ns_menu_items.values() { + for ns_item in ns_items { + unsafe { + ns_item.setKeyEquivalent(&key_equivalent); + ns_item.setKeyEquivalentModifierMask(modifier_mask); + } + } + } + } + + self.key_accelerator = key_accelerator; + + Ok(()) + } +} + +/// CheckMenuItem methods +impl MenuChild { + pub fn is_checked(&self) -> bool { + self.checked.get() + } + + pub fn set_checked(&self, checked: bool) { + self.checked.set(checked); + let state = if checked { + NSControlStateValueOn + } else { + NSControlStateValueOff + }; + for ns_items in self.ns_menu_items.values() { + for ns_item in ns_items { + unsafe { + ns_item.setState(state); + } + } + } + } +} + +/// IconMenuItem methods +impl MenuChild { + pub fn set_icon(&mut self, icon: Option) { + self.icon.clone_from(&icon); + self.native_icon = None; + for ns_items in self.ns_menu_items.values() { + for ns_item in ns_items { + menuitem_set_icon(ns_item, icon.as_ref()); + } + } + } + + pub fn set_native_icon(&mut self, icon: Option) { + self.native_icon = icon; + self.icon = None; + for ns_items in self.ns_menu_items.values() { + for ns_item in ns_items { + menuitem_set_native_icon(ns_item, icon); + } + } + } +} + +/// Submenu methods +impl MenuChild { + pub fn add_menu_item(&mut self, item: &dyn crate::IsMenuItem, op: AddOp) -> crate::Result<()> { + let child = item.child(); + + unsafe { + match op { + AddOp::Append => { + for menus in self.ns_menus.as_ref().unwrap().values() { + for ns_menu in menus { + let ns_menu_item = item.make_ns_item_for_menu(ns_menu.0)?; + ns_menu.1.addItem(&ns_menu_item); + } + } + + let ns_menu_item = + item.make_ns_item_for_menu(self.ns_menu.as_ref().unwrap().0)?; + self.ns_menu.as_ref().unwrap().1.addItem(&ns_menu_item); + + self.children.as_mut().unwrap().push(child); + } + AddOp::Insert(position) => { + for menus in self.ns_menus.as_ref().unwrap().values() { + for ns_menu in menus { + let ns_menu_item = item.make_ns_item_for_menu(ns_menu.0)?; + ns_menu + .1 + .insertItem_atIndex(&ns_menu_item, position as NSInteger); + } + } + + let ns_menu_item = + item.make_ns_item_for_menu(self.ns_menu.as_ref().unwrap().0)?; + self.ns_menu + .as_ref() + .unwrap() + .1 + .insertItem_atIndex(&ns_menu_item, position as NSInteger); + + self.children.as_mut().unwrap().insert(position, child); + } + } + } + + Ok(()) + } + + pub fn remove(&mut self, item: &dyn crate::IsMenuItem) -> crate::Result<()> { + self.remove_inner(item, true, None) + } + pub fn remove_inner( + &mut self, + item: &dyn crate::IsMenuItem, + remove_from_cache: bool, + id: Option, + ) -> crate::Result<()> { + // get child + let child = { + let index = self + .children + .as_ref() + .unwrap() + .iter() + .position(|e| e.borrow().id == item.id()) + .ok_or(crate::Error::NotAChildOfThisMenu)?; + if remove_from_cache { + self.children.as_mut().unwrap().remove(index) + } else { + self.children.as_ref().unwrap().get(index).cloned().unwrap() + } + }; + + for menus in self.ns_menus.as_ref().unwrap().values() { + for menu in menus { + // check if we are removing this item from all ns_menus + // which is usually when this is the item the user is actually removing + // or if we are removing from a specific menu (id) + // which is when the actual item being removed is a submenu + // and we are iterating through its children and removing + // each child ns menu item that are related to this submenu. + if id.map(|i| i == menu.0).unwrap_or(true) { + let mut child_ = child.borrow_mut(); + + if child_.item_type == MenuItemType::Submenu { + let menus = child_.ns_menus.as_ref().unwrap().get(&menu.0).cloned(); + if let Some(menus) = menus { + for menu in menus { + // iterate through children and only remove the ns menu items + // related to this submenu + for item in child_.items() { + child_.remove_inner(item.as_ref(), false, Some(menu.0))?; + } + } + } + child_.ns_menus.as_mut().unwrap().remove(&menu.0); + } + + if let Some(items) = child_.ns_menu_items.remove(&menu.0) { + for item in items { + unsafe { menu.1.removeItem(&item) }; + } + } + } + } + } + + if remove_from_cache { + if let Some(ns_menu_items) = child + .borrow_mut() + .ns_menu_items + .remove(&self.ns_menu.as_ref().unwrap().0) + { + for item in ns_menu_items { + unsafe { self.ns_menu.as_ref().unwrap().1.removeItem(&item) }; + } + } + } + + Ok(()) + } + + pub fn items(&self) -> Vec { + self.children + .as_ref() + .unwrap() + .iter() + .map(|c| c.borrow().kind(c.clone())) + .collect() + } + + pub unsafe fn show_context_menu_for_nsview( + &self, + view: *const c_void, + position: Option, + ) -> bool { + show_context_menu(&self.ns_menu.as_ref().unwrap().1, view, position) + } + + pub fn set_as_windows_menu_for_nsapp(&self) { + let Some(menu) = self.resolve_ns_menu_for_nsapp() else { + return; + }; + + let mtm = MainThreadMarker::from(&*menu); + let app = NSApplication::sharedApplication(mtm); + unsafe { app.setWindowsMenu(Some(&menu)) } + } + + pub fn set_as_help_menu_for_nsapp(&self) { + let Some(menu) = self.resolve_ns_menu_for_nsapp() else { + return; + }; + + let mtm = MainThreadMarker::from(&*menu); + let app = NSApplication::sharedApplication(mtm); + unsafe { app.setHelpMenu(Some(&menu)) } + } + + /// Finds the NSMenu instance for this submenu that is attached to the + /// current NSApp main menu, by reading the menu id stored in the + /// main menu's delegate. + fn resolve_ns_menu_for_nsapp(&self) -> Option> { + let ns_menu = &self.ns_menu.as_ref().unwrap().1; + let mtm = MainThreadMarker::from(&**ns_menu); + let app = NSApplication::sharedApplication(mtm); + let main_menu = unsafe { app.mainMenu()? }; + let delegate = unsafe { main_menu.delegate()? }; + + // Downcast the delegate to our MudaMenuDelegate to get the menu id + let delegate_obj: &AnyObject = ProtocolObject::as_ref(&*delegate); + let muda_delegate: &MudaMenuDelegate = delegate_obj.downcast_ref()?; + let parent_id = muda_delegate.menu_id(); + + // Look up the NSMenu in ns_menus for this parent id + self.ns_menus + .as_ref() + .unwrap() + .get(&parent_id) + // A submenu can be added multiple times to the same parent menu + // lets just take the first one we find + .and_then(|menus| menus.first()) + .map(|menu_ref| menu_ref.1.clone()) + } + + pub fn ns_menu(&self) -> *mut std::ffi::c_void { + Retained::as_ptr(&self.ns_menu.as_ref().unwrap().1) as *mut _ + } +} + +/// NSMenuItem item creation methods +impl MenuChild { + pub fn create_ns_item_for_submenu( + &mut self, + menu_id: u32, + ) -> crate::Result> { + let mtm = MainThreadMarker::new().expect("can only create menu item on the main thread"); + let ns_menu_item; + let ns_submenu; + + let title = NSString::from_str(&self.text); + unsafe { + ns_menu_item = NSMenuItem::initWithTitle_action_keyEquivalent( + mtm.alloc(), + &title, + None, + &NSString::new(), + ); + ns_submenu = NSMenu::new(mtm); + ns_submenu.setTitle(&title); + + ns_menu_item.setSubmenu(Some(&ns_submenu)); + ns_submenu.setAutoenablesItems(false); + + ns_menu_item.setEnabled(self.enabled); + + if let Some(native_icon) = self.native_icon { + menuitem_set_native_icon(&ns_menu_item, Some(native_icon)); + } + + if let Some(icon) = self.icon.as_ref() { + menuitem_set_icon(&ns_menu_item, Some(icon)); + } + } + + let id = COUNTER.next(); + + for item in self.children.as_ref().unwrap() { + let ns_item = item.borrow_mut().make_ns_item_for_menu(id)?; + ns_submenu.addItem(&ns_item); + } + + self.ns_menus + .as_mut() + .unwrap() + .entry(menu_id) + .or_default() + .push(NsMenuRef::new(mtm, id, ns_submenu)); + + self.ns_menu_items + .entry(menu_id) + .or_default() + .push(ns_menu_item.retain()); + + Ok(ns_menu_item) + } + + pub fn create_ns_item_for_menu_item( + &mut self, + menu_id: u32, + ) -> crate::Result> { + let mtm = MainThreadMarker::new().expect("can only create menu item on the main thread"); + let ns_menu_item = MenuItem::create( + mtm, + &self.text, + Some(sel!(fireMenuItemAction:)), + &self.key_accelerator, + )?; + + unsafe { + ns_menu_item.setTarget(Some(&ns_menu_item)); + + // Store a raw pointer to the `MenuChild` as an instance variable on the native menu item + ns_menu_item.ivars().set(&*self); + + ns_menu_item.setEnabled(self.enabled); + } + + self.ns_menu_items + .entry(menu_id) + .or_default() + .push(Retained::into_super(ns_menu_item.retain())); + + Ok(Retained::into_super(ns_menu_item)) + } + + pub fn create_ns_item_for_predefined_menu_item( + &mut self, + menu_id: u32, + ) -> crate::Result> { + let mtm = MainThreadMarker::new().expect("can only create menu item on the main thread"); + let item_type = self.predefined_item_type.as_ref().unwrap(); + let ns_menu_item = match item_type { + PredefinedMenuItemType::Separator => NSMenuItem::separatorItem(mtm), + _ => { + let ns_menu_item = + MenuItem::create(mtm, &self.text, item_type.selector(), &self.key_accelerator)?; + + if let PredefinedMenuItemType::About(_) = item_type { + unsafe { + ns_menu_item.setTarget(Some(&ns_menu_item)); + + // Store a raw pointer to the `MenuChild` as an instance variable on the native menu item + ns_menu_item.ivars().set(&*self); + } + } + + Retained::into_super(ns_menu_item) + } + }; + + unsafe { + ns_menu_item.setEnabled(self.enabled); + + if let PredefinedMenuItemType::Services = item_type { + // we have to assign an empty menu as the app's services menu, and macOS will populate it + let services_menu = NSMenu::new(mtm); + NSApplication::sharedApplication(mtm).setServicesMenu(Some(&services_menu)); + ns_menu_item.setSubmenu(Some(&services_menu)); + } + } + + self.ns_menu_items + .entry(menu_id) + .or_default() + .push(ns_menu_item.retain()); + + Ok(ns_menu_item) + } + + pub fn create_ns_item_for_check_menu_item( + &mut self, + menu_id: u32, + ) -> crate::Result> { + let mtm = MainThreadMarker::new().expect("can only create menu item on the main thread"); + let ns_menu_item = MenuItem::create( + mtm, + &self.text, + Some(sel!(fireMenuItemAction:)), + &self.key_accelerator, + )?; + + unsafe { + ns_menu_item.setTarget(Some(&ns_menu_item)); + + // Store a raw pointer to the `MenuChild` as an instance variable on the native menu item + ns_menu_item.ivars().set(&*self); + + ns_menu_item.setEnabled(self.enabled); + if self.checked.get() { + ns_menu_item.setState(NSControlStateValueOn); + } + } + + self.ns_menu_items + .entry(menu_id) + .or_default() + .push(Retained::into_super(ns_menu_item.retain())); + + Ok(Retained::into_super(ns_menu_item)) + } + + pub fn create_ns_item_for_icon_menu_item( + &mut self, + menu_id: u32, + ) -> crate::Result> { + let mtm = MainThreadMarker::new().expect("can only create menu item on the main thread"); + let ns_menu_item = MenuItem::create( + mtm, + &self.text, + Some(sel!(fireMenuItemAction:)), + &self.key_accelerator, + )?; + + unsafe { + ns_menu_item.setTarget(Some(&ns_menu_item)); + + // Store a raw pointer to the `MenuChild` as an instance variable on the native menu item + ns_menu_item.ivars().set(&*self); + + ns_menu_item.setEnabled(self.enabled); + + if self.icon.is_some() { + menuitem_set_icon(&ns_menu_item, self.icon.as_ref()); + } else if self.native_icon.is_some() { + menuitem_set_native_icon(&ns_menu_item, self.native_icon); + } + } + + self.ns_menu_items + .entry(menu_id) + .or_default() + .push(Retained::into_super(ns_menu_item.retain())); + + Ok(Retained::into_super(ns_menu_item)) + } + + fn make_ns_item_for_menu(&mut self, menu_id: u32) -> crate::Result> { + match self.item_type { + MenuItemType::Submenu => self.create_ns_item_for_submenu(menu_id), + MenuItemType::MenuItem => self.create_ns_item_for_menu_item(menu_id), + MenuItemType::Predefined => self.create_ns_item_for_predefined_menu_item(menu_id), + MenuItemType::Check => self.create_ns_item_for_check_menu_item(menu_id), + MenuItemType::Icon => self.create_ns_item_for_icon_menu_item(menu_id), + } + } +} + +impl PredefinedMenuItemType { + pub(crate) fn selector(&self) -> Option { + match self { + PredefinedMenuItemType::Separator => None, + PredefinedMenuItemType::Copy => Some(sel!(copy:)), + PredefinedMenuItemType::Cut => Some(sel!(cut:)), + PredefinedMenuItemType::Paste => Some(sel!(paste:)), + PredefinedMenuItemType::SelectAll => Some(sel!(selectAll:)), + PredefinedMenuItemType::Undo => Some(sel!(undo:)), + PredefinedMenuItemType::Redo => Some(sel!(redo:)), + PredefinedMenuItemType::Minimize => Some(sel!(performMiniaturize:)), + PredefinedMenuItemType::Maximize => Some(sel!(performZoom:)), + PredefinedMenuItemType::Fullscreen => Some(sel!(toggleFullScreen:)), + PredefinedMenuItemType::Hide => Some(sel!(hide:)), + PredefinedMenuItemType::HideOthers => Some(sel!(hideOtherApplications:)), + PredefinedMenuItemType::ShowAll => Some(sel!(unhideAllApplications:)), + PredefinedMenuItemType::CloseWindow => Some(sel!(performClose:)), + PredefinedMenuItemType::Quit => Some(sel!(terminate:)), + // manual implementation in `fire_menu_item_click` + PredefinedMenuItemType::About(_) => Some(sel!(fireMenuItemAction:)), + PredefinedMenuItemType::Services => None, + PredefinedMenuItemType::BringAllToFront => Some(sel!(arrangeInFront:)), + PredefinedMenuItemType::None => None, + } + } +} + +impl dyn IsMenuItem + '_ { + fn make_ns_item_for_menu(&self, menu_id: u32) -> crate::Result> { + match self.kind() { + MenuItemKind::Submenu(i) => i.inner.borrow_mut().create_ns_item_for_submenu(menu_id), + MenuItemKind::MenuItem(i) => i.inner.borrow_mut().create_ns_item_for_menu_item(menu_id), + MenuItemKind::Predefined(i) => i + .inner + .borrow_mut() + .create_ns_item_for_predefined_menu_item(menu_id), + MenuItemKind::Check(i) => i + .inner + .borrow_mut() + .create_ns_item_for_check_menu_item(menu_id), + MenuItemKind::Icon(i) => i + .inner + .borrow_mut() + .create_ns_item_for_icon_menu_item(menu_id), + } + } +} + +define_class!( + #[unsafe(super(NSMenuItem))] + #[name = "MudaMenuItem"] + #[thread_kind = MainThreadOnly] + // FIXME: Use `Rc` or something else to access the MenuChild. + #[ivars = Cell<*const MenuChild>] + struct MenuItem; + + impl MenuItem { + #[unsafe(method(fireMenuItemAction:))] + fn fire_menu_item_action(&self, _sender: Option<&AnyObject>) { + self.fire_menu_item_click(); + } + } +); + +impl MenuItem { + fn new( + mtm: MainThreadMarker, + title: &NSString, + action: Option, + key_equivalent: &NSString, + ) -> Retained { + let this = mtm.alloc().set_ivars(Cell::new(ptr::null())); + unsafe { + msg_send![super(this), initWithTitle: title, action: action, keyEquivalent: key_equivalent] + } + } + + fn fire_menu_item_click(&self) { + let mtm = MainThreadMarker::from(self); + // Create a reference to the `MenuChild` from the raw pointer + // stored as an instance variable on the native menu item + let item = + unsafe { self.ivars().get().as_ref() }.expect("MenuItem's MenuChild pointer was unset"); + + if let Some(PredefinedMenuItemType::About(about_meta)) = &item.predefined_item_type { + match about_meta { + Some(about_meta) => { + let mut keys: Vec<&NSString> = Default::default(); + let mut objects: Vec> = Default::default(); + + if let Some(name) = &about_meta.name { + keys.push(unsafe { NSAboutPanelOptionApplicationName }); + objects.push(Retained::into_super(Retained::into_super( + NSString::from_str(name), + ))); + } + + if let Some(version) = &about_meta.version { + keys.push(unsafe { NSAboutPanelOptionApplicationVersion }); + objects.push(Retained::into_super(Retained::into_super( + NSString::from_str(version), + ))); + } + + if let Some(short_version) = &about_meta.short_version { + keys.push(unsafe { NSAboutPanelOptionVersion }); + objects.push(Retained::into_super(Retained::into_super( + NSString::from_str(short_version), + ))); + } + + if let Some(copyright) = &about_meta.copyright { + keys.push(ns_string!(NSAboutPanelOptionCopyright)); + objects.push(Retained::into_super(Retained::into_super( + NSString::from_str(copyright), + ))); + } + + if let Some(icon) = &about_meta.icon { + keys.push(unsafe { NSAboutPanelOptionApplicationIcon }); + objects.push(Retained::into_super(Retained::into_super( + icon.inner.to_nsimage(None), + ))); + } + + if let Some(credits) = &about_meta.credits { + keys.push(unsafe { NSAboutPanelOptionCredits }); + objects.push(Retained::into_super(Retained::into_super( + NSAttributedString::from_nsstring(&NSString::from_str(credits)), + ))); + } + + let dict = NSDictionary::from_retained_objects(&keys, &objects); + + unsafe { + NSApplication::sharedApplication(mtm) + .orderFrontStandardAboutPanelWithOptions(&dict) + }; + } + + None => { + unsafe { + NSApplication::sharedApplication(mtm) + .orderFrontStandardAboutPanel(Some(self)) + }; + } + } + } else { + if item.item_type == MenuItemType::Check { + item.set_checked(!item.is_checked()); + } + + let id = (*item).id().clone(); + MenuEvent::send(crate::MenuEvent { id }); + } + } + + fn create( + mtm: MainThreadMarker, + title: &str, + selector: Option, + key_accelerator: &Option, + ) -> crate::Result> { + let title = NSString::from_str(title); + + let key_equivalent = key_accelerator + .as_ref() + .map(|accel| accel.key_equivalent()) + .transpose()? + .unwrap_or_default(); + let key_equivalent = NSString::from_str(&key_equivalent); + + let modifier_mask = key_accelerator + .as_ref() + .map(KeyAccelerator::modifier_mask) + .unwrap_or_else(NSEventModifierFlags::empty); + + let item = MenuItem::new(mtm, &title, selector, &key_equivalent); + item.setKeyEquivalentModifierMask(modifier_mask); + + Ok(item) + } +} + +fn menuitem_set_icon(menuitem: &NSMenuItem, icon: Option<&Icon>) { + if let Some(icon) = icon { + unsafe { + let nsimage = icon.inner.to_nsimage(Some(18.)); + menuitem.setImage(Some(&nsimage)); + } + } else { + unsafe { + menuitem.setImage(None); + } + } +} + +fn menuitem_set_native_icon(menuitem: &NSMenuItem, icon: Option) { + if let Some(icon) = icon { + unsafe { + let named_img = icon.named_img(); + let nsimage = NSImage::imageNamed(named_img).unwrap(); + let size = NSSize::new(18.0, 18.0); + nsimage.setSize(size); + menuitem.setImage(Some(&nsimage)); + } + } else { + unsafe { + menuitem.setImage(None); + } + } +} + +unsafe fn show_context_menu( + ns_menu: &NSMenu, + view: *const c_void, + position: Option, +) -> bool { + // SAFETY: Caller verifies that the view is valid. + let view: &NSView = unsafe { &*view.cast() }; + + let window = view.window().expect("view must be installed in a window"); + let scale_factor = window.backingScaleFactor(); + let (location, in_view) = if let Some(pos) = position.map(|p| p.to_logical(scale_factor)) { + let view_rect = view.frame(); + let location = NSPoint::new(pos.x, view_rect.size.height - pos.y); + (location, Some(view)) + } else { + let mouse_location = unsafe { NSEvent::mouseLocation() }; + let pos = LogicalPosition { + x: mouse_location.x, + y: mouse_location.y, + }; + let location = NSPoint::new(pos.x, pos.y); + (location, None) + }; + + unsafe { ns_menu.popUpMenuPositioningItem_atLocation_inView(None, location, in_view) } +} + +impl NativeIcon { + unsafe fn named_img(self) -> &'static NSImageName { + use objc2_app_kit as appkit; + match self { + NativeIcon::Add => appkit::NSImageNameAddTemplate, + NativeIcon::StatusAvailable => appkit::NSImageNameStatusAvailable, + NativeIcon::StatusUnavailable => appkit::NSImageNameStatusUnavailable, + NativeIcon::StatusPartiallyAvailable => appkit::NSImageNameStatusPartiallyAvailable, + NativeIcon::Advanced => appkit::NSImageNameAdvanced, + NativeIcon::Bluetooth => appkit::NSImageNameBluetoothTemplate, + NativeIcon::Bookmarks => appkit::NSImageNameBookmarksTemplate, + NativeIcon::Caution => appkit::NSImageNameCaution, + NativeIcon::ColorPanel => appkit::NSImageNameColorPanel, + NativeIcon::ColumnView => appkit::NSImageNameColumnViewTemplate, + NativeIcon::Computer => appkit::NSImageNameComputer, + NativeIcon::EnterFullScreen => appkit::NSImageNameEnterFullScreenTemplate, + NativeIcon::Everyone => appkit::NSImageNameEveryone, + NativeIcon::ExitFullScreen => appkit::NSImageNameExitFullScreenTemplate, + NativeIcon::FlowView => appkit::NSImageNameFlowViewTemplate, + NativeIcon::Folder => appkit::NSImageNameFolder, + NativeIcon::FolderBurnable => appkit::NSImageNameFolderBurnable, + NativeIcon::FolderSmart => appkit::NSImageNameFolderSmart, + NativeIcon::FollowLinkFreestanding => appkit::NSImageNameFollowLinkFreestandingTemplate, + NativeIcon::FontPanel => appkit::NSImageNameFontPanel, + NativeIcon::GoLeft => appkit::NSImageNameGoLeftTemplate, + NativeIcon::GoRight => appkit::NSImageNameGoRightTemplate, + NativeIcon::Home => appkit::NSImageNameHomeTemplate, + NativeIcon::IChatTheater => appkit::NSImageNameIChatTheaterTemplate, + NativeIcon::IconView => appkit::NSImageNameIconViewTemplate, + NativeIcon::Info => appkit::NSImageNameInfo, + NativeIcon::InvalidDataFreestanding => { + appkit::NSImageNameInvalidDataFreestandingTemplate + } + NativeIcon::LeftFacingTriangle => appkit::NSImageNameLeftFacingTriangleTemplate, + NativeIcon::ListView => appkit::NSImageNameListViewTemplate, + NativeIcon::LockLocked => appkit::NSImageNameLockLockedTemplate, + NativeIcon::LockUnlocked => appkit::NSImageNameLockUnlockedTemplate, + NativeIcon::MenuMixedState => appkit::NSImageNameMenuMixedStateTemplate, + NativeIcon::MenuOnState => appkit::NSImageNameMenuOnStateTemplate, + NativeIcon::MobileMe => appkit::NSImageNameMobileMe, + NativeIcon::MultipleDocuments => appkit::NSImageNameMultipleDocuments, + NativeIcon::Network => appkit::NSImageNameNetwork, + NativeIcon::Path => appkit::NSImageNamePathTemplate, + NativeIcon::PreferencesGeneral => appkit::NSImageNamePreferencesGeneral, + NativeIcon::QuickLook => appkit::NSImageNameQuickLookTemplate, + NativeIcon::RefreshFreestanding => appkit::NSImageNameRefreshFreestandingTemplate, + NativeIcon::Refresh => appkit::NSImageNameRefreshTemplate, + NativeIcon::Remove => appkit::NSImageNameRemoveTemplate, + NativeIcon::RevealFreestanding => appkit::NSImageNameRevealFreestandingTemplate, + NativeIcon::RightFacingTriangle => appkit::NSImageNameRightFacingTriangleTemplate, + NativeIcon::Share => appkit::NSImageNameShareTemplate, + NativeIcon::Slideshow => appkit::NSImageNameSlideshowTemplate, + NativeIcon::SmartBadge => appkit::NSImageNameSmartBadgeTemplate, + NativeIcon::StatusNone => appkit::NSImageNameStatusNone, + NativeIcon::StopProgressFreestanding => { + appkit::NSImageNameStopProgressFreestandingTemplate + } + NativeIcon::StopProgress => appkit::NSImageNameStopProgressTemplate, + NativeIcon::TrashEmpty => appkit::NSImageNameTrashEmpty, + NativeIcon::TrashFull => appkit::NSImageNameTrashFull, + NativeIcon::User => appkit::NSImageNameUser, + NativeIcon::UserAccounts => appkit::NSImageNameUserAccounts, + NativeIcon::UserGroup => appkit::NSImageNameUserGroup, + NativeIcon::UserGuest => appkit::NSImageNameUserGuest, + } + } +} diff --git a/ports/muda/src/platform_impl/macos/util.rs b/ports/muda/src/platform_impl/macos/util.rs new file mode 100644 index 000000000000..c6c9d735f54c --- /dev/null +++ b/ports/muda/src/platform_impl/macos/util.rs @@ -0,0 +1,16 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::str; + +/// Strips single `&` characters from the string. +/// +/// `&` can be escaped as `&&` to prevent stripping, in which case a single `&` will be output. +pub fn strip_mnemonic>(string: S) -> String { + string + .as_ref() + .replace("&&", "[~~]") + .replace('&', "") + .replace("[~~]", "&") +} diff --git a/ports/muda/src/platform_impl/mod.rs b/ports/muda/src/platform_impl/mod.rs new file mode 100644 index 000000000000..2288fcbca9ad --- /dev/null +++ b/ports/muda/src/platform_impl/mod.rs @@ -0,0 +1,119 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#[cfg(target_os = "windows")] +#[path = "windows/mod.rs"] +mod platform; +#[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" +))] +#[path = "gtk/mod.rs"] +mod platform; +#[cfg(target_os = "macos")] +#[path = "macos/mod.rs"] +mod platform; + +use std::{ + cell::{Ref, RefCell, RefMut}, + rc::Rc, +}; + +use crate::{items::*, IsMenuItem, MenuItemKind, MenuItemType}; + +pub(crate) use self::platform::*; + +impl dyn IsMenuItem + '_ { + fn child(&self) -> Rc> { + match self.kind() { + MenuItemKind::MenuItem(i) => i.inner, + MenuItemKind::Submenu(i) => i.inner, + MenuItemKind::Predefined(i) => i.inner, + MenuItemKind::Check(i) => i.inner, + MenuItemKind::Icon(i) => i.inner, + } + } +} + +/// Internal utilities +impl MenuChild { + fn kind(&self, c: Rc>) -> MenuItemKind { + match self.item_type() { + MenuItemType::Submenu => { + let id = c.borrow().id().clone(); + MenuItemKind::Submenu(Submenu { + id: Rc::new(id), + inner: c, + }) + } + MenuItemType::MenuItem => { + let id = c.borrow().id().clone(); + MenuItemKind::MenuItem(MenuItem { + id: Rc::new(id), + inner: c, + }) + } + MenuItemType::Predefined => { + let id = c.borrow().id().clone(); + MenuItemKind::Predefined(PredefinedMenuItem { + id: Rc::new(id), + inner: c, + }) + } + MenuItemType::Check => { + let id = c.borrow().id().clone(); + MenuItemKind::Check(CheckMenuItem { + id: Rc::new(id), + inner: c, + }) + } + MenuItemType::Icon => { + let id = c.borrow().id().clone(); + MenuItemKind::Icon(IconMenuItem { + id: Rc::new(id), + inner: c, + }) + } + } + } +} + +#[allow(unused)] +impl MenuItemKind { + pub(crate) fn as_ref(&self) -> &dyn IsMenuItem { + match self { + MenuItemKind::MenuItem(i) => i, + MenuItemKind::Submenu(i) => i, + MenuItemKind::Predefined(i) => i, + MenuItemKind::Check(i) => i, + MenuItemKind::Icon(i) => i, + } + } + + pub(crate) fn child(&self) -> Ref<'_, MenuChild> { + match self { + MenuItemKind::MenuItem(i) => i.inner.borrow(), + MenuItemKind::Submenu(i) => i.inner.borrow(), + MenuItemKind::Predefined(i) => i.inner.borrow(), + MenuItemKind::Check(i) => i.inner.borrow(), + MenuItemKind::Icon(i) => i.inner.borrow(), + } + } + + pub(crate) fn child_mut(&self) -> RefMut<'_, MenuChild> { + match self { + MenuItemKind::MenuItem(i) => i.inner.borrow_mut(), + MenuItemKind::Submenu(i) => i.inner.borrow_mut(), + MenuItemKind::Predefined(i) => i.inner.borrow_mut(), + MenuItemKind::Check(i) => i.inner.borrow_mut(), + MenuItemKind::Icon(i) => i.inner.borrow_mut(), + } + } +} diff --git a/ports/muda/src/platform_impl/windows/accelerator.rs b/ports/muda/src/platform_impl/windows/accelerator.rs new file mode 100644 index 000000000000..230394ee868a --- /dev/null +++ b/ports/muda/src/platform_impl/windows/accelerator.rs @@ -0,0 +1,221 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::fmt; + +use keyboard_types::{Key, Modifiers}; +use windows_sys::Win32::UI::{ + Input::KeyboardAndMouse::*, + WindowsAndMessaging::{ACCEL, FALT, FCONTROL, FSHIFT, FVIRTKEY}, +}; + +use crate::accelerator::{Accelerator, AcceleratorParseError, KeyAccelerator}; + +impl KeyAccelerator { + pub fn to_accel(&self, menu_id: u16) -> crate::Result { + let mut virt_key = FVIRTKEY; + let key_mods: Modifiers = self.mods; + if key_mods.contains(Modifiers::CONTROL) { + virt_key |= FCONTROL; + } + if key_mods.contains(Modifiers::ALT) { + virt_key |= FALT; + } + if key_mods.contains(Modifiers::SHIFT) { + virt_key |= FSHIFT; + } + + let vk_code = key_to_vk(&self.key)?; + let mod_code = vk_code >> 8; + if mod_code & 0x1 != 0 { + virt_key |= FSHIFT; + } + if mod_code & 0x02 != 0 { + virt_key |= FCONTROL; + } + if mod_code & 0x04 != 0 { + virt_key |= FALT; + } + let raw_key = vk_code & 0x00ff; + + Ok(ACCEL { + fVirt: virt_key, + key: raw_key, + cmd: menu_id, + }) + } +} + +// used to build accelerators table from Key +fn key_to_vk(key: &Key) -> Result { + Ok(match key { + Key::Character(s) => match s.as_str() { + "a" | "A" => VK_A, + "b" | "B" => VK_B, + "c" | "C" => VK_C, + "d" | "D" => VK_D, + "e" | "E" => VK_E, + "f" | "F" => VK_F, + "g" | "G" => VK_G, + "h" | "H" => VK_H, + "i" | "I" => VK_I, + "j" | "J" => VK_J, + "k" | "K" => VK_K, + "l" | "L" => VK_L, + "m" | "M" => VK_M, + "n" | "N" => VK_N, + "o" | "O" => VK_O, + "p" | "P" => VK_P, + "q" | "Q" => VK_Q, + "r" | "R" => VK_R, + "s" | "S" => VK_S, + "t" | "T" => VK_T, + "u" | "U" => VK_U, + "v" | "V" => VK_V, + "w" | "W" => VK_W, + "x" | "X" => VK_X, + "y" | "Y" => VK_Y, + "z" | "Z" => VK_Z, + "0" => VK_0, + "1" => VK_1, + "2" => VK_2, + "3" => VK_3, + "4" => VK_4, + "5" => VK_5, + "6" => VK_6, + "7" => VK_7, + "8" => VK_8, + "9" => VK_9, + "=" | "+" => VK_OEM_PLUS, + "," => VK_OEM_COMMA, + "-" => VK_OEM_MINUS, + "." => VK_OEM_PERIOD, + ";" => VK_OEM_1, + "/" => VK_OEM_2, + "`" => VK_OEM_3, + "[" => VK_OEM_4, + "\\" => VK_OEM_5, + "]" => VK_OEM_6, + "'" => VK_OEM_7, + " " => VK_SPACE, + other => { + // Try VkKeyScanW for characters reachable on the current keyboard layout + let c = other + .chars() + .next() + .ok_or_else(|| AcceleratorParseError::UnsupportedKey(other.to_string()))?; + let result = unsafe { VkKeyScanW(c as u16) }; + if result as i16 == -1 { + return Err(AcceleratorParseError::UnsupportedKey(other.to_string())); + } + result as VIRTUAL_KEY + } + }, + Key::Backspace => VK_BACK, + Key::Tab => VK_TAB, + Key::Enter => VK_RETURN, + Key::Pause => VK_PAUSE, + Key::CapsLock => VK_CAPITAL, + Key::KanaMode => VK_KANA, + Key::Escape => VK_ESCAPE, + Key::NonConvert => VK_NONCONVERT, + Key::PageUp => VK_PRIOR, + Key::PageDown => VK_NEXT, + Key::End => VK_END, + Key::Home => VK_HOME, + Key::ArrowLeft => VK_LEFT, + Key::ArrowUp => VK_UP, + Key::ArrowRight => VK_RIGHT, + Key::ArrowDown => VK_DOWN, + Key::PrintScreen => VK_SNAPSHOT, + Key::Insert => VK_INSERT, + Key::Delete => VK_DELETE, + Key::Help => VK_HELP, + Key::ContextMenu => VK_APPS, + Key::F1 => VK_F1, + Key::F2 => VK_F2, + Key::F3 => VK_F3, + Key::F4 => VK_F4, + Key::F5 => VK_F5, + Key::F6 => VK_F6, + Key::F7 => VK_F7, + Key::F8 => VK_F8, + Key::F9 => VK_F9, + Key::F10 => VK_F10, + Key::F11 => VK_F11, + Key::F12 => VK_F12, + Key::F13 => VK_F13, + Key::F14 => VK_F14, + Key::F15 => VK_F15, + Key::F16 => VK_F16, + Key::F17 => VK_F17, + Key::F18 => VK_F18, + Key::F19 => VK_F19, + Key::F20 => VK_F20, + Key::F21 => VK_F21, + Key::F22 => VK_F22, + Key::F23 => VK_F23, + Key::F24 => VK_F24, + Key::NumLock => VK_NUMLOCK, + Key::ScrollLock => VK_SCROLL, + Key::BrowserBack => VK_BROWSER_BACK, + Key::BrowserForward => VK_BROWSER_FORWARD, + Key::BrowserRefresh => VK_BROWSER_REFRESH, + Key::BrowserStop => VK_BROWSER_STOP, + Key::BrowserSearch => VK_BROWSER_SEARCH, + Key::BrowserFavorites => VK_BROWSER_FAVORITES, + Key::BrowserHome => VK_BROWSER_HOME, + Key::AudioVolumeMute => VK_VOLUME_MUTE, + Key::AudioVolumeDown => VK_VOLUME_DOWN, + Key::AudioVolumeUp => VK_VOLUME_UP, + Key::MediaTrackNext => VK_MEDIA_NEXT_TRACK, + Key::MediaTrackPrevious => VK_MEDIA_PREV_TRACK, + Key::MediaStop => VK_MEDIA_STOP, + Key::MediaPlayPause => VK_MEDIA_PLAY_PAUSE, + Key::LaunchMail => VK_LAUNCH_MAIL, + Key::Convert => VK_CONVERT, + key => return Err(AcceleratorParseError::UnsupportedKey(format!("{:?}", key))), + }) +} + +impl fmt::Display for Accelerator { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", KeyAccelerator::from(*self)) + } +} + +impl fmt::Display for KeyAccelerator { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let key_mods: Modifiers = self.mods; + if key_mods.contains(Modifiers::CONTROL) { + write!(f, "Ctrl+")?; + } + if key_mods.contains(Modifiers::SHIFT) { + write!(f, "Shift+")?; + } + if key_mods.contains(Modifiers::ALT) { + write!(f, "Alt+")?; + } + if key_mods.contains(Modifiers::SUPER) { + write!(f, "Windows+")?; + } + match &self.key { + Key::Character(s) => match s.as_str() { + " " => write!(f, "Space"), + c => write!(f, "{}", c.to_uppercase()), + }, + Key::Tab => write!(f, "Tab"), + Key::Escape => write!(f, "Esc"), + Key::Delete => write!(f, "Del"), + Key::Insert => write!(f, "Ins"), + Key::PageUp => write!(f, "PgUp"), + Key::PageDown => write!(f, "PgDn"), + Key::ArrowLeft => write!(f, "Left"), + Key::ArrowRight => write!(f, "Right"), + Key::ArrowUp => write!(f, "Up"), + Key::ArrowDown => write!(f, "Down"), + key => write!(f, "{:?}", key), + } + } +} diff --git a/ports/muda/src/platform_impl/windows/dark_menu_bar.rs b/ports/muda/src/platform_impl/windows/dark_menu_bar.rs new file mode 100644 index 000000000000..9e2346b56517 --- /dev/null +++ b/ports/muda/src/platform_impl/windows/dark_menu_bar.rs @@ -0,0 +1,346 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +// this is a port of combination of https://github.com/hrydgard/ppsspp/blob/master/Windows/W32Util/UAHMenuBar.cpp and https://github.com/ysc3839/win32-darkmode/blob/master/win32-darkmode/DarkMode.h + +#![allow(non_snake_case, clippy::upper_case_acronyms)] + +use std::cell::Cell; + +use once_cell::sync::Lazy; +use windows_sys::{ + s, + Win32::{ + Foundation::{HWND, LPARAM, RECT, WPARAM}, + Graphics::Gdi::*, + System::LibraryLoader::{GetProcAddress, LoadLibraryA}, + UI::{ + Accessibility::HIGHCONTRASTA, + Controls::*, + WindowsAndMessaging::{ + GetClientRect, GetMenuBarInfo, GetMenuItemInfoW, GetWindowRect, + SystemParametersInfoA, HMENU, MENUBARINFO, MENUITEMINFOW, MIIM_STRING, OBJID_MENU, + SPI_GETHIGHCONTRAST, WM_NCACTIVATE, WM_NCPAINT, + }, + }, + }, +}; + +pub const WM_UAHDRAWMENU: u32 = 0x0091; +pub const WM_UAHDRAWMENUITEM: u32 = 0x0092; + +#[repr(C)] +struct UAHMENUITEMMETRICS0 { + cx: u32, + cy: u32, +} + +#[repr(C)] +struct UAHMENUITEMMETRICS { + rgsizeBar: [UAHMENUITEMMETRICS0; 2], + rgsizePopup: [UAHMENUITEMMETRICS0; 4], +} + +#[repr(C)] +struct UAHMENUPOPUPMETRICS { + rgcx: [u32; 4], + fUpdateMaxWidths: u32, +} + +#[repr(C)] +struct UAHMENU { + hmenu: HMENU, + hdc: HDC, + dwFlags: u32, +} +#[repr(C)] +struct UAHMENUITEM { + iPosition: u32, + umim: UAHMENUITEMMETRICS, + umpm: UAHMENUPOPUPMETRICS, +} +#[repr(C)] +struct UAHDRAWMENUITEM { + dis: DRAWITEMSTRUCT, + um: UAHMENU, + umi: UAHMENUITEM, +} + +#[derive(Debug)] +struct Win32Brush(Cell); + +impl Win32Brush { + const fn null() -> Win32Brush { + Self(Cell::new(0 as _)) + } + + fn get_or_set(&self, color: u32) -> HBRUSH { + if self.0.get().is_null() { + self.0.set(unsafe { CreateSolidBrush(color) }); + } + self.0.get() + } +} + +impl Drop for Win32Brush { + fn drop(&mut self) { + unsafe { DeleteObject(self.0.get()) }; + } +} + +fn background_brush() -> HBRUSH { + thread_local! { + static BACKGROUND_BRUSH: Win32Brush = const { Win32Brush::null() }; + } + const BACKGROUND_COLOR: u32 = 2829099; + BACKGROUND_BRUSH.with(|brush| brush.get_or_set(BACKGROUND_COLOR)) +} + +fn selected_background_brush() -> HBRUSH { + thread_local! { + static SELECTED_BACKGROUND_BRUSH: Win32Brush = const { Win32Brush::null() }; + } + const SELECTED_BACKGROUND_COLOR: u32 = 4276545; + SELECTED_BACKGROUND_BRUSH.with(|brush| brush.get_or_set(SELECTED_BACKGROUND_COLOR)) +} + +/// Draws a dark menu bar if needed and returns whether it draws it or not +pub fn draw(hwnd: super::Hwnd, msg: u32, _wparam: WPARAM, lparam: LPARAM) { + match msg { + // draw over the annoying white line blow menubar + // ref: https://github.com/notepad-plus-plus/notepad-plus-plus/pull/9985 + WM_NCACTIVATE | WM_NCPAINT => { + let mut mbi = MENUBARINFO { + cbSize: std::mem::size_of::() as _, + ..unsafe { std::mem::zeroed() } + }; + unsafe { GetMenuBarInfo(hwnd as _, OBJID_MENU, 0, &mut mbi) }; + + let mut client_rc: RECT = unsafe { std::mem::zeroed() }; + unsafe { + GetClientRect(hwnd as _, &mut client_rc); + MapWindowPoints( + hwnd as _, + std::ptr::null_mut(), + &mut client_rc as *mut _ as *mut _, + 2, + ); + }; + + let mut window_rc: RECT = unsafe { std::mem::zeroed() }; + unsafe { GetWindowRect(hwnd as _, &mut window_rc) }; + + unsafe { OffsetRect(&mut client_rc, -window_rc.left, -window_rc.top) }; + + let mut annoying_rc = client_rc; + annoying_rc.bottom = annoying_rc.top; + annoying_rc.top -= 1; + + unsafe { + let hdc = GetWindowDC(hwnd as _); + FillRect(hdc, &annoying_rc, background_brush()); + ReleaseDC(hwnd as _, hdc); + } + } + + // draw menu bar background + WM_UAHDRAWMENU => { + let pudm = lparam as *const UAHMENU; + + // get the menubar rect + let rc = { + let mut mbi = MENUBARINFO { + cbSize: std::mem::size_of::() as _, + ..unsafe { std::mem::zeroed() } + }; + unsafe { GetMenuBarInfo(hwnd as _, OBJID_MENU, 0, &mut mbi) }; + + let mut window_rc: RECT = unsafe { std::mem::zeroed() }; + unsafe { GetWindowRect(hwnd as _, &mut window_rc) }; + + let mut rc = mbi.rcBar; + // the rcBar is offset by the window rect + unsafe { OffsetRect(&mut rc, -window_rc.left, -window_rc.top) }; + rc.top -= 1; + rc + }; + + unsafe { FillRect((*pudm).hdc, &rc, background_brush()) }; + } + + // draw menu bar items + WM_UAHDRAWMENUITEM => { + let pudmi = lparam as *mut UAHDRAWMENUITEM; + + // get the menu item string + let (label, cch) = { + let mut info: MENUITEMINFOW = unsafe { std::mem::zeroed() }; + info.cbSize = std::mem::size_of::() as _; + info.fMask = MIIM_STRING; + let ok = unsafe { + GetMenuItemInfoW( + (*pudmi).um.hmenu, + (*pudmi).umi.iPosition, + true.into(), + &mut info, + ) + }; + if ok == 0 { + return; + } + + info.cch += 1; // add 1 for null terminator + let mut label = vec![0u16; info.cch as usize]; + info.dwTypeData = label.as_mut_ptr(); + + let ok = unsafe { + GetMenuItemInfoW( + (*pudmi).um.hmenu, + (*pudmi).umi.iPosition, + true.into(), + &mut info, + ) + }; + if ok == 0 { + return; + } + + (label, info.cch) + }; + + // get the item state for drawing + let mut dw_flags = DT_CENTER | DT_SINGLELINE | DT_VCENTER; + let mut i_text_state_id = 0; + let mut i_background_state_id = 0; + + unsafe { + if (((*pudmi).dis.itemState & ODS_INACTIVE) + | ((*pudmi).dis.itemState & ODS_DEFAULT)) + != 0 + { + // normal display + i_text_state_id = MPI_NORMAL; + i_background_state_id = MPI_NORMAL; + } + if (*pudmi).dis.itemState & ODS_HOTLIGHT != 0 { + // hot tracking + i_text_state_id = MPI_HOT; + i_background_state_id = MPI_HOT; + } + if (*pudmi).dis.itemState & ODS_SELECTED != 0 { + // clicked -- MENU_POPUPITEM has no state for this, though MENU_BARITEM does + i_text_state_id = MPI_HOT; + i_background_state_id = MPI_HOT; + } + if ((*pudmi).dis.itemState & ODS_GRAYED) != 0 + || ((*pudmi).dis.itemState & ODS_DISABLED) != 0 + { + // disabled / grey text + i_text_state_id = MPI_DISABLED; + i_background_state_id = MPI_DISABLED; + } + if ((*pudmi).dis.itemState & ODS_NOACCEL) != 0 { + dw_flags |= DT_HIDEPREFIX; + } + + let bg_brush = match i_background_state_id { + MPI_HOT => selected_background_brush(), + _ => background_brush(), + }; + + FillRect((*pudmi).um.hdc, &(*pudmi).dis.rcItem, bg_brush); + + const TEXT_COLOR: u32 = 16777215; + const DISABLED_TEXT_COLOR: u32 = 7171437; + + let text_brush = match i_text_state_id { + MPI_DISABLED => DISABLED_TEXT_COLOR, + _ => TEXT_COLOR, + }; + + SetBkMode((*pudmi).um.hdc, 0); + SetTextColor((*pudmi).um.hdc, text_brush); + DrawTextW( + (*pudmi).um.hdc, + label.as_ptr(), + cch as _, + &mut (*pudmi).dis.rcItem, + dw_flags, + ); + } + } + + _ => {} + }; +} + +pub fn should_use_dark_mode(hwnd: super::Hwnd) -> bool { + should_apps_use_dark_mode() && !is_high_contrast() && is_dark_mode_allowed_for_window(hwnd as _) +} + +static HUXTHEME: Lazy = Lazy::new(|| unsafe { LoadLibraryA(s!("uxtheme.dll")) as _ }); + +fn should_apps_use_dark_mode() -> bool { + const UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL: u16 = 132; + type ShouldAppsUseDarkMode = unsafe extern "system" fn() -> bool; + static SHOULD_APPS_USE_DARK_MODE: Lazy> = Lazy::new(|| unsafe { + if *HUXTHEME == 0 { + return None; + } + + GetProcAddress( + (*HUXTHEME) as *mut _, + UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL as usize as *mut _, + ) + .map(|handle| std::mem::transmute(handle)) + }); + + SHOULD_APPS_USE_DARK_MODE + .map(|should_apps_use_dark_mode| unsafe { (should_apps_use_dark_mode)() }) + .unwrap_or(false) +} + +fn is_dark_mode_allowed_for_window(hwnd: HWND) -> bool { + const UXTHEME_ISDARKMODEALLOWEDFORWINDOW_ORDINAL: u16 = 137; + type IsDarkModeAllowedForWindow = unsafe extern "system" fn(HWND) -> bool; + static IS_DARK_MODE_ALLOWED_FOR_WINDOW: Lazy> = + Lazy::new(|| unsafe { + if *HUXTHEME == 0 { + return None; + } + + GetProcAddress( + (*HUXTHEME) as *mut _, + UXTHEME_ISDARKMODEALLOWEDFORWINDOW_ORDINAL as usize as *mut _, + ) + .map(|handle| std::mem::transmute(handle)) + }); + + if let Some(_is_dark_mode_allowed_for_window) = *IS_DARK_MODE_ALLOWED_FOR_WINDOW { + unsafe { _is_dark_mode_allowed_for_window(hwnd) } + } else { + false + } +} + +fn is_high_contrast() -> bool { + const HCF_HIGHCONTRASTON: u32 = 1; + + let mut hc = HIGHCONTRASTA { + cbSize: 0, + dwFlags: Default::default(), + lpszDefaultScheme: std::ptr::null_mut(), + }; + + let ok = unsafe { + SystemParametersInfoA( + SPI_GETHIGHCONTRAST, + std::mem::size_of_val(&hc) as _, + &mut hc as *mut _ as _, + Default::default(), + ) + }; + + ok != 0 && (HCF_HIGHCONTRASTON & hc.dwFlags) != 0 +} diff --git a/ports/muda/src/platform_impl/windows/icon.rs b/ports/muda/src/platform_impl/windows/icon.rs new file mode 100644 index 000000000000..c1c32a228caa --- /dev/null +++ b/ports/muda/src/platform_impl/windows/icon.rs @@ -0,0 +1,201 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +// taken from https://github.com/rust-windowing/winit/blob/92fdf5ba85f920262a61cee4590f4a11ad5738d1/src/platform_impl/windows/icon.rs + +use std::{fmt, io, mem, path::Path, sync::Arc}; + +use windows_sys::{ + core::PCWSTR, + Win32::{ + Foundation::RECT, + Graphics::Gdi::{ + CreateCompatibleDC, CreateDIBSection, DeleteDC, GetDC, ReleaseDC, SelectObject, + BITMAPINFO, BITMAPINFOHEADER, BI_RGB, DIB_RGB_COLORS, HBITMAP, + }, + UI::WindowsAndMessaging::{ + CreateIcon, DestroyIcon, DrawIconEx, LoadImageW, DI_NORMAL, HICON, IMAGE_ICON, + LR_DEFAULTSIZE, LR_LOADFROMFILE, + }, + }, +}; + +use crate::icon::*; + +use super::util; + +impl Pixel { + fn convert_to_bgra(&mut self) { + mem::swap(&mut self.r, &mut self.b); + } +} + +impl RgbaIcon { + fn into_windows_icon(self) -> Result { + let rgba = self.rgba; + let pixel_count = rgba.len() / PIXEL_SIZE; + let mut and_mask = Vec::with_capacity(pixel_count); + let pixels = + unsafe { std::slice::from_raw_parts_mut(rgba.as_ptr() as *mut Pixel, pixel_count) }; + for pixel in pixels { + and_mask.push(pixel.a.wrapping_sub(u8::MAX)); // invert alpha channel + pixel.convert_to_bgra(); + } + assert_eq!(and_mask.len(), pixel_count); + let handle = unsafe { + CreateIcon( + std::ptr::null_mut(), + self.width as i32, + self.height as i32, + 1, + (PIXEL_SIZE * 8) as u8, + and_mask.as_ptr(), + rgba.as_ptr(), + ) + }; + if !handle.is_null() { + Ok(WinIcon::from_handle(handle)) + } else { + Err(BadIcon::OsError(io::Error::last_os_error())) + } + } +} + +#[derive(Debug)] +struct RaiiIcon { + handle: HICON, +} + +#[derive(Clone)] +pub(crate) struct WinIcon { + inner: Arc, +} + +unsafe impl Send for WinIcon {} + +impl WinIcon { + pub unsafe fn to_hbitmap(&self) -> HBITMAP { + let hdc = CreateCompatibleDC(std::ptr::null_mut()); + + let rc = RECT { + left: 0, + top: 0, + right: 16, + bottom: 16, + }; + + let mut bitmap_info: BITMAPINFO = std::mem::zeroed(); + bitmap_info.bmiHeader.biSize = std::mem::size_of::() as _; + bitmap_info.bmiHeader.biWidth = rc.right; + bitmap_info.bmiHeader.biHeight = rc.bottom; + bitmap_info.bmiHeader.biPlanes = 1; + bitmap_info.bmiHeader.biBitCount = 32; + bitmap_info.bmiHeader.biCompression = BI_RGB as _; + + let h_dc_bitmap = GetDC(std::ptr::null_mut()); + + let hbitmap = CreateDIBSection( + h_dc_bitmap, + &bitmap_info, + DIB_RGB_COLORS, + 0 as _, + std::ptr::null_mut(), + 0, + ); + + ReleaseDC(std::ptr::null_mut(), h_dc_bitmap); + + let h_bitmap_old = SelectObject(hdc, hbitmap); + + DrawIconEx( + hdc, + 0, + 0, + self.inner.handle, + rc.right, + rc.bottom, + 0, + std::ptr::null_mut(), + DI_NORMAL, + ); + + SelectObject(hdc, h_bitmap_old); + DeleteDC(hdc); + + hbitmap + } + + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + let rgba_icon = RgbaIcon::from_rgba(rgba, width, height)?; + rgba_icon.into_windows_icon() + } + + fn from_handle(handle: HICON) -> Self { + Self { + #[allow(clippy::arc_with_non_send_sync)] + inner: Arc::new(RaiiIcon { handle }), + } + } + + pub(crate) fn from_path>( + path: P, + size: Option<(u32, u32)>, + ) -> Result { + // width / height of 0 along with LR_DEFAULTSIZE tells windows to load the default icon size + let (width, height) = size.unwrap_or((0, 0)); + + let wide_path = util::encode_wide(path.as_ref()); + + let handle = unsafe { + LoadImageW( + std::ptr::null_mut(), + wide_path.as_ptr(), + IMAGE_ICON, + width as i32, + height as i32, + LR_DEFAULTSIZE | LR_LOADFROMFILE, + ) + }; + if !handle.is_null() { + Ok(WinIcon::from_handle(handle as HICON)) + } else { + Err(BadIcon::OsError(io::Error::last_os_error())) + } + } + + pub(crate) fn from_resource( + resource_id: u16, + size: Option<(u32, u32)>, + ) -> Result { + // width / height of 0 along with LR_DEFAULTSIZE tells windows to load the default icon size + let (width, height) = size.unwrap_or((0, 0)); + let handle = unsafe { + LoadImageW( + util::get_instance_handle(), + resource_id as PCWSTR, + IMAGE_ICON, + width as i32, + height as i32, + LR_DEFAULTSIZE, + ) + }; + if !handle.is_null() { + Ok(WinIcon::from_handle(handle as HICON)) + } else { + Err(BadIcon::OsError(io::Error::last_os_error())) + } + } +} + +impl Drop for RaiiIcon { + fn drop(&mut self) { + unsafe { DestroyIcon(self.handle) }; + } +} + +impl fmt::Debug for WinIcon { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + (*self.inner).fmt(formatter) + } +} diff --git a/ports/muda/src/platform_impl/windows/mod.rs b/ports/muda/src/platform_impl/windows/mod.rs new file mode 100644 index 000000000000..9544deed410a --- /dev/null +++ b/ports/muda/src/platform_impl/windows/mod.rs @@ -0,0 +1,1399 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +mod accelerator; +mod dark_menu_bar; +mod icon; +mod util; + +use self::dark_menu_bar::{WM_UAHDRAWMENU, WM_UAHDRAWMENUITEM}; +pub(crate) use self::icon::WinIcon as PlatformIcon; + +use crate::{ + accelerator::KeyAccelerator, + dpi::Position, + icon::{Icon, NativeIcon}, + items::PredefinedMenuItemType, + util::{AddOp, Counter}, + AboutMetadata, IsMenuItem, MenuEvent, MenuId, MenuItemKind, MenuItemType, MenuTheme, +}; +use std::{ + cell::{RefCell, RefMut}, + collections::HashMap, + fmt::Debug, + rc::Rc, +}; +use util::{decode_wide, encode_wide, Accel}; +use windows_sys::Win32::{ + Foundation::{FALSE, LPARAM, LRESULT, POINT, WPARAM}, + Graphics::Gdi::{ClientToScreen, HBITMAP}, + UI::{ + Input::KeyboardAndMouse::{ + GetActiveWindow, SendInput, INPUT, INPUT_KEYBOARD, KEYEVENTF_KEYUP, VK_CONTROL, + }, + Shell::{DefSubclassProc, RemoveWindowSubclass, SetWindowSubclass}, + WindowsAndMessaging::{ + AppendMenuW, CreateAcceleratorTableW, CreateMenu, CreatePopupMenu, + DestroyAcceleratorTable, DestroyMenu, DrawMenuBar, EnableMenuItem, GetCursorPos, + GetMenu, GetMenuItemInfoW, InsertMenuW, PostMessageW, PostQuitMessage, RemoveMenu, + SendMessageW, SetForegroundWindow, SetMenu, SetMenuItemInfoW, ShowWindow, + TrackPopupMenu, HACCEL, HMENU, MENUITEMINFOW, MFS_CHECKED, MFS_DISABLED, MF_BYCOMMAND, + MF_BYPOSITION, MF_CHECKED, MF_DISABLED, MF_ENABLED, MF_GRAYED, MF_POPUP, MF_SEPARATOR, + MF_STRING, MF_UNCHECKED, MIIM_BITMAP, MIIM_STATE, MIIM_STRING, SW_HIDE, SW_MAXIMIZE, + SW_MINIMIZE, TPM_LEFTALIGN, TPM_RETURNCMD, WM_CLOSE, WM_COMMAND, WM_NCACTIVATE, + WM_NCPAINT, + }, + }, +}; + +type Hwnd = isize; + +static COUNTER: Counter = Counter::new_with_start(1000); + +macro_rules! inner_menu_child_and_flags { + ($item:ident) => {{ + let mut flags = 0; + let child = match $item.kind() { + MenuItemKind::Submenu(i) => { + flags |= MF_POPUP; + i.inner + } + MenuItemKind::MenuItem(i) => { + flags |= MF_STRING; + i.inner + } + + MenuItemKind::Predefined(i) => { + let child = i.inner; + let child_ = child.borrow(); + match child_.predefined_item_type.as_ref().unwrap() { + PredefinedMenuItemType::None => return Ok(()), + PredefinedMenuItemType::Separator => { + flags |= MF_SEPARATOR; + } + _ => { + flags |= MF_STRING; + } + } + drop(child_); + child + } + MenuItemKind::Check(i) => { + let child = i.inner; + flags |= MF_STRING; + if child.borrow().checked { + flags |= MF_CHECKED; + } + child + } + MenuItemKind::Icon(i) => { + flags |= MF_STRING; + i.inner + } + }; + + (child, flags) + }}; +} + +type AccelWrapper = (HACCEL, HashMap); + +#[derive(Debug)] +pub(crate) struct Menu { + id: MenuId, + internal_id: u32, + hmenu: HMENU, + hpopupmenu: HMENU, + hwnds: Rc>>, + haccel_store: Rc>, + children: Vec>>, +} + +impl Drop for Menu { + fn drop(&mut self) { + for (hwnd, _) in self.hwnds.borrow_mut().drain() { + unsafe { Self::remove_from_hwnd(hwnd) }; + } + + fn remove_from_children_stores(internal_id: u32, children: &Vec>>) { + for child in children { + let mut child_ = child.borrow_mut(); + child_.root_menu_haccel_stores.remove(&internal_id); + if child_.item_type == MenuItemType::Submenu { + remove_from_children_stores(internal_id, child_.children.as_ref().unwrap()); + } + } + } + + remove_from_children_stores(self.internal_id, &self.children); + + for child in &self.children { + let child_ = child.borrow(); + let id = if child_.item_type == MenuItemType::Submenu { + child_.hmenu as _ + } else { + child_.internal_id + }; + unsafe { + RemoveMenu(self.hpopupmenu, id, MF_BYCOMMAND); + RemoveMenu(self.hmenu, id, MF_BYCOMMAND); + } + } + + unsafe { + DestroyMenu(self.hmenu); + DestroyMenu(self.hpopupmenu); + } + } +} + +impl Menu { + pub fn new(id: Option) -> Self { + let internal_id = COUNTER.next(); + Self { + id: id.unwrap_or_else(|| MenuId::new(internal_id.to_string())), + internal_id, + hmenu: unsafe { CreateMenu() }, + hpopupmenu: unsafe { CreatePopupMenu() }, + haccel_store: Rc::new(RefCell::new((std::ptr::null_mut(), HashMap::new()))), + children: Vec::new(), + hwnds: Rc::new(RefCell::new(HashMap::new())), + } + } + + pub fn id(&self) -> &MenuId { + &self.id + } + + pub fn add_menu_item(&mut self, item: &dyn IsMenuItem, op: AddOp) -> crate::Result<()> { + let (child, mut flags) = inner_menu_child_and_flags!(item); + + { + child + .borrow_mut() + .root_menu_haccel_stores + .insert(self.internal_id, self.haccel_store.clone()); + } + + { + let child_ = child.borrow(); + if !child_.enabled { + flags |= MF_GRAYED; + } + + let mut text = child_.text.clone(); + + if let Some(accelerator) = &child_.accelerator { + let accel_str = accelerator.to_string(); + + text.push('\t'); + text.push_str(&accel_str); + + AccelAction::add( + &mut self.haccel_store.borrow_mut(), + child_.internal_id(), + accelerator, + )?; + } + + let id = child_.internal_id() as usize; + + let text = encode_wide(text); + unsafe { + match op { + AddOp::Append => { + AppendMenuW(self.hmenu, flags, id, text.as_ptr()); + AppendMenuW(self.hpopupmenu, flags, id, text.as_ptr()); + } + AddOp::Insert(position) => { + InsertMenuW( + self.hmenu, + position as _, + flags | MF_BYPOSITION, + id, + text.as_ptr(), + ); + InsertMenuW( + self.hpopupmenu, + position as _, + flags | MF_BYPOSITION, + id, + text.as_ptr(), + ); + } + } + } + } + + { + let child_ = child.borrow(); + let item_type = child_.item_type(); + + // Set icons for both regular menu items and submenus + if matches!(item_type, MenuItemType::Icon | MenuItemType::Submenu) { + let hbitmap = child_ + .icon + .as_ref() + .map(|i| unsafe { i.inner.to_hbitmap() }) + .unwrap_or(std::ptr::null_mut()); + + let info = create_icon_item_info(hbitmap); + + unsafe { + SetMenuItemInfoW(self.hmenu, child_.internal_id(), FALSE, &info); + SetMenuItemInfoW(self.hpopupmenu, child_.internal_id(), FALSE, &info); + }; + } + } + + // redraw the menu bar + for hwnd in self.hwnds.borrow().keys() { + unsafe { DrawMenuBar(*hwnd as _) }; + } + + { + let mut child_ = child.borrow_mut(); + child_ + .parents_hemnu + .push((self.hmenu, Some(self.hwnds.clone()))); + child_.parents_hemnu.push((self.hpopupmenu, None)); + } + + { + match op { + AddOp::Append => self.children.push(child), + AddOp::Insert(position) => self.children.insert(position, child), + } + } + + Ok(()) + } + + pub fn remove(&mut self, item: &dyn IsMenuItem) -> crate::Result<()> { + let id = item.child().borrow().internal_id(); + unsafe { + RemoveMenu(self.hmenu, id, MF_BYCOMMAND); + RemoveMenu(self.hpopupmenu, id, MF_BYCOMMAND); + + // redraw the menu bar + for hwnd in self.hwnds.borrow().keys() { + DrawMenuBar(*hwnd as _); + } + } + + let child = item.child(); + + { + let mut child = child.borrow_mut(); + let index = child + .parents_hemnu + .iter() + .position(|&(h, _)| h == self.hmenu) + .ok_or(crate::Error::NotAChildOfThisMenu)?; + child.parents_hemnu.remove(index); + let index = child + .parents_hemnu + .iter() + .position(|&(h, _)| h == self.hpopupmenu) + .ok_or(crate::Error::NotAChildOfThisMenu)?; + child.parents_hemnu.remove(index); + } + + let index = self + .children + .iter() + .position(|e| e.borrow().internal_id() == id) + .ok_or(crate::Error::NotAChildOfThisMenu)?; + self.children.remove(index); + + Ok(()) + } + + pub fn items(&self) -> Vec { + self.children + .iter() + .map(|c| c.borrow().kind(c.clone())) + .collect() + } + + fn find_by_id(&self, id: u32) -> Option>> { + find_by_id(id, &self.children) + } + + pub fn haccel(&self) -> isize { + self.haccel_store.borrow().0 as _ + } + + pub fn hpopupmenu(&self) -> isize { + self.hpopupmenu as _ + } + + pub unsafe fn init_for_hwnd_with_theme( + &mut self, + hwnd: isize, + theme: MenuTheme, + ) -> crate::Result<()> { + if self.hwnds.borrow().contains_key(&hwnd) { + return Err(crate::Error::AlreadyInitialized); + } + + self.hwnds.borrow_mut().insert(hwnd, theme); + + // SAFETY: HWND validity is upheld by caller + SetWindowSubclass( + hwnd as _, + Some(menu_subclass_proc), + MENU_SUBCLASS_ID, + dwrefdata_from_obj(self), + ); + SetMenu(hwnd as _, self.hmenu); + DrawMenuBar(hwnd as _); + + Ok(()) + } + + pub unsafe fn init_for_hwnd(&mut self, hwnd: isize) -> crate::Result<()> { + self.init_for_hwnd_with_theme(hwnd, MenuTheme::Auto) + } + + pub unsafe fn remove_for_hwnd(&mut self, hwnd: isize) -> crate::Result<()> { + self.hwnds + .borrow_mut() + .remove(&hwnd) + .ok_or(crate::Error::NotInitialized)?; + Self::remove_from_hwnd(hwnd); + Ok(()) + } + + unsafe fn remove_from_hwnd(hwnd: isize) { + let hwnd = hwnd as windows_sys::Win32::Foundation::HWND; + // SAFETY: HWND validity is upheld by caller + RemoveWindowSubclass(hwnd, Some(menu_subclass_proc), MENU_SUBCLASS_ID); + SetMenu(hwnd, std::ptr::null_mut()); + DrawMenuBar(hwnd); + } + + pub unsafe fn attach_menu_subclass_for_hwnd(&self, hwnd: isize) { + // SAFETY: HWND validity is upheld by caller + SetWindowSubclass( + hwnd as _, + Some(menu_subclass_proc), + MENU_SUBCLASS_ID, + dwrefdata_from_obj(self), + ); + } + + pub unsafe fn detach_menu_subclass_from_hwnd(&self, hwnd: isize) { + // SAFETY: HWND validity is upheld by caller + RemoveWindowSubclass(hwnd as _, Some(menu_subclass_proc), MENU_SUBCLASS_ID); + } + + pub unsafe fn hide_for_hwnd(&self, hwnd: isize) -> crate::Result<()> { + if !self.hwnds.borrow().contains_key(&hwnd) { + return Err(crate::Error::NotInitialized); + } + + // SAFETY: HWND validity is upheld by caller + SetMenu(hwnd as _, std::ptr::null_mut()); + DrawMenuBar(hwnd as _); + + Ok(()) + } + + pub unsafe fn show_for_hwnd(&self, hwnd: isize) -> crate::Result<()> { + if !self.hwnds.borrow().contains_key(&hwnd) { + return Err(crate::Error::NotInitialized); + } + + // SAFETY: HWND validity is upheld by caller + SetMenu(hwnd as _, self.hmenu); + DrawMenuBar(hwnd as _); + + Ok(()) + } + + pub unsafe fn is_visible_on_hwnd(&self, hwnd: isize) -> bool { + self.hwnds + .borrow() + .get(&hwnd) + // SAFETY: HWND validity is upheld by caller + .map(|_| !unsafe { GetMenu(hwnd as _) }.is_null()) + .unwrap_or(false) + } + + pub unsafe fn show_context_menu_for_hwnd( + &mut self, + hwnd: isize, + position: Option, + ) -> bool { + let rc = show_context_menu(hwnd as _, self.hpopupmenu, position); + if let Some(item) = rc.and_then(|rc| self.find_by_id(rc)) { + unsafe { + menu_selected(hwnd as _, &mut item.borrow_mut()); + } + return true; + } + false + } + + pub unsafe fn set_theme_for_hwnd(&self, hwnd: isize, theme: MenuTheme) -> crate::Result<()> { + if !self.hwnds.borrow().contains_key(&hwnd) { + return Err(crate::Error::NotInitialized); + } + + // SAFETY: HWND validity is upheld by caller + SendMessageW(hwnd as _, MENU_UPDATE_THEME, 0, theme as _); + + Ok(()) + } +} + +type ParentMenu = (HMENU, Option>>>); + +/// A generic child in a menu +#[derive(Debug)] +pub(crate) struct MenuChild { + // shared fields between submenus and menu items + item_type: MenuItemType, + text: String, + enabled: bool, + parents_hemnu: Vec, + root_menu_haccel_stores: HashMap>>, + + // menu item fields + internal_id: u32, + id: MenuId, + accelerator: Option, + + // predefined menu item fields + predefined_item_type: Option, + + // check menu item fields + checked: bool, + + // icon menu item fields + icon: Option, + + // submenu fields + hmenu: HMENU, + hpopupmenu: HMENU, + pub children: Option>>>, +} + +impl Drop for MenuChild { + fn drop(&mut self) { + if self.item_type == MenuItemType::Submenu { + unsafe { + DestroyMenu(self.hmenu); + DestroyMenu(self.hpopupmenu); + } + } + + if self.accelerator.is_some() { + for store in self.root_menu_haccel_stores.values() { + AccelAction::remove(&mut store.borrow_mut(), self.internal_id) + } + } + } +} + +/// Constructors +impl MenuChild { + pub fn new( + text: &str, + enabled: bool, + key_accelerator: Option, + id: Option, + ) -> Self { + let internal_id = COUNTER.next(); + Self { + item_type: MenuItemType::MenuItem, + text: text.to_string(), + enabled, + parents_hemnu: Vec::new(), + internal_id, + id: id.unwrap_or_else(|| MenuId::new(internal_id.to_string())), + accelerator: key_accelerator, + root_menu_haccel_stores: HashMap::new(), + predefined_item_type: None, + icon: None, + checked: false, + children: None, + hmenu: std::ptr::null_mut(), + hpopupmenu: std::ptr::null_mut(), + } + } + + pub fn new_submenu(text: &str, enabled: bool, id: Option) -> Self { + let internal_id = COUNTER.next(); + Self { + item_type: MenuItemType::Submenu, + text: text.to_string(), + enabled, + parents_hemnu: Vec::new(), + children: Some(Vec::new()), + hmenu: unsafe { CreateMenu() }, + internal_id, + id: id.unwrap_or_else(|| MenuId::new(internal_id.to_string())), + hpopupmenu: unsafe { CreatePopupMenu() }, + root_menu_haccel_stores: HashMap::new(), + predefined_item_type: None, + icon: None, + checked: false, + accelerator: None, + } + } + + pub fn new_predefined(item_type: PredefinedMenuItemType, text: Option) -> Self { + let internal_id = COUNTER.next(); + Self { + item_type: MenuItemType::Predefined, + text: text.unwrap_or_else(|| item_type.text().to_string()), + enabled: true, + parents_hemnu: Vec::new(), + internal_id, + id: MenuId::new(internal_id.to_string()), + accelerator: item_type.accelerator().map(Into::into), + predefined_item_type: Some(item_type), + root_menu_haccel_stores: HashMap::new(), + icon: None, + checked: false, + children: None, + hmenu: std::ptr::null_mut(), + hpopupmenu: std::ptr::null_mut(), + } + } + + pub fn new_check( + text: &str, + enabled: bool, + checked: bool, + key_accelerator: Option, + id: Option, + ) -> Self { + let internal_id = COUNTER.next(); + Self { + item_type: MenuItemType::Check, + text: text.to_string(), + enabled, + parents_hemnu: Vec::new(), + internal_id, + id: id.unwrap_or_else(|| MenuId::new(internal_id.to_string())), + accelerator: key_accelerator, + checked, + root_menu_haccel_stores: HashMap::new(), + predefined_item_type: None, + icon: None, + children: None, + hmenu: std::ptr::null_mut(), + hpopupmenu: std::ptr::null_mut(), + } + } + + pub fn new_icon( + text: &str, + enabled: bool, + icon: Option, + key_accelerator: Option, + id: Option, + ) -> Self { + let internal_id = COUNTER.next(); + Self { + item_type: MenuItemType::Icon, + text: text.to_string(), + enabled, + parents_hemnu: Vec::new(), + internal_id, + id: id.unwrap_or_else(|| MenuId::new(internal_id.to_string())), + accelerator: key_accelerator, + icon, + root_menu_haccel_stores: HashMap::new(), + predefined_item_type: None, + checked: false, + children: None, + hmenu: std::ptr::null_mut(), + hpopupmenu: std::ptr::null_mut(), + } + } + + pub fn new_native_icon( + text: &str, + enabled: bool, + _native_icon: Option, + key_accelerator: Option, + id: Option, + ) -> Self { + let internal_id = COUNTER.next(); + Self { + item_type: MenuItemType::Icon, + text: text.to_string(), + enabled, + parents_hemnu: Vec::new(), + internal_id, + id: id.unwrap_or_else(|| MenuId::new(internal_id.to_string())), + accelerator: key_accelerator, + root_menu_haccel_stores: HashMap::new(), + predefined_item_type: None, + icon: None, + checked: false, + children: None, + hmenu: std::ptr::null_mut(), + hpopupmenu: std::ptr::null_mut(), + } + } +} + +/// Shared methods +impl MenuChild { + pub fn item_type(&self) -> MenuItemType { + self.item_type + } + + pub fn id(&self) -> &MenuId { + &self.id + } + + pub fn internal_id(&self) -> u32 { + match self.item_type() { + MenuItemType::Submenu => self.hmenu as u32, + _ => self.internal_id, + } + } + + pub fn text(&self) -> String { + self.parents_hemnu + .first() + .map(|(hmenu, _)| { + let id = self.internal_id(); + let mut info: MENUITEMINFOW = unsafe { std::mem::zeroed() }; + info.cbSize = std::mem::size_of::() as _; + info.fMask = MIIM_STRING; + + unsafe { GetMenuItemInfoW(*hmenu, id, FALSE, &mut info) }; + + info.cch += 1; + let mut dw_type_data = Vec::with_capacity(info.cch as usize); + info.dwTypeData = dw_type_data.as_mut_ptr(); + + unsafe { GetMenuItemInfoW(*hmenu, id, FALSE, &mut info) }; + + let text = decode_wide(info.dwTypeData); + text.split('\t').next().unwrap().to_string() + }) + .unwrap_or_else(|| self.text.clone()) + } + + pub fn set_text(&mut self, text: &str) { + self.text = text.to_string(); + let mut text = if let Some(accelerator) = &self.accelerator { + encode_wide(format!("{text}\t{}", accelerator)) + } else { + encode_wide(text) + }; + + for (parent, menu_bars) in &self.parents_hemnu { + let mut info: MENUITEMINFOW = unsafe { std::mem::zeroed() }; + info.cbSize = std::mem::size_of::() as _; + info.fMask = MIIM_STRING; + info.dwTypeData = text.as_mut_ptr(); + + unsafe { SetMenuItemInfoW(*parent, self.internal_id(), FALSE, &info) }; + + if let Some(menu_bars) = menu_bars { + for hwnd in menu_bars.borrow().keys() { + unsafe { DrawMenuBar(*hwnd as _) }; + } + } + } + } + + pub fn is_enabled(&self) -> bool { + self.parents_hemnu + .first() + .map(|(hmenu, _)| { + let mut info: MENUITEMINFOW = unsafe { std::mem::zeroed() }; + info.cbSize = std::mem::size_of::() as _; + info.fMask = MIIM_STATE; + + unsafe { GetMenuItemInfoW(*hmenu, self.internal_id(), FALSE, &mut info) }; + + (info.fState & MFS_DISABLED) == 0 + }) + .unwrap_or(self.enabled) + } + + pub fn set_enabled(&mut self, enabled: bool) { + self.enabled = enabled; + for (parent, menu_bars) in &self.parents_hemnu { + let flag = if enabled { MF_ENABLED } else { MF_DISABLED }; + unsafe { EnableMenuItem(*parent, self.internal_id(), flag) }; + + if let Some(menu_bars) = menu_bars { + for hwnd in menu_bars.borrow().keys() { + unsafe { DrawMenuBar(*hwnd as _) }; + } + }; + } + } + + pub fn set_key_accelerator( + &mut self, + accelerator: Option, + ) -> crate::Result<()> { + self.accelerator = accelerator; + self.set_text(&self.text.clone()); + + for store in self.root_menu_haccel_stores.values() { + let mut store = store.borrow_mut(); + if let Some(accelerator) = &self.accelerator { + AccelAction::add(&mut store, self.internal_id, accelerator)? + } else { + AccelAction::remove(&mut store, self.internal_id) + } + } + + Ok(()) + } +} + +/// CheckMenuItem methods +impl MenuChild { + pub fn is_checked(&self) -> bool { + self.parents_hemnu + .first() + .map(|(hmenu, _)| { + let mut info: MENUITEMINFOW = unsafe { std::mem::zeroed() }; + info.cbSize = std::mem::size_of::() as _; + info.fMask = MIIM_STATE; + + unsafe { GetMenuItemInfoW(*hmenu, self.internal_id(), FALSE, &mut info) }; + + (info.fState & MFS_CHECKED) != 0 + }) + .unwrap_or(self.enabled) + } + + pub fn set_checked(&mut self, checked: bool) { + use windows_sys::Win32::UI::WindowsAndMessaging; + + self.checked = checked; + for (parent, menu_bars) in &self.parents_hemnu { + let flag = if checked { MF_CHECKED } else { MF_UNCHECKED }; + unsafe { WindowsAndMessaging::CheckMenuItem(*parent, self.internal_id(), flag) }; + + if let Some(menu_bars) = menu_bars { + for hwnd in menu_bars.borrow().keys() { + unsafe { DrawMenuBar(*hwnd as _) }; + } + }; + } + } +} + +/// IconMenuItem methods +impl MenuChild { + pub fn set_icon(&mut self, icon: Option) { + self.icon.clone_from(&icon); + + let hbitmap = icon + .map(|i| unsafe { i.inner.to_hbitmap() }) + .unwrap_or(std::ptr::null_mut()); + + let info = create_icon_item_info(hbitmap); + + for (parent, menu_bars) in &self.parents_hemnu { + unsafe { SetMenuItemInfoW(*parent, self.internal_id(), FALSE, &info) }; + + if let Some(menu_bars) = menu_bars { + for hwnd in menu_bars.borrow().keys() { + unsafe { DrawMenuBar(*hwnd as _) }; + } + }; + } + } +} + +/// Submenu methods +impl MenuChild { + pub fn hpopupmenu(&self) -> isize { + self.hpopupmenu as _ + } + + pub fn add_menu_item(&mut self, item: &dyn IsMenuItem, op: AddOp) -> crate::Result<()> { + let (child, mut flags) = inner_menu_child_and_flags!(item); + + { + child + .borrow_mut() + .root_menu_haccel_stores + .extend(self.root_menu_haccel_stores.clone()); + } + + { + let child_ = child.borrow(); + if !child_.enabled { + flags |= MF_GRAYED; + } + + let mut text = child_.text.clone(); + + if let Some(accelerator) = &child_.accelerator { + let accel_str = accelerator.to_string(); + + text.push('\t'); + text.push_str(&accel_str); + + for root_menu in self.root_menu_haccel_stores.values() { + let mut haccel = root_menu.borrow_mut(); + AccelAction::add(&mut haccel, child_.internal_id(), accelerator)?; + } + } + + let id = child_.internal_id() as usize; + let text = encode_wide(text); + unsafe { + match op { + AddOp::Append => { + AppendMenuW(self.hmenu, flags, id, text.as_ptr()); + AppendMenuW(self.hpopupmenu, flags, id, text.as_ptr()); + } + AddOp::Insert(position) => { + InsertMenuW( + self.hmenu, + position as _, + flags | MF_BYPOSITION, + id, + text.as_ptr(), + ); + InsertMenuW( + self.hpopupmenu, + position as _, + flags | MF_BYPOSITION, + id, + text.as_ptr(), + ); + } + } + } + } + + { + let child_ = child.borrow(); + let item_type = child_.item_type(); + + if matches!(item_type, MenuItemType::Icon | MenuItemType::Submenu) { + let hbitmap = child_ + .icon + .as_ref() + .map(|i| unsafe { i.inner.to_hbitmap() }) + .unwrap_or(std::ptr::null_mut()); + let info = create_icon_item_info(hbitmap); + unsafe { + SetMenuItemInfoW(self.hmenu, child_.internal_id(), FALSE, &info); + SetMenuItemInfoW(self.hpopupmenu, child_.internal_id(), FALSE, &info); + }; + } + } + + { + let mut child_ = child.borrow_mut(); + child_.parents_hemnu.push((self.hmenu, None)); + child_.parents_hemnu.push((self.hpopupmenu, None)); + } + + { + let children = self.children.as_mut().unwrap(); + match op { + AddOp::Append => children.push(child), + AddOp::Insert(position) => children.insert(position, child), + } + } + + Ok(()) + } + + pub fn remove(&mut self, item: &dyn IsMenuItem) -> crate::Result<()> { + let id = item.child().borrow().internal_id(); + unsafe { + RemoveMenu(self.hmenu, id, MF_BYCOMMAND); + RemoveMenu(self.hpopupmenu, id, MF_BYCOMMAND); + } + + let child = item.child(); + + { + let mut child = child.borrow_mut(); + let index = child + .parents_hemnu + .iter() + .position(|&(h, _)| h == self.hmenu) + .ok_or(crate::Error::NotAChildOfThisMenu)?; + child.parents_hemnu.remove(index); + let index = child + .parents_hemnu + .iter() + .position(|&(h, _)| h == self.hpopupmenu) + .ok_or(crate::Error::NotAChildOfThisMenu)?; + child.parents_hemnu.remove(index); + } + + let children = self.children.as_mut().unwrap(); + let index = children + .iter() + .position(|e| e.borrow().internal_id() == id) + .ok_or(crate::Error::NotAChildOfThisMenu)?; + children.remove(index); + + Ok(()) + } + + pub fn items(&self) -> Vec { + self.children + .as_ref() + .unwrap() + .iter() + .map(|c| c.borrow().kind(c.clone())) + .collect() + } + + pub unsafe fn show_context_menu_for_hwnd( + &mut self, + hwnd: isize, + position: Option, + ) -> bool { + let rc = show_context_menu(hwnd as _, self.hpopupmenu, position); + if let Some(item) = rc.and_then(|rc| self.find_by_id(rc)) { + unsafe { + menu_selected(hwnd as _, &mut item.borrow_mut()); + } + return true; + } + false + } + + pub unsafe fn attach_menu_subclass_for_hwnd(&self, hwnd: isize) { + // SAFETY: HWND validity is upheld by caller + SetWindowSubclass( + hwnd as _, + Some(menu_subclass_proc), + SUBMENU_SUBCLASS_ID, + dwrefdata_from_obj(self), + ); + } + + pub unsafe fn detach_menu_subclass_from_hwnd(&self, hwnd: isize) { + // SAFETY: HWND validity is upheld by caller + RemoveWindowSubclass(hwnd as _, Some(menu_subclass_proc), SUBMENU_SUBCLASS_ID); + } +} + +/// Internal Utilities +impl MenuChild { + fn find_by_id(&self, id: u32) -> Option>> { + let children = self.children.as_ref().unwrap(); + find_by_id(id, children) + } +} + +fn find_by_id(id: u32, children: &Vec>>) -> Option>> { + for i in children { + let item = i.borrow(); + if item.internal_id() == id { + return Some(i.clone()); + } + + if item.item_type() == MenuItemType::Submenu { + if let Some(child) = item.find_by_id(id) { + return Some(child); + } + } + } + None +} + +// SAFETY: +// HWND validity is upheld by caller +unsafe fn show_context_menu( + hwnd: windows_sys::Win32::Foundation::HWND, + hmenu: HMENU, + position: Option, +) -> Option { + let result = unsafe { + let pt = if let Some(pos) = position { + let dpi = util::hwnd_dpi(hwnd); + let scale_factor = util::dpi_to_scale_factor(dpi); + let pos = pos.to_physical::(scale_factor); + let mut pt = POINT { + x: pos.x as _, + y: pos.y as _, + }; + ClientToScreen(hwnd, &mut pt); + pt + } else { + let mut pt = POINT { x: 0, y: 0 }; + GetCursorPos(&mut pt); + pt + }; + SetForegroundWindow(hwnd); + TrackPopupMenu( + hmenu, + TPM_LEFTALIGN | TPM_RETURNCMD, + pt.x, + pt.y, + 0, + hwnd, + std::ptr::null(), + ) + }; + (result > 0).then_some(result.try_into().ok()).flatten() +} + +struct AccelAction; + +impl AccelAction { + fn add( + haccel_store: &mut RefMut, + id: u32, + accelerator: &KeyAccelerator, + ) -> crate::Result<()> { + let accel = accelerator.to_accel(id as _)?; + haccel_store.1.insert(id, Accel(accel)); + Self::update_store(haccel_store); + Ok(()) + } + + fn remove(haccel_store: &mut RefMut, id: u32) { + haccel_store.1.remove(&id); + Self::update_store(haccel_store) + } + + fn update_store(haccel_store: &mut RefMut) { + unsafe { + DestroyAcceleratorTable(haccel_store.0); + let len = haccel_store.1.len(); + let accels = haccel_store.1.values().map(|i| i.0).collect::>(); + haccel_store.0 = CreateAcceleratorTableW(accels.as_ptr(), len as _); + } + } +} + +fn create_icon_item_info(hbitmap: HBITMAP) -> MENUITEMINFOW { + let mut info: MENUITEMINFOW = unsafe { std::mem::zeroed() }; + info.cbSize = std::mem::size_of::() as _; + info.fMask = MIIM_BITMAP; + info.hbmpItem = hbitmap; + info +} + +fn dwrefdata_from_obj(obj: &T) -> usize { + (obj as *const T) as usize +} + +unsafe fn obj_from_dwrefdata(dwrefdata: usize) -> &'static mut T { + unsafe { (dwrefdata as *mut T).as_mut().unwrap() } +} + +const MENU_SUBCLASS_ID: usize = 200; +const MENU_UPDATE_THEME: u32 = 201; +const SUBMENU_SUBCLASS_ID: usize = 202; + +unsafe extern "system" fn menu_subclass_proc( + hwnd: windows_sys::Win32::Foundation::HWND, + msg: u32, + wparam: WPARAM, + lparam: LPARAM, + uidsubclass: usize, + dwrefdata: usize, +) -> LRESULT { + match msg { + MENU_UPDATE_THEME if uidsubclass == MENU_SUBCLASS_ID => { + let menu = obj_from_dwrefdata::(dwrefdata); + let theme: MenuTheme = std::mem::transmute(lparam); + menu.hwnds.borrow_mut().insert(hwnd as _, theme); + if GetActiveWindow() == hwnd { + PostMessageW(hwnd, WM_NCACTIVATE, 0, 0); + PostMessageW(hwnd, WM_NCACTIVATE, true.into(), 0); + } else { + PostMessageW(hwnd, WM_NCACTIVATE, true.into(), 0); + PostMessageW(hwnd, WM_NCACTIVATE, 0, 0); + } + 0 + } + + WM_COMMAND => { + let id = util::LOWORD(wparam as _) as u32; + + let item = match uidsubclass { + MENU_SUBCLASS_ID => { + let menu = obj_from_dwrefdata::(dwrefdata); + menu.find_by_id(id) + } + SUBMENU_SUBCLASS_ID => { + let menu = obj_from_dwrefdata::(dwrefdata); + menu.find_by_id(id) + } + _ => unreachable!(), + }; + + if let Some(item) = item { + menu_selected(hwnd, &mut item.borrow_mut()); + 0 + } else { + DefSubclassProc(hwnd as _, msg, wparam, lparam) + } + } + + WM_UAHDRAWMENUITEM | WM_UAHDRAWMENU if uidsubclass == MENU_SUBCLASS_ID => { + let menu = obj_from_dwrefdata::(dwrefdata); + let theme = menu + .hwnds + .borrow() + .get(&(hwnd as _)) + .copied() + .unwrap_or(MenuTheme::Auto); + if theme.should_use_dark(hwnd as _) { + dark_menu_bar::draw(hwnd as _, msg, wparam, lparam); + 0 + } else { + DefSubclassProc(hwnd as _, msg, wparam, lparam) + } + } + WM_NCACTIVATE | WM_NCPAINT => { + // DefSubclassProc needs to be called before calling the + // custom dark menu redraw + let res = DefSubclassProc(hwnd as _, msg, wparam, lparam); + + let menu = obj_from_dwrefdata::(dwrefdata); + let theme = menu + .hwnds + .borrow() + .get(&(hwnd as _)) + .copied() + .unwrap_or(MenuTheme::Auto); + if theme.should_use_dark(hwnd as _) { + dark_menu_bar::draw(hwnd as _, msg, wparam, lparam); + } + + res + } + _ => DefSubclassProc(hwnd as _, msg, wparam, lparam), + } +} + +unsafe fn menu_selected(hwnd: windows_sys::Win32::Foundation::HWND, item: &mut MenuChild) { + let (mut dispatch, mut menu_id) = (true, None); + + { + if item.item_type() == MenuItemType::Predefined { + dispatch = false; + } else { + menu_id.replace(item.id.clone()); + } + + match item.item_type() { + MenuItemType::Check => { + let checked = !item.checked; + item.set_checked(checked); + } + MenuItemType::Predefined => { + if let Some(predefined_item_type) = &item.predefined_item_type { + match predefined_item_type { + PredefinedMenuItemType::Copy => execute_edit_command(EditCommand::Copy), + PredefinedMenuItemType::Cut => execute_edit_command(EditCommand::Cut), + PredefinedMenuItemType::Paste => execute_edit_command(EditCommand::Paste), + PredefinedMenuItemType::SelectAll => { + execute_edit_command(EditCommand::SelectAll) + } + PredefinedMenuItemType::Undo => execute_edit_command(EditCommand::Undo), + PredefinedMenuItemType::Redo => execute_edit_command(EditCommand::Redo), + PredefinedMenuItemType::Separator => {} + PredefinedMenuItemType::Minimize => { + ShowWindow(hwnd, SW_MINIMIZE); + } + PredefinedMenuItemType::Maximize => { + ShowWindow(hwnd, SW_MAXIMIZE); + } + PredefinedMenuItemType::Hide => { + ShowWindow(hwnd, SW_HIDE); + } + PredefinedMenuItemType::CloseWindow => { + SendMessageW(hwnd, WM_CLOSE, 0, 0); + } + PredefinedMenuItemType::Quit => { + PostQuitMessage(0); + } + PredefinedMenuItemType::About(Some(ref metadata)) => { + show_about_dialog(hwnd as _, metadata) + } + + _ => {} + } + } + } + _ => {} + } + } + + if dispatch { + MenuEvent::send(MenuEvent { + id: menu_id.unwrap(), + }); + } +} + +impl MenuTheme { + fn should_use_dark(&self, hwnd: isize) -> bool { + match self { + MenuTheme::Dark => true, + MenuTheme::Auto if dark_menu_bar::should_use_dark_mode(hwnd as _) => true, + _ => false, + } + } +} + +enum EditCommand { + Copy, + Cut, + Paste, + SelectAll, + Undo, + Redo, +} + +fn execute_edit_command(command: EditCommand) { + let key = match command { + EditCommand::Copy => 0x43, // c + EditCommand::Cut => 0x58, // x + EditCommand::Paste => 0x56, // v + EditCommand::SelectAll => 0x41, // a + EditCommand::Undo => 0x5A, // z + EditCommand::Redo => 0x59, // y + }; + + unsafe { + let mut inputs: [INPUT; 4] = std::mem::zeroed(); + inputs[0].r#type = INPUT_KEYBOARD; + inputs[0].Anonymous.ki.wVk = VK_CONTROL; + inputs[0].Anonymous.ki.dwFlags = 0; + + inputs[1].r#type = INPUT_KEYBOARD; + inputs[1].Anonymous.ki.wVk = key; + inputs[1].Anonymous.ki.dwFlags = 0; + + inputs[2].r#type = INPUT_KEYBOARD; + inputs[2].Anonymous.ki.wVk = key; + inputs[2].Anonymous.ki.dwFlags = KEYEVENTF_KEYUP; + + inputs[3].r#type = INPUT_KEYBOARD; + inputs[3].Anonymous.ki.wVk = VK_CONTROL; + inputs[3].Anonymous.ki.dwFlags = KEYEVENTF_KEYUP; + + SendInput(4, &inputs as *const _, std::mem::size_of::() as _); + } +} + +fn show_about_dialog(hwnd: Hwnd, metadata: &AboutMetadata) { + use std::fmt::Write; + + let mut message = String::new(); + if let Some(name) = &metadata.name { + let _ = writeln!(&mut message, "Name: {}", name); + } + if let Some(version) = &metadata.full_version() { + let _ = writeln!(&mut message, "Version: {}", version); + } + if let Some(authors) = &metadata.authors { + let _ = writeln!(&mut message, "Authors: {}", authors.join(", ")); + } + if let Some(license) = &metadata.license { + let _ = writeln!(&mut message, "License: {}", license); + } + match (&metadata.website_label, &metadata.website) { + (Some(label), None) => { + let _ = writeln!(&mut message, "Website: {}", label); + } + (None, Some(url)) => { + let _ = writeln!(&mut message, "Website: {}", url); + } + (Some(label), Some(url)) => { + let _ = writeln!(&mut message, "Website: {} {}", label, url); + } + _ => {} + } + if let Some(comments) = &metadata.comments { + let _ = writeln!(&mut message, "\n{}", comments); + } + if let Some(copyright) = &metadata.copyright { + let _ = writeln!(&mut message, "\n{}", copyright); + } + + let message = encode_wide(message); + let title = encode_wide(format!( + "About {}", + metadata.name.as_deref().unwrap_or_default() + )); + + #[cfg(not(feature = "common-controls-v6"))] + std::thread::spawn(move || unsafe { + use windows_sys::Win32::UI::WindowsAndMessaging::{MessageBoxW, MB_ICONINFORMATION}; + MessageBoxW( + hwnd as _, + message.as_ptr(), + title.as_ptr(), + MB_ICONINFORMATION, + ); + }); + + #[cfg(feature = "common-controls-v6")] + { + use windows_sys::Win32::UI::Controls::{ + TaskDialogIndirect, TASKDIALOGCONFIG, TASKDIALOGCONFIG_0, TASKDIALOGCONFIG_1, + TDCBF_OK_BUTTON, TDF_ALLOW_DIALOG_CANCELLATION, TD_INFORMATION_ICON, + }; + + std::thread::spawn(move || unsafe { + let task_dialog_config = TASKDIALOGCONFIG { + cbSize: core::mem::size_of::() as u32, + hwndParent: hwnd as _, + dwFlags: TDF_ALLOW_DIALOG_CANCELLATION, + pszWindowTitle: title.as_ptr(), + pszContent: message.as_ptr(), + Anonymous1: TASKDIALOGCONFIG_0 { + pszMainIcon: TD_INFORMATION_ICON, + }, + Anonymous2: TASKDIALOGCONFIG_1 { + pszFooterIcon: std::ptr::null(), + }, + dwCommonButtons: TDCBF_OK_BUTTON, + pButtons: std::ptr::null(), + cButtons: 0, + pRadioButtons: std::ptr::null(), + cRadioButtons: 0, + cxWidth: 0, + hInstance: std::ptr::null_mut(), + pfCallback: None, + lpCallbackData: 0, + nDefaultButton: 0, + nDefaultRadioButton: 0, + pszCollapsedControlText: std::ptr::null(), + pszExpandedControlText: std::ptr::null(), + pszExpandedInformation: std::ptr::null(), + pszMainInstruction: std::ptr::null(), + pszVerificationText: std::ptr::null(), + pszFooter: std::ptr::null(), + }; + + let mut pf_verification_flag_checked = 0; + let mut pn_button = 0; + let mut pn_radio_button = 0; + + TaskDialogIndirect( + &task_dialog_config, + &mut pn_button, + &mut pn_radio_button, + &mut pf_verification_flag_checked, + ) + }); + } +} diff --git a/ports/muda/src/platform_impl/windows/util.rs b/ports/muda/src/platform_impl/windows/util.rs new file mode 100644 index 000000000000..08d5a7b35520 --- /dev/null +++ b/ports/muda/src/platform_impl/windows/util.rs @@ -0,0 +1,169 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::ops::{Deref, DerefMut}; + +use once_cell::sync::Lazy; +use windows_sys::{ + core::HRESULT, + Win32::{ + Foundation::{FARPROC, HWND, S_OK}, + Graphics::Gdi::{ + GetDC, GetDeviceCaps, MonitorFromWindow, HMONITOR, LOGPIXELSX, MONITOR_DEFAULTTONEAREST, + }, + System::LibraryLoader::{GetProcAddress, LoadLibraryW}, + UI::{ + HiDpi::{MDT_EFFECTIVE_DPI, MONITOR_DPI_TYPE}, + WindowsAndMessaging::{IsProcessDPIAware, ACCEL}, + }, + }, +}; + +pub fn encode_wide>(string: S) -> Vec { + std::os::windows::prelude::OsStrExt::encode_wide(string.as_ref()) + .chain(std::iter::once(0)) + .collect() +} + +#[allow(non_snake_case)] +pub fn LOWORD(dword: u32) -> u16 { + (dword & 0xFFFF) as u16 +} + +pub fn decode_wide(w_str: *mut u16) -> String { + let len = unsafe { windows_sys::Win32::Globalization::lstrlenW(w_str) } as usize; + let w_str_slice = unsafe { std::slice::from_raw_parts(w_str, len) }; + String::from_utf16_lossy(w_str_slice) +} + +/// ACCEL wrapper to implement Debug +#[derive(Clone)] +#[repr(transparent)] +pub struct Accel(pub ACCEL); + +impl std::fmt::Debug for Accel { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ACCEL") + .field("key", &self.0.key) + .field("cmd", &self.0.cmd) + .field("fVirt", &self.0.fVirt) + .finish() + } +} + +impl Deref for Accel { + type Target = ACCEL; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Accel { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +// taken from winit's code base +// https://github.com/rust-windowing/winit/blob/ee88e38f13fbc86a7aafae1d17ad3cd4a1e761df/src/platform_impl/windows/util.rs#L138 +pub fn get_instance_handle() -> windows_sys::Win32::Foundation::HMODULE { + // Gets the instance handle by taking the address of the + // pseudo-variable created by the microsoft linker: + // https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483 + + // This is preferred over GetModuleHandle(NULL) because it also works in DLLs: + // https://stackoverflow.com/questions/21718027/getmodulehandlenull-vs-hinstance + + extern "C" { + static __ImageBase: windows_sys::Win32::System::SystemServices::IMAGE_DOS_HEADER; + } + + unsafe { &__ImageBase as *const _ as _ } +} + +fn get_function_impl(library: &str, function: &str) -> FARPROC { + let library = encode_wide(library); + assert_eq!(function.chars().last(), Some('\0')); + + // Library names we will use are ASCII so we can use the A version to avoid string conversion. + let module = unsafe { LoadLibraryW(library.as_ptr()) }; + if module.is_null() { + return None; + } + + unsafe { GetProcAddress(module, function.as_ptr()) } +} + +macro_rules! get_function { + ($lib:expr, $func:ident) => { + crate::platform_impl::platform::util::get_function_impl( + $lib, + concat!(stringify!($func), '\0'), + ) + .map(|f| unsafe { std::mem::transmute::<_, $func>(f) }) + }; +} + +pub type GetDpiForWindow = unsafe extern "system" fn(hwnd: HWND) -> u32; +pub type GetDpiForMonitor = unsafe extern "system" fn( + hmonitor: HMONITOR, + dpi_type: MONITOR_DPI_TYPE, + dpi_x: *mut u32, + dpi_y: *mut u32, +) -> HRESULT; + +static GET_DPI_FOR_WINDOW: Lazy> = + Lazy::new(|| get_function!("user32.dll", GetDpiForWindow)); +static GET_DPI_FOR_MONITOR: Lazy> = + Lazy::new(|| get_function!("shcore.dll", GetDpiForMonitor)); + +pub const BASE_DPI: u32 = 96; +pub fn dpi_to_scale_factor(dpi: u32) -> f64 { + dpi as f64 / BASE_DPI as f64 +} + +#[allow(non_snake_case)] +pub unsafe fn hwnd_dpi(hwnd: HWND) -> u32 { + if let Some(GetDpiForWindow) = *GET_DPI_FOR_WINDOW { + // We are on Windows 10 Anniversary Update (1607) or later. + match GetDpiForWindow(hwnd) { + 0 => BASE_DPI, // 0 is returned if hwnd is invalid + #[allow(clippy::unnecessary_cast)] + dpi => dpi as u32, + } + } else if let Some(GetDpiForMonitor) = *GET_DPI_FOR_MONITOR { + // We are on Windows 8.1 or later. + let monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); + if monitor.is_null() { + return BASE_DPI; + } + + let mut dpi_x = 0; + let mut dpi_y = 0; + #[allow(clippy::unnecessary_cast)] + if GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &mut dpi_x, &mut dpi_y) == S_OK { + dpi_x as u32 + } else { + BASE_DPI + } + } else { + let hdc = GetDC(hwnd); + if hdc.is_null() { + return BASE_DPI; + } + + // We are on Vista or later. + if IsProcessDPIAware() == 1 { + // If the process is DPI aware, then scaling must be handled by the application using + // this DPI value. + GetDeviceCaps(hdc, LOGPIXELSX as _) as u32 + } else { + // If the process is DPI unaware, then scaling is performed by the OS; we thus return + // 96 (scale factor 1.0) to prevent the window from being re-scaled by both the + // application and the WM. + BASE_DPI + } + } +} diff --git a/ports/muda/src/util.rs b/ports/muda/src/util.rs new file mode 100644 index 000000000000..fd5bb100d350 --- /dev/null +++ b/ports/muda/src/util.rs @@ -0,0 +1,29 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::sync::atomic::{AtomicU32, Ordering}; + +#[derive(Clone, Copy, Debug)] +pub enum AddOp { + Append, + Insert(usize), +} + +pub struct Counter(AtomicU32); + +impl Counter { + #[allow(unused)] + pub const fn new() -> Self { + Self(AtomicU32::new(1)) + } + + #[allow(unused)] + pub const fn new_with_start(start: u32) -> Self { + Self(AtomicU32::new(start)) + } + + pub fn next(&self) -> u32 { + self.0.fetch_add(1, Ordering::Relaxed) + } +} diff --git a/ports/tray-icon/.changes/config.json b/ports/tray-icon/.changes/config.json new file mode 100644 index 000000000000..d768478def87 --- /dev/null +++ b/ports/tray-icon/.changes/config.json @@ -0,0 +1,52 @@ +{ + "gitSiteUrl": "https://www.github.com/tauri-apps/tray-icon", + "timeout": 3600000, + "pkgManagers": { + "rust": { + "version": true, + "getPublishedVersion": "cargo search ${ pkg.pkg } --limit 1 | sed -nE 's/^[^\"]*\"//; s/\".*//1p' -", + "prepublish": [ + "sudo apt-get update", + "sudo apt-get install -y libgtk-3-dev libxdo-dev libayatana-appindicator3-dev" + ], + "publish": [ + { + "command": "cargo package --no-verify", + "dryRunCommand": true + }, + { + "command": "echo '
\n

Cargo Publish

\n\n```'", + "dryRunCommand": true, + "pipe": true + }, + { + "command": "cargo publish", + "dryRunCommand": "cargo publish --dry-run", + "pipe": true + }, + { + "command": "echo '```\n\n
\n'", + "dryRunCommand": true, + "pipe": true + } + ], + "postpublish": [ + "git tag ${ pkg.pkg }-v${ pkgFile.versionMajor } -f", + "git tag ${ pkg.pkg }-v${ pkgFile.versionMajor }.${ pkgFile.versionMinor } -f", + "git push --tags -f" + ] + } + }, + "packages": { + "tray-icon": { + "path": ".", + "manager": "rust", + "assets": [ + { + "path": "${ pkg.path }/target/package/tray-icon-${ pkgFile.version }.crate", + "name": "${ pkg.pkg }-${ pkgFile.version }.crate" + } + ] + } + } +} \ No newline at end of file diff --git a/ports/tray-icon/.changes/nis-hidden.md b/ports/tray-icon/.changes/nis-hidden.md new file mode 100644 index 000000000000..cfb8d1e77590 --- /dev/null +++ b/ports/tray-icon/.changes/nis-hidden.md @@ -0,0 +1,5 @@ +--- +tray-icon: patch +--- + +Migrated to use `NIS_HIDDEN` to change visible states on Windows diff --git a/ports/tray-icon/.changes/perf-macos-avoid-allocating.md b/ports/tray-icon/.changes/perf-macos-avoid-allocating.md new file mode 100644 index 000000000000..4b5f0a236b47 --- /dev/null +++ b/ports/tray-icon/.changes/perf-macos-avoid-allocating.md @@ -0,0 +1,5 @@ +--- +"tray-icon": patch +--- + +Avoid unnecessary cloning when applying tray icons, titles, and tooltips on macOS. diff --git a/ports/tray-icon/.changes/readme.md b/ports/tray-icon/.changes/readme.md new file mode 100644 index 000000000000..a03e6b1d5bf7 --- /dev/null +++ b/ports/tray-icon/.changes/readme.md @@ -0,0 +1,29 @@ +# Changes + +##### via https://github.com/jbolda/covector + +As you create PRs and make changes that require a version bump, please add a new markdown file in this folder. You do not note the version _number_, but rather the type of bump that you expect: major, minor, or patch. The filename is not important, as long as it is a `.md`, but we recommend it represents the overall change for our sanity. + +When you select the version bump required, you do _not_ need to consider dependencies. Only note the package with the actual change, and any packages that depend on that package will be bumped automatically in the process. + +Use the following format: + +```md +--- +"tray-icon": patch +--- + +Change summary goes here +``` + +Summaries do not have a specific character limit, but are text only. These summaries are used within the (future implementation of) changelogs. They will give context to the change and also point back to the original PR if more details and context are needed. + +Changes will be designated as a `major`, `minor` or `patch` as further described in [semver](https://semver.org/). + +Given a version number MAJOR.MINOR.PATCH, increment the: + +- MAJOR version when you make incompatible API changes, +- MINOR version when you add functionality in a backwards compatible manner, and +- PATCH version when you make backwards compatible bug fixes. + +Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format, but will be discussed prior to usage (as extra steps will be necessary in consideration of merging and publishing). diff --git a/ports/tray-icon/.changes/set-cb-size.md b/ports/tray-icon/.changes/set-cb-size.md new file mode 100644 index 000000000000..125384c3f4c2 --- /dev/null +++ b/ports/tray-icon/.changes/set-cb-size.md @@ -0,0 +1,5 @@ +--- +tray-icon: patch +--- + +Set `NOTIFYICONDATAW.cbSize` to `size_of::()`, this increased the max tooltip length from 64 to 128 characters. diff --git a/ports/tray-icon/.github/workflows/audit.yml b/ports/tray-icon/.github/workflows/audit.yml new file mode 100644 index 000000000000..fd10e86e6e59 --- /dev/null +++ b/ports/tray-icon/.github/workflows/audit.yml @@ -0,0 +1,33 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: audit + +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * *' + push: + branches: + - dev + paths: + - 'Cargo.lock' + - 'Cargo.toml' + pull_request: + paths: + - 'Cargo.lock' + - 'Cargo.toml' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rustsec/audit-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/ports/tray-icon/.github/workflows/clippy-fmt.yml b/ports/tray-icon/.github/workflows/clippy-fmt.yml new file mode 100644 index 000000000000..8065661ecf31 --- /dev/null +++ b/ports/tray-icon/.github/workflows/clippy-fmt.yml @@ -0,0 +1,48 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: clippy & fmt + +on: + push: + branches: + - dev + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + clippy: + strategy: + fail-fast: false + matrix: + platform: [ubuntu-latest, macos-latest, windows-latest] + + runs-on: ${{ matrix.platform }} + + steps: + - uses: actions/checkout@v4 + - name: install system deps + if: matrix.platform == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev libxdo-dev libayatana-appindicator3-dev + + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + + - run: cargo clippy --all-targets --all-features -- -D warnings + + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + + - run: cargo fmt --all -- --check diff --git a/ports/tray-icon/.github/workflows/covector-status.yml b/ports/tray-icon/.github/workflows/covector-status.yml new file mode 100644 index 000000000000..b33f108a93e5 --- /dev/null +++ b/ports/tray-icon/.github/workflows/covector-status.yml @@ -0,0 +1,20 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: covector status +on: [pull_request] + +jobs: + covector: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: covector status + uses: jbolda/covector/packages/action@covector-v0 + id: covector + with: + command: "status" + token: ${{ secrets.GITHUB_TOKEN }} + comment: true diff --git a/ports/tray-icon/.github/workflows/covector-version-or-publish.yml b/ports/tray-icon/.github/workflows/covector-version-or-publish.yml new file mode 100644 index 000000000000..d85dca0d3637 --- /dev/null +++ b/ports/tray-icon/.github/workflows/covector-version-or-publish.yml @@ -0,0 +1,58 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: covector version or publish + +on: + push: + branches: + - dev + +jobs: + version-or-publish: + runs-on: ubuntu-latest + timeout-minutes: 65 + outputs: + change: ${{ steps.covector.outputs.change }} + commandRan: ${{ steps.covector.outputs.commandRan }} + successfulPublish: ${{ steps.covector.outputs.successfulPublish }} + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: cargo login + run: cargo login ${{ secrets.ORG_CRATES_IO_TOKEN }} + + - name: git config + run: | + git config --global user.name "${{ github.event.pusher.name }}" + git config --global user.email "${{ github.event.pusher.email }}" + + - name: covector version or publish (publish when no change files present) + uses: jbolda/covector/packages/action@covector-v0 + id: covector + env: + NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }} + with: + token: ${{ secrets.GITHUB_TOKEN }} + command: 'version-or-publish' + createRelease: true + recognizeContributors: true + + - name: Sync Cargo.lock + if: steps.covector.outputs.commandRan == 'version' + run: cargo tree --depth 0 + + - name: Create Pull Request With Versions Bumped + if: steps.covector.outputs.commandRan == 'version' + uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # 7.0.6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + title: Apply Version Updates From Current Changes + commit-message: 'apply version updates' + labels: 'version updates' + branch: 'release' + body: ${{ steps.covector.outputs.change }} + sign-commits: true diff --git a/ports/tray-icon/.github/workflows/test.yml b/ports/tray-icon/.github/workflows/test.yml new file mode 100644 index 000000000000..9cb9c552ba69 --- /dev/null +++ b/ports/tray-icon/.github/workflows/test.yml @@ -0,0 +1,42 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: test + +on: + push: + branches: + - dev + pull_request: + +env: + RUST_BACKTRACE: 1 + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + strategy: + fail-fast: false + matrix: + platform: ["windows-latest", "macos-latest", "ubuntu-latest"] + + runs-on: ${{ matrix.platform }} + + steps: + - uses: actions/checkout@v4 + + - name: install system deps + if: matrix.platform == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev libxdo-dev libayatana-appindicator3-dev + + - uses: dtolnay/rust-toolchain@1.73 + - run: cargo build + + - uses: dtolnay/rust-toolchain@stable + - run: cargo test diff --git a/ports/tray-icon/.gitignore b/ports/tray-icon/.gitignore new file mode 100644 index 000000000000..b8a245393b2d --- /dev/null +++ b/ports/tray-icon/.gitignore @@ -0,0 +1,6 @@ +# Copyright 2022-2022 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +/target +.vscode/ \ No newline at end of file diff --git a/ports/tray-icon/CHANGELOG.md b/ports/tray-icon/CHANGELOG.md new file mode 100644 index 000000000000..a7711a109407 --- /dev/null +++ b/ports/tray-icon/CHANGELOG.md @@ -0,0 +1,340 @@ +# Changelog + +## \[0.24.1] + +- [`7adc007`](https://www.github.com/tauri-apps/tray-icon/commit/7adc007bb54a91e7e6de4baac87ae534e1aa0550) ([#325](https://www.github.com/tauri-apps/tray-icon/pull/325) by [@Y-ASLant](https://www.github.com/tauri-apps/tray-icon/../../Y-ASLant)) On Windows, preserve tray icon visibility on Explorer restart so a hidden tray icon won't become visible. + +## \[0.24.0] + +- [`19bcab3`](https://www.github.com/tauri-apps/tray-icon/commit/19bcab382753cbbb883b7d6ae96d07111fc73e67) ([#305](https://www.github.com/tauri-apps/tray-icon/pull/305) by [@expenses](https://www.github.com/tauri-apps/tray-icon/../../expenses)) Make gtk an optional feature (enabled by default) + +## \[0.23.1] + +- [`7e5953c`](https://www.github.com/tauri-apps/tray-icon/commit/7e5953c227065f92dc3113268c86d6d0f05739a4) ([#311](https://www.github.com/tauri-apps/tray-icon/pull/311) by [@Fullzoon](https://www.github.com/tauri-apps/tray-icon/../../Fullzoon)) Fixed a Windows tray menu issue reported in #303 where the context menu could appear behind the taskbar after launching from the Start Menu by aligning the tray menu handling with the expected shell behavior, including showing the right-click menu on button release and posting `WM_NULL` after `TrackPopupMenu`. + +## \[0.23.0] + +- [`b74676a`](https://www.github.com/tauri-apps/tray-icon/commit/b74676a487cd74d1cf12b2d355a91473ac476369) ([#312](https://www.github.com/tauri-apps/tray-icon/pull/312) by [@lucasfernog](https://www.github.com/tauri-apps/tray-icon/../../lucasfernog)) Updated `muda` to 0.19. + +## \[0.22.2] + +- [`215e972`](https://www.github.com/tauri-apps/tray-icon/commit/215e97221e3a9e9cbc71b29c10bcfb234e1cc022) ([#262](https://www.github.com/tauri-apps/tray-icon/pull/262) by [@renovate](https://www.github.com/tauri-apps/tray-icon/../../renovate)) Relaxed `windows-sys` dependency to `>=0.60, <=0.61` instead of `0.60` + +## \[0.22.1] + +- [`eabe0f4`](https://www.github.com/tauri-apps/tray-icon/commit/eabe0f48f89c3df1cde48e8111d46bd9fec1ca30) ([#306](https://www.github.com/tauri-apps/tray-icon/pull/306) by [@Legend-Master](https://www.github.com/tauri-apps/tray-icon/../../Legend-Master)) Fix tray icon gets blurry after changing dpi on Windows + +## \[0.22.0] + +- [`f912921`](https://www.github.com/tauri-apps/tray-icon/commit/f912921a56584251dc0b5670b5281cbf7e4106b0) ([#294](https://www.github.com/tauri-apps/tray-icon/pull/294) by [@felipecrs](https://www.github.com/tauri-apps/tray-icon/../../felipecrs)) Added `with_menu_on_right_click` builder method, `set_show_menu_on_right_click` to control whether the context menu is shown on right click (analogous to the existing left click option), and `show_menu()` to programmatically display the tray menu. + + Together these enable dynamic menu workflows where the menu content is updated before being shown, for example by disabling automatic right-click menu, listening for the click event, updating items, and then calling `show_menu()`. +- [`0a5835b`](https://www.github.com/tauri-apps/tray-icon/commit/0a5835b0e6828e37a1f781de9c2d671ae7a939e6) ([#295](https://www.github.com/tauri-apps/tray-icon/pull/295) by [@thief-sty](https://www.github.com/tauri-apps/tray-icon/../../thief-sty)) Update png dependency version to 0.18. + + This avoids duplicated dependencies in downstream crates. +- [`0a5835b`](https://www.github.com/tauri-apps/tray-icon/commit/0a5835b0e6828e37a1f781de9c2d671ae7a939e6) ([#295](https://www.github.com/tauri-apps/tray-icon/pull/295) by [@thief-sty](https://www.github.com/tauri-apps/tray-icon/../../thief-sty)) Update rust version to 1.73. + +## \[0.21.3] + +- [`d3c2468`](https://www.github.com/tauri-apps/tray-icon/commit/d3c24683fd63d197fa064bfbf205ad2fb464e338) ([#293](https://www.github.com/tauri-apps/tray-icon/pull/293) by [@Slinetrac](https://www.github.com/tauri-apps/tray-icon/../../Slinetrac)) Handle Windows tray icon creation when the taskbar is not ready by keeping the message window alive and re-registering on TaskbarCreated. +- [`cb22cd5`](https://www.github.com/tauri-apps/tray-icon/commit/cb22cd5df6b0938aaeebd6c302ec50bc696d8b1a) ([#290](https://www.github.com/tauri-apps/tray-icon/pull/290) by [@FabianLars](https://www.github.com/tauri-apps/tray-icon/../../FabianLars)) The default `id` is now derived from the process id to prevent issues when multiple open apps use the `tray-icon` crate on Linux. + +## \[0.21.2] + +- [`c9f0d21`](https://www.github.com/tauri-apps/tray-icon/commit/c9f0d2108202b3743efb7696a334759b403b9856) ([#278](https://www.github.com/tauri-apps/tray-icon/pull/278) by [@aarol](https://www.github.com/tauri-apps/tray-icon/../../aarol)) Fix infinite loops when printing the full error chain (for example "{err:?}" with anyhow) for `BadIcon` +- [`4bbabba`](https://www.github.com/tauri-apps/tray-icon/commit/4bbabba49cd82e7eb8b5f58cfdfe2b00812517af) ([#277](https://www.github.com/tauri-apps/tray-icon/pull/277) by [@ancwrd1](https://www.github.com/tauri-apps/tray-icon/../../ancwrd1)) Fix a problem on Windows platform where the created window was not destroyed correctly in case the tray icon creation fails. +- [`343599f`](https://www.github.com/tauri-apps/tray-icon/commit/343599f27fb59bf393793140a09511f1331aeda6) ([#284](https://www.github.com/tauri-apps/tray-icon/pull/284) by [@FabianLars](https://www.github.com/tauri-apps/tray-icon/../../FabianLars)) This hotfix reverts https://github.com/tauri-apps/tray-icon/pull/268 because it caused `assertion failed: flush_paint_messages` panics. + +## \[0.21.1] + +- [`1470763`](https://www.github.com/tauri-apps/tray-icon/commit/147076368596bac8626f51d70563ce3a1b048cfb) ([#272](https://www.github.com/tauri-apps/tray-icon/pull/272) by [@ahonn](https://www.github.com/tauri-apps/tray-icon/../../ahonn)) Add platform specific methods to access the underlying native handles of the tray (similar to `TrayIcon::window_handle`): + + - `TrayIcon::ns_status_item` for macOS + - `TrayIcon::app_indicator` for Linux. +- [`2a6a19b`](https://www.github.com/tauri-apps/tray-icon/commit/2a6a19bbac9848d3887b12599b2860ba6653c8f7) ([#268](https://www.github.com/tauri-apps/tray-icon/pull/268) by [@iKineticate](https://www.github.com/tauri-apps/tray-icon/../../iKineticate)) On Windows, fix tray menu freeze on device change events + +## \[0.21.0] + +- [`986007b`](https://www.github.com/tauri-apps/tray-icon/commit/986007b4113f3050d65b6fd1bb43d2bd4b97dcc1) ([#263](https://www.github.com/tauri-apps/tray-icon/pull/263) by [@renovate](https://www.github.com/tauri-apps/tray-icon/../../renovate)) Updated `muda` to `0.17`. + +## \[0.20.1] + +- [`47fc3f3`](https://www.github.com/tauri-apps/tray-icon/commit/47fc3f3ef8ad9a60476d6cf7b5eaa87c621c380a) ([#248](https://www.github.com/tauri-apps/tray-icon/pull/248) by [@aschey](https://www.github.com/tauri-apps/tray-icon/../../aschey)) Add `window_handle` method to retrieve the underlying `hwnd` on Windows +- [`1f28d6f`](https://www.github.com/tauri-apps/tray-icon/commit/1f28d6fc6bc52dfcea0358bae17d9119ec99c4b6) ([#241](https://www.github.com/tauri-apps/tray-icon/pull/241) by [@Legend-Master](https://www.github.com/tauri-apps/tray-icon/../../Legend-Master)) Correct `with_menu_on_left_click`'s docs to include window support + +## \[0.20.0] + +- [`e94976b`](https://www.github.com/tauri-apps/tray-icon/commit/e94976bb48bbe97ac5ab215c6da7c7ca746a5c8a) ([#237](https://www.github.com/tauri-apps/tray-icon/pull/237) by [@renovate](https://www.github.com/tauri-apps/tray-icon/../../renovate)) Updated `muda` to 0.16.0 + +## \[0.19.3] + +- [`d6fee6f`](https://www.github.com/tauri-apps/tray-icon/commit/d6fee6ff627e6ff08bf8bf9a2880197d0f07271e) ([#226](https://www.github.com/tauri-apps/tray-icon/pull/226) by [@madsmtm](https://www.github.com/tauri-apps/tray-icon/../../madsmtm)) Update `objc2` to v0.6. + +## \[0.19.2] + +- [`1f0e1f8`](https://www.github.com/tauri-apps/tray-icon/commit/1f0e1f8f0d0ad65cd0ab549655fac26c0f524de6) ([#204](https://www.github.com/tauri-apps/tray-icon/pull/204) by [@mrexox](https://www.github.com/tauri-apps/tray-icon/../../mrexox)) Add `set_icon_with_as_template` method to update icon and `is_template` property, preventing glitchy effects during icon animation on macOS. + +## \[0.19.1] + +- [`19e67de`](https://www.github.com/tauri-apps/tray-icon/commit/19e67de6ff0b66241fddde507eb82e96781b6c36) ([#199](https://www.github.com/tauri-apps/tray-icon/pull/199) by [@Klemen2](https://www.github.com/tauri-apps/tray-icon/../../Klemen2)) Implemented `TrayIcon::set_show_menu_on_left_click` on windows + +## \[0.19.0] + +- [`bf5cec4`](https://www.github.com/tauri-apps/tray-icon/commit/bf5cec4c3242534cb068978bb27e37551bcb63f9) ([#196](https://www.github.com/tauri-apps/tray-icon/pull/196) by [@amrbashir](https://www.github.com/tauri-apps/tray-icon/../../amrbashir)) **Breaking change** Changed `serde` derive implementation for `TrayIconEvent` to use `serde(tag = "type")` and `rename_all = "camelCase"` on variants so the expected JSON serialization would look like this + + ```json + { + "type": "Click", + "button": "Left", + "buttonState": "Down", + "id": "some id", + "position": { + "x": 0, + "y": 0 + }, + "rect": { + "size": { + "width": 0, + "height": 0 + }, + "position": { + "x": 0, + "y": 0 + } + } + } + ``` + +## \[0.18.0] + +- [`c63733c`](https://www.github.com/tauri-apps/tray-icon/commit/c63733c45f5fd34bc16c9310cb4f1a063e5e21c7) ([#193](https://www.github.com/tauri-apps/tray-icon/pull/193) by [@amrbashir](https://www.github.com/tauri-apps/tray-icon/../../amrbashir)) Update `muda` crate to `0.15` + +## \[0.17.0] + +- [`e711c1f`](https://www.github.com/tauri-apps/tray-icon/commit/e711c1f5e6aef3052694ee8da33b2de624093ec8) ([#189](https://www.github.com/tauri-apps/tray-icon/pull/189) by [@htngr](https://www.github.com/tauri-apps/tray-icon/../../htngr)) Implemented `TrayIcon::with_menu_on_left_click` on windows + +## \[0.16.0] + +- [`20819e4`](https://www.github.com/tauri-apps/tray-icon/commit/20819e445e23f1d3749d03534eba9641404a8db6) ([#187](https://www.github.com/tauri-apps/tray-icon/pull/187) by [@amrbashir](https://www.github.com/tauri-apps/tray-icon/../../amrbashir)) Removed `button_state` field in `TrayIconEvent::DoubleClick` variant. + +## \[0.15.2] + +- [`a1303c3`](https://www.github.com/tauri-apps/tray-icon/commit/a1303c39020befc977d818d7cce1a039d416ccd2) ([#185](https://www.github.com/tauri-apps/tray-icon/pull/185) by [@amrbashir](https://www.github.com/tauri-apps/tray-icon/../../amrbashir)) On Windows, Add and emit `DoubleClick` variant for `TrayIconEvent`. + +## \[0.15.1] + +- [`5a381ff`](https://www.github.com/tauri-apps/tray-icon/commit/5a381ffd3d0f8ab8b1a88a95e557c5837c17a1b7) Update `core-foundation` crate to `0.10` and `core-graphics` to `0.24` + +## \[0.15.0] + +- [`d407869`](https://www.github.com/tauri-apps/tray-icon/commit/d4078696edba67b0ab42cef67e6a421a0332c96f) ([#172](https://www.github.com/tauri-apps/tray-icon/pull/172)) Added a new variant `NotMainThread` to the `Error` enum, which is emitted on macOS when trying to create tray icons from a thread that is not the main thread. +- [`8857b7d`](https://www.github.com/tauri-apps/tray-icon/commit/8857b7dd12ba523532ac7a58bf08302316af13c8) Updated `muda` crate to `0.14` +- [`d407869`](https://www.github.com/tauri-apps/tray-icon/commit/d4078696edba67b0ab42cef67e6a421a0332c96f) ([#172](https://www.github.com/tauri-apps/tray-icon/pull/172)) Rewrite the internals of the crate to use `objc2` instead of `objc`. + + This should have no user-facing changes, other than improved memory safety, and less leaking. + +## \[0.14.3] + +- [`e257d6b`](https://www.github.com/tauri-apps/tray-icon/commit/e257d6bf510b34707d48964a2914ee5c91b13570) ([#169](https://www.github.com/tauri-apps/tray-icon/pull/169)) On Windows, fix `Enter` event emitted only once and never emitted again. + +## \[0.14.2] + +- [`f1f3adb`](https://www.github.com/tauri-apps/tray-icon/commit/f1f3adb5ec726335226ab8ec1d8c6c41012cb9c5)([#166](https://www.github.com/tauri-apps/tray-icon/pull/166)) Switch from `dirs_next` to `dirs` as `dirs_next` is now unmaintained while `dirs` is + +## \[0.14.1] + +- [`b491c98`](https://www.github.com/tauri-apps/tray-icon/commit/b491c9886619d3a26876476b078d99a0ae788918)([#164](https://www.github.com/tauri-apps/tray-icon/pull/164)) Fix tray icon rect scaled by dpi on Windows + +## \[0.14.0] + +- [`587292b`](https://www.github.com/tauri-apps/tray-icon/commit/587292b2e7bfbebdd2677c51b34c6362730d5111)([#161](https://www.github.com/tauri-apps/tray-icon/pull/161)) This release contains **breaking change** to the event structs in order to be able to add new `Enter`, `Move` and `Leave` events: + + - Changed `TrayIconEvent` to be an enum instead of a struct. + - Added new events for when the mouse enters, moves or leaves the tray icon region. + - Removed `ClickType` enum and replaced it with `MouseButton` enum. + - Added `MouseButtonState` enum. + +## \[0.13.5] + +- [`a1cd50e`](https://www.github.com/tauri-apps/tray-icon/commit/a1cd50e53021474ad87cdf2e269acfb56d36cc14)([#145](https://www.github.com/tauri-apps/tray-icon/pull/145)) Fix tray icon gets blurry after changing dpi on Windows +- [`ad317c7`](https://www.github.com/tauri-apps/tray-icon/commit/ad317c7dab271145c641f0c4c22e283bb2aa0c91)([#150](https://www.github.com/tauri-apps/tray-icon/pull/150)) On macOS, fix tray event position not scaled properly. +- [`6d099ee`](https://www.github.com/tauri-apps/tray-icon/commit/6d099ee2a4c455561f4c6f86ea995df267469eca)([#149](https://www.github.com/tauri-apps/tray-icon/pull/149)) On macOS, fix the `y` position of the tray icon to be top-left not bottom-left of the icon. +- [`599bb8f`](https://www.github.com/tauri-apps/tray-icon/commit/599bb8f55546d674892a80051766d36656975e86)([#147](https://www.github.com/tauri-apps/tray-icon/pull/147)) Add `TrayIcon::rect` method to retrieve the tray icon rectangle on Windows and macOS. + +## \[0.13.4] + +- [`6b09b8e`](https://www.github.com/tauri-apps/tray-icon/commit/6b09b8e920e79d7768c3a55324431cbd0acadb27)([#136](https://www.github.com/tauri-apps/tray-icon/pull/136)) Add `Icon::from_resource_name` to support icon resource without a ordinal id on Windows + +## \[0.13.3] + +- [`646f56c`](https://www.github.com/tauri-apps/tray-icon/commit/646f56cb6786377b8dbae1e742bb94e7b6f1bb09)([#138](https://www.github.com/tauri-apps/tray-icon/pull/138)) Fix unexpected crashes on I/O or Png encoding errors on macOS and Linux. + +## \[0.13.2] + +- [`c368bbc`](https://www.github.com/tauri-apps/tray-icon/commit/c368bbc6a24b24767c902508651d856413039108)([#134](https://www.github.com/tauri-apps/tray-icon/pull/134)) Fix incorrect icon size reported in events on macOS + +## \[0.13.1] + +- [`784e01e`](https://www.github.com/tauri-apps/tray-icon/commit/784e01e5b4392a39fbec47f17cdcbee7f27af2bc)([#130](https://www.github.com/tauri-apps/tray-icon/pull/130)) On macOS, reset the tray icon when using `setIconAsTemplate` to avoid artifacts. + +## \[0.13.0] + +- [`63abc69`](https://www.github.com/tauri-apps/tray-icon/commit/63abc69affffdd2849d3d42178d76b9bf1ea994a)([#127](https://www.github.com/tauri-apps/tray-icon/pull/127)) Update `muda` dependency to `0.13` +- [`63abc69`](https://www.github.com/tauri-apps/tray-icon/commit/63abc69affffdd2849d3d42178d76b9bf1ea994a)([#127](https://www.github.com/tauri-apps/tray-icon/pull/127)) Added `dpi` module and changed position and sizes in `TrayIconEvent` to use the new `dpi` module: + + - Removed `TrayIconEvent.x` and `TrayIconEvent.y` and replaced with `TrayIconEvent.position` + - Replaced `Rectangle` type with `Rect` which has just two fields `position` and `size`. + +## \[0.12.0] + +- [`91a5bf6`](https://www.github.com/tauri-apps/tray-icon/commit/91a5bf65d7e3895e9f2eedf4e7ffaf7cc9d082ad)([#119](https://www.github.com/tauri-apps/tray-icon/pull/119)) Updated `muda` dependency to `0.12` + +## \[0.11.3] + +- [`5407f14`](https://www.github.com/tauri-apps/tray-icon/commit/5407f140e12aa83984f6a5402ab99e70a4d4f82c)([#114](https://www.github.com/tauri-apps/tray-icon/pull/114)) On Linux, fix `TrayIcon::set_visible` incorrect inverted behavior. + +## \[0.11.2] + +- [`ca3bed5`](https://www.github.com/tauri-apps/tray-icon/commit/ca3bed51b5d6e8b7e04429f8f90a2d514393b034)([#109](https://www.github.com/tauri-apps/tray-icon/pull/109)) On Windows, add `Icon::from_handle` + +## \[0.11.1] + +- [`6382ea5`](https://www.github.com/tauri-apps/tray-icon/commit/6382ea5b47813ce1546dff6e8a69ca053dc6f145)([#103](https://www.github.com/tauri-apps/tray-icon/pull/103)) On Linux, fix tray menu failing to show. + +## \[0.11.0] + +- [`6e8374a`](https://www.github.com/tauri-apps/tray-icon/commit/6e8374a81a2e84bf38c8678085986e569e517e76) Update `muda` crate to `0.11` + +## \[0.10.0] + +- [`8463328`](https://www.github.com/tauri-apps/tray-icon/commit/84633285a0b465fe4c261ff0c7be035ce7615715)([#92](https://www.github.com/tauri-apps/tray-icon/pull/92)) Upgraded `gtk` to 0.18 and bumped MSRV to 1.70.0. + +## \[0.9.0] + +- [`32b3523`](https://www.github.com/tauri-apps/tray-icon/commit/32b352371b6da730abbb024730015492f87205c0) Update `muda` crate to `0.9` + +## \[0.8.3] + +- [`75fed4a`](https://www.github.com/tauri-apps/tray-icon/commit/75fed4aeca82c5614777865a9f6fa2d4457f47a1) Derive `serde` for more types. + +## \[0.8.2] + +- [`cd6fb13`](https://www.github.com/tauri-apps/tray-icon/commit/cd6fb1300e2b2bf78781777de45302c98cfcabd4)([#80](https://www.github.com/tauri-apps/tray-icon/pull/80)) Add `PartialEq<&str> for &TrayIconId` and `PartialEq for &TrayIconId` implementations. Also add a blanket `From for TrayIconId` where `T: ToString` implementation. + +## \[0.8.1] + +- [`0cf36ad`](https://www.github.com/tauri-apps/tray-icon/commit/0cf36ad6afd1ddd93b7087e8eb4475410fb9be8a)([#77](https://www.github.com/tauri-apps/tray-icon/pull/77)) Add `TrayIconId::new` convenience method. + +## \[0.8.0] + +- [`95c1be8`](https://www.github.com/tauri-apps/tray-icon/commit/95c1be8a459f2ef146ccaccfe858c427678613af)([#75](https://www.github.com/tauri-apps/tray-icon/pull/75)) Th `icon` module has been removed and instead its types are exported from crate root. +- [`95c1be8`](https://www.github.com/tauri-apps/tray-icon/commit/95c1be8a459f2ef146ccaccfe858c427678613af)([#75](https://www.github.com/tauri-apps/tray-icon/pull/75)) Update to `muda@0.8` +- [`f93b57d`](https://www.github.com/tauri-apps/tray-icon/commit/f93b57d08a84a8c7ff7f9035f8cc73a3e48e90b9) Add `TrayIconId` struct an changed all `.id()` methods to return `TrayIconId` instead of a u32. +- [`95c1be8`](https://www.github.com/tauri-apps/tray-icon/commit/95c1be8a459f2ef146ccaccfe858c427678613af)([#75](https://www.github.com/tauri-apps/tray-icon/pull/75)) Changed the order of arguments for `TrayIcon::with_id` function to take the `id` as the first argument instead of the second. + +## \[0.7.7] + +- [`197f431`](https://www.github.com/tauri-apps/tray-icon/commit/197f43161cd1806fcae15b19b4f8335d9b3492b6)([#73](https://www.github.com/tauri-apps/tray-icon/pull/73)) Always highlight tray icon on click on macOS. + +## \[0.7.6] + +- [`a458317`](https://www.github.com/tauri-apps/tray-icon/commit/a458317ad1d85ac9477a019f86580a14d4082c7f)([#71](https://www.github.com/tauri-apps/tray-icon/pull/71)) Fixes a crash on mouse events on macOS. + +## \[0.7.5] + +- [`54fc7de`](https://www.github.com/tauri-apps/tray-icon/commit/54fc7de37c3568312b27c30bdd22e830b1f15a3b)([#69](https://www.github.com/tauri-apps/tray-icon/pull/69)) Refactor macOS implementation to fix missing click issues. + +## \[0.7.4] + +- [`71d25a1`](https://www.github.com/tauri-apps/tray-icon/commit/71d25a14ecd2bf0996223127b2fa01ec7f915fce)([#66](https://www.github.com/tauri-apps/tray-icon/pull/66)) On Linux, fix the issue that gtk caches the icon if you use `TrayIcon::set_icon` repeatedly. + +## \[0.7.3] + +- [`c0d16c5`](https://www.github.com/tauri-apps/tray-icon/commit/c0d16c5f90c3e3b4acadee9c5c83bd5e9a3671f6)([#63](https://www.github.com/tauri-apps/tray-icon/pull/63)) Fixes multiple `set_menu` calls not updating the tray menu on macOS. + +## \[0.7.2] + +- [`d0a25b0`](https://www.github.com/tauri-apps/tray-icon/commit/d0a25b0e980d01306344dd4903c1e2e8ef4519ac)([#61](https://www.github.com/tauri-apps/tray-icon/pull/61)) On Windows, fix dropping tray icon caused the whole process to close. +- [`d0a25b0`](https://www.github.com/tauri-apps/tray-icon/commit/d0a25b0e980d01306344dd4903c1e2e8ef4519ac)([#61](https://www.github.com/tauri-apps/tray-icon/pull/61)) On Windows, fix `TrayIcon::set_menu` not firing events for the new menu. + +## \[0.7.1] + +- [`04ed58f`](https://www.github.com/tauri-apps/tray-icon/commit/04ed58f954b113e1f4d52c161231d52c9f5c3546) Remove accidental impl of `Sync` and `Send` for `TrayIcon` where it is not. + +## \[0.7.0] + +- [`d8d6082`](https://www.github.com/tauri-apps/tray-icon/commit/d8d6082c73b1fa6047ead13d228cf7de1ad0d71c)([#57](https://www.github.com/tauri-apps/tray-icon/pull/57)) Add `TrayIconBuilder::id` to access the unique id that will be assigend to the tray icon upon creation. +- [`dd63ef3`](https://www.github.com/tauri-apps/tray-icon/commit/dd63ef3b68c35fc8b8fbc1d59975d8826420ae51) Add `TrayIconEvent::id` method. +- [`3901519`](https://www.github.com/tauri-apps/tray-icon/commit/3901519a48f76b57174b36ce36c7f803dbfb5536) Update to `muda@0.7` +- [`13d448a`](https://www.github.com/tauri-apps/tray-icon/commit/13d448a9ee7c013f0cc13391ea498da93e806551)([#55](https://www.github.com/tauri-apps/tray-icon/pull/55)) Implement `Clone` for `TrayIcon`. +- [`13d448a`](https://www.github.com/tauri-apps/tray-icon/commit/13d448a9ee7c013f0cc13391ea498da93e806551)([#55](https://www.github.com/tauri-apps/tray-icon/pull/55)) - **Breaking change**: `TrayEvent` has been renamed to `TrayIconEvent` for consistency with other struct names. + - **Breaking change**: `ClickEvent` enum has been renamed to `ClickType` and `TrayEvent`'s `event` field has been renamed to `click_type` +- [`d8d6082`](https://www.github.com/tauri-apps/tray-icon/commit/d8d6082c73b1fa6047ead13d228cf7de1ad0d71c)([#57](https://www.github.com/tauri-apps/tray-icon/pull/57)) Add `TrayIcon::with_id` and `TrayIconBuilder::with_id` to create the tray icon with specified id. + +## \[0.6.0] + +- [`934b927`](https://www.github.com/tauri-apps/tray-icon/commit/934b927e552641c3d319981cdeae84ca901ae399)([#49](https://www.github.com/tauri-apps/tray-icon/pull/49)) Expose `muda` crate feature flags. + +## \[0.5.2] + +- [`9409f36`](https://www.github.com/tauri-apps/tray-icon/commit/9409f36c5293e7fb0c8dd7d0fd74a59472aedfcb)([#46](https://www.github.com/tauri-apps/tray-icon/pull/46)) Fix compiling on `i686-pc-windows-msvc` target + +## \[0.5.1] + +- [`ff7f7bc`](https://www.github.com/tauri-apps/tray-icon/commit/ff7f7bc4400a6f7aa0b5c025c85ab6c4f89e9109)([#40](https://www.github.com/tauri-apps/tray-icon/pull/40)) Fix building for `i686-pc-windows-msvc` target. + +## \[0.5.0] + +- On macOS, fix `set_visible(false)` still occupying space on the system menu bar. + - [71f9d29](https://www.github.com/tauri-apps/tray-icon/commit/71f9d292dd69b498e57fcebeb76ad6a1365144cd) fix(macos): remove tray icon when `set_visible(false)` ([#37](https://www.github.com/tauri-apps/tray-icon/pull/37)) on 2023-04-18 + +## \[0.4.4] + +- Make Rectangle's point fields public. + - [12a0daf](https://www.github.com/tauri-apps/tray-icon/commit/12a0daf92352fbecddd7b0afdfc0c633232fb15c) Make Rectangle's point fields public. ([#33](https://www.github.com/tauri-apps/tray-icon/pull/33)) on 2023-03-23 + +## \[0.4.3] + +- Update documentation. + - [258b49a](https://www.github.com/tauri-apps/tray-icon/commit/258b49aaebd81b6e4327cca1a1a0a2d9bb64188a) docs: update docs on 2023-02-08 + - [3293885](https://www.github.com/tauri-apps/tray-icon/commit/3293885ae5ef19e14f2fe1baaf4d35719f3b3344) Apply Version Updates From Current Changes ([#22](https://www.github.com/tauri-apps/tray-icon/pull/22)) on 2023-02-08 + - [e58a6ce](https://www.github.com/tauri-apps/tray-icon/commit/e58a6cecfffa63096d459429c5d31ec5b3475a9b) docs: document menu and icon relation on Linux on 2023-02-12 + +## \[0.4.2] + +- Update docs. + - [258b49a](https://www.github.com/tauri-apps/tray-icon/commit/258b49aaebd81b6e4327cca1a1a0a2d9bb64188a) docs: update docs on 2023-02-08 + +## \[0.4.1] + +- Bump `muda` to `0.4` and `libappindicator` to `0.8` + - [d92dd6d](https://www.github.com/tauri-apps/tray-icon/commit/d92dd6dc25d268befe9c14cfe193e1de10bc5717) chore(deps): update deps ([#17](https://www.github.com/tauri-apps/tray-icon/pull/17)) on 2023-01-26 + +## \[0.4.0] + +- On macOS and Linux, add `TrayIconBuilder::with_title` and `TrayIcon::set_title` to optionally add a text next to the icon. + - [6df6fc7](https://www.github.com/tauri-apps/tray-icon/commit/6df6fc78885204be5189b41527a39324851c9671) feat: add `with_title` and `set_title` ([#11](https://www.github.com/tauri-apps/tray-icon/pull/11)) on 2023-01-10 + - [b83f14e](https://www.github.com/tauri-apps/tray-icon/commit/b83f14ee66f9d3801535697c30f54bccc433cce1) chore: adjust change bumps on 2023-01-12 +- Add `TrayIcon::set_visible`. + - [ba4580e](https://www.github.com/tauri-apps/tray-icon/commit/ba4580ec8bd061a76575859b5ead8ec16e3b7817) feat: add `set_visible` ([#14](https://www.github.com/tauri-apps/tray-icon/pull/14)) on 2023-01-12 + - [b83f14e](https://www.github.com/tauri-apps/tray-icon/commit/b83f14ee66f9d3801535697c30f54bccc433cce1) chore: adjust change bumps on 2023-01-12 + +## \[0.3.0] + +- Add `TrayEvent::set_event_handler` to set a handler for new tray events. + - [9247abb](https://www.github.com/tauri-apps/tray-icon/commit/9247abb69ce297096b2c388d67b250509fe44efa) refactor: allow changing the menu event sender ([#8](https://www.github.com/tauri-apps/tray-icon/pull/8)) on 2023-01-03 +- Update `muda` to `0.3`. + - [9247abb](https://www.github.com/tauri-apps/tray-icon/commit/9247abb69ce297096b2c388d67b250509fe44efa) refactor: allow changing the menu event sender ([#8](https://www.github.com/tauri-apps/tray-icon/pull/8)) on 2023-01-03 + - [b64b57e](https://www.github.com/tauri-apps/tray-icon/commit/b64b57ec565dada4bc06201f5b4529725bb0009f) chore: update changefile on 2023-01-03 +- **Breaking change** Remove `tray_event_receiver` function, use `TrayEvent::receiver` instead. + - [9247abb](https://www.github.com/tauri-apps/tray-icon/commit/9247abb69ce297096b2c388d67b250509fe44efa) refactor: allow changing the menu event sender ([#8](https://www.github.com/tauri-apps/tray-icon/pull/8)) on 2023-01-03 + +## \[0.2.0] + +- Update `muda` dependency to `0.2`. + - [aa3aa1e](https://www.github.com/tauri-apps/tray-icon/commit/aa3aa1ec0bdcb48ecf9d17204809802c4e6559fc) chore: add change file on 2022-12-30 + +## \[0.1.1] + +- Initial Release. + - [0651773](https://www.github.com/tauri-apps/tray-icon/commit/0651773ad248d34141fbefc1c65a8889a90a8c9b) chore: prepare for initial release on 2022-12-05 diff --git a/ports/tray-icon/Cargo.lock b/ports/tray-icon/Cargo.lock new file mode 100644 index 000000000000..2c02774253ca --- /dev/null +++ b/ports/tray-icon/Cargo.lock @@ -0,0 +1,5674 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[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.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d3b8f9bae46a948369bc4a03e815d4ed6d616bd00de4051133a5019dc31c5a" + +[[package]] +name = "accesskit_atspi_common" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5dd55e6e94949498698daf4d48fb5659e824d7abec0d394089656ceaf99d4f" +dependencies = [ + "accesskit", + "accesskit_consumer", + "atspi-common", + "serde", + "thiserror 1.0.69", + "zvariant", +] + +[[package]] +name = "accesskit_consumer" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459" +dependencies = [ + "accesskit", + "hashbrown 0.15.5", + "immutable-chunkmap", +] + +[[package]] +name = "accesskit_macos" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7329821f3bd1101e03a7d2e03bd339e3ac0dc64c70b4c9f9ae1949e3ba8dece1" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.15.5", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "accesskit_unix" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcee751cc20d88678c33edaf9c07e8b693cd02819fe89053776f5313492273f5" +dependencies = [ + "accesskit", + "accesskit_atspi_common", + "async-channel", + "async-executor", + "async-task", + "atspi", + "futures-lite", + "futures-util", + "serde", + "zbus", +] + +[[package]] +name = "accesskit_windows" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24fcd5d23d70670992b823e735e859374d694a3d12bfd8dd32bd3bd8bedb5d81" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.15.5", + "paste", + "static_assertions", + "windows 0.58.0", + "windows-core 0.58.0", +] + +[[package]] +name = "accesskit_winit" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6a48dad5530b6deb9fc7a52cc6c3bf72cdd9eb8157ac9d32d69f2427a5e879" +dependencies = [ + "accesskit", + "accesskit_macos", + "accesskit_unix", + "accesskit_windows", + "raw-window-handle", + "winit", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[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.13.0", + "cc", + "jni 0.22.4", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys 0.6.0+11769913", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "arboard" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" +dependencies = [ + "clipboard-win", + "image", + "log", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.2", + "parking_lot", + "percent-encoding", + "windows-sys 0.60.2", + "x11rb", +] + +[[package]] +name = "arc-swap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" +dependencies = [ + "rustversion", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading 0.8.9", +] + +[[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-fs" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "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 2.0.118", +] + +[[package]] +name = "async-signal" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" +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-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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "atk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +dependencies = [ + "atk-sys", + "glib 0.18.5", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +dependencies = [ + "glib-sys 0.18.1", + "gobject-sys 0.18.0", + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "atspi" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be534b16650e35237bb1ed189ba2aab86ce65e88cc84c66f4935ba38575cecbf" +dependencies = [ + "atspi-common", + "atspi-connection", + "atspi-proxies", +] + +[[package]] +name = "atspi-common" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1909ed2dc01d0a17505d89311d192518507e8a056a48148e3598fef5e7bb6ba7" +dependencies = [ + "enumflags2", + "serde", + "static_assertions", + "zbus", + "zbus-lockstep", + "zbus-lockstep-macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "atspi-connection" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "430c5960624a4baaa511c9c0fcc2218e3b58f5dbcc47e6190cafee344b873333" +dependencies = [ + "atspi-common", + "atspi-proxies", + "futures-lite", + "zbus", +] + +[[package]] +name = "atspi-proxies" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e6c5de3e524cf967569722446bcd458d5032348554d9a17d7d72b041ab7496" +dependencies = [ + "atspi-common", + "serde", + "zbus", + "zvariant", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +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 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 = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.13.0", + "cairo-sys-rs 0.18.2", + "glib 0.18.5", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-rs" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc8d9aa793480744cd9a0524fef1a2e197d9eaa0f739cde19d16aba530dcb95" +dependencies = [ + "bitflags 2.13.0", + "cairo-sys-rs 0.22.0", + "glib 0.22.8", + "libc", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys 0.18.1", + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8b4985713047f5faee02b8db6a6ef32bbb50269ff53c1aee716d1d195b76d54" +dependencies = [ + "glib-sys 0.22.8", + "libc", + "system-deps 7.0.8", +] + +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.13.0", + "log", + "polling", + "rustix 0.38.44", + "slab", + "thiserror 1.0.69", +] + +[[package]] +name = "calloop" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" +dependencies = [ + "bitflags 2.13.0", + "polling", + "rustix 1.1.4", + "slab", + "tracing", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "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 = "cc" +version = "1.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon 0.12.16", +] + +[[package]] +name = "cfg-expr" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb693542bcafa528e198be0ebd9d3632ca5b7c93dbe7237460e199910835997c" +dependencies = [ + "smallvec", + "target-lexicon 0.13.5", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +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 = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "clipboard-win" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" +dependencies = [ + "error-code", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +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 0.1.3", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" +dependencies = [ + "bitflags 2.13.0", + "core-foundation 0.10.1", + "core-graphics-types 0.2.0", + "foreign-types", + "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 = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.13.0", + "core-foundation 0.10.1", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cursor-icon" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" + +[[package]] +name = "dbus" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "dbus-codegen" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a49da9fdfbe872d4841d56605dc42efa5e6ca3291299b87f44e1cde91a28617c" +dependencies = [ + "clap", + "dbus", + "xml-rs", +] + +[[package]] +name = "dbus-tree" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f456e698ae8e54575e19ddb1f9b7bce2298568524f215496b248eb9498b4f508" +dependencies = [ + "dbus", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.13.0", + "block2 0.6.2", + "libc", + "objc2 0.6.4", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[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 = "dlopen2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +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" +dependencies = [ + "serde", +] + +[[package]] +name = "ecolor" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc4feb366740ded31a004a0e4452fbf84e80ef432ecf8314c485210229672fd1" +dependencies = [ + "bytemuck", + "emath", +] + +[[package]] +name = "eframe" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0dfe0859f3fb1bc6424c57d41e10e9093fe938f426b691e42272c2f336d915c" +dependencies = [ + "ahash", + "bytemuck", + "document-features", + "egui", + "egui-wgpu", + "egui-winit", + "egui_glow", + "glow", + "glutin", + "glutin-winit", + "image", + "js-sys", + "log", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "parking_lot", + "percent-encoding", + "profiling", + "raw-window-handle", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "web-time", + "winapi", + "windows-sys 0.59.0", + "winit", +] + +[[package]] +name = "egui" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" +dependencies = [ + "accesskit", + "ahash", + "bitflags 2.13.0", + "emath", + "epaint", + "log", + "nohash-hasher", + "profiling", +] + +[[package]] +name = "egui-wgpu" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d319dfef570f699b6e9114e235e862a2ddcf75f0d1a061de9e1328d92146d820" +dependencies = [ + "ahash", + "bytemuck", + "document-features", + "egui", + "epaint", + "log", + "profiling", + "thiserror 1.0.69", + "type-map", + "web-time", + "wgpu", + "winit", +] + +[[package]] +name = "egui-winit" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9dfbb78fe4eb9c3a39ad528b90ee5915c252e77bbab9d4ebc576541ab67e13" +dependencies = [ + "accesskit_winit", + "ahash", + "arboard", + "bytemuck", + "egui", + "log", + "profiling", + "raw-window-handle", + "smithay-clipboard", + "web-time", + "webbrowser", + "winit", +] + +[[package]] +name = "egui_glow" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "910906e3f042ea6d2378ec12a6fd07698e14ddae68aed2d819ffe944a73aab9e" +dependencies = [ + "ahash", + "bytemuck", + "egui", + "glow", + "log", + "memoffset", + "profiling", + "wasm-bindgen", + "web-sys", + "winit", +] + +[[package]] +name = "emath" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "endi" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" + +[[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 2.0.118", +] + +[[package]] +name = "epaint" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fcc0f5a7c613afd2dee5e4b30c3e6acafb8ad6f0edb06068811f708a67c562" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor", + "emath", + "epaint_default_fonts", + "log", + "nohash-hasher", + "parking_lot", + "profiling", +] + +[[package]] +name = "epaint_default_fonts" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7e7a64c02cf7a5b51e745a9e45f60660a286f151c238b9d397b3e923f5082f" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "error-code" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fax" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[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 = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gdk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +dependencies = [ + "cairo-rs 0.18.5", + "gdk-pixbuf 0.18.5", + "gdk-sys", + "gio 0.18.4", + "glib 0.18.5", + "libc", + "pango 0.18.3", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys 0.18.0", + "gio 0.18.4", + "glib 0.18.5", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f420376dbee041b2db374ce4573892a36222bb3f6c0c43e24f0d67eae9b646" +dependencies = [ + "gdk-pixbuf-sys 0.22.0", + "gio 0.22.8", + "glib 0.22.8", + "libc", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys 0.18.1", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f31b37b1fc4b48b54f6b91b7ef04c18e00b4585d98359dd7b998774bbd91fb" +dependencies = [ + "gio-sys 0.22.8", + "glib-sys 0.22.8", + "gobject-sys 0.22.6", + "libc", + "system-deps 7.0.8", +] + +[[package]] +name = "gdk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +dependencies = [ + "cairo-sys-rs 0.18.2", + "gdk-pixbuf-sys 0.18.0", + "gio-sys 0.18.1", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", + "libc", + "pango-sys 0.18.0", + "pkg-config", + "system-deps 6.2.2", +] + +[[package]] +name = "gdk4" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d81e2a6c6ecba2aab60633a98df1868b03fa0bfdce8105edc27c1bccf71f0e39" +dependencies = [ + "cairo-rs 0.22.0", + "gdk-pixbuf 0.22.0", + "gdk4-sys", + "gio 0.22.8", + "glib 0.22.8", + "libc", + "pango 0.22.8", +] + +[[package]] +name = "gdk4-sys" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d8f608d8d7d229975c4d0d026f5d3071598c4ddab3c5262b0a31840fec78d13" +dependencies = [ + "cairo-sys-rs 0.22.0", + "gdk-pixbuf-sys 0.22.0", + "gio-sys 0.22.8", + "glib-sys 0.22.8", + "gobject-sys 0.22.6", + "libc", + "pango-sys 0.22.0", + "pkg-config", + "system-deps 7.0.8", +] + +[[package]] +name = "gdk4-wayland" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d95828dadc0357dee236cc6a5712808bd894d3217159982592ce24f2b8aaf7" +dependencies = [ + "gdk4", + "gdk4-wayland-sys", + "gio 0.22.8", + "glib 0.22.8", + "libc", + "wayland-backend", + "wayland-client", + "wayland-protocols", +] + +[[package]] +name = "gdk4-wayland-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653cafb8715f2ac1c56edaf8060d9360ae3acbe3c6fb61b676a2917d42b668cf" +dependencies = [ + "glib-sys 0.22.8", + "libc", + "system-deps 7.0.8", +] + +[[package]] +name = "gdk4-x11" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d892b4cf5a07e90e1390e93cd792975746c68b59f790a2de9e96ce77211ea9a" +dependencies = [ + "gdk4", + "gdk4-x11-sys", + "gio 0.22.8", + "glib 0.22.8", + "libc", +] + +[[package]] +name = "gdk4-x11-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d41f2e28f62378b081288914325d73bddbb6ccbbadb41aa6392afc71d27002" +dependencies = [ + "gdk4-sys", + "glib-sys 0.22.8", + "libc", + "system-deps 7.0.8", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "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 = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys 0.18.1", + "glib 0.18.5", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b3e1f669909c326b9413bde5a742097b8c90a7d78f45326db13668984769ded" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys 0.22.8", + "glib 0.22.8", + "libc", + "pin-project-lite", + "smallvec", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys 0.18.1", + "gobject-sys 0.18.0", + "libc", + "system-deps 6.2.2", + "winapi", +] + +[[package]] +name = "gio-sys" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353fdc7da7cd16da916104b1e0e4e7de380ec9c8aaa20d4d742d66310ab4b0d5" +dependencies = [ + "glib-sys 0.22.8", + "gobject-sys 0.22.6", + "libc", + "system-deps 7.0.8", + "windows-sys 0.61.2", +] + +[[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 = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.13.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys 0.18.1", + "glib-macros 0.18.5", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddbcf514bd1881fc1b960e4e52b4e82873f4da3bceddbd58d42827b508888100" +dependencies = [ + "bitflags 2.13.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys 0.22.8", + "glib-macros 0.22.6", + "glib-sys 0.22.8", + "gobject-sys 0.22.6", + "libc", + "memchr", + "smallvec", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 2.0.2", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "glib-macros" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "506d23499707c7142898429757e8d9a3871d965239a2cb66dfa05052be6d6f19" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "glib-sys" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030967459f9f676851872c6304adea7825c6d462ec9b72554c733cf0c5952233" +dependencies = [ + "libc", + "system-deps 7.0.8", +] + +[[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.13.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 = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys 0.18.1", + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "gobject-sys" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a861859b887a79cf461359c192c97a57d8fb0229dd291232e57aa11f6fa72c" +dependencies = [ + "glib-sys 0.22.8", + "libc", + "system-deps 7.0.8", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45cf04b2726f02df5508c6de726acdc90cdf97ac771a9a0ffd8ba10a6e696bf9" +dependencies = [ + "bitflags 2.13.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bbed164dd10ed526c2e4fe3e721ca4a71c61730e5aafac6844b417b3227058" +dependencies = [ + "bitflags 2.13.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags 2.13.0", + "gpu-descriptor-types", + "hashbrown 0.15.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.13.0", +] + +[[package]] +name = "graphene-rs" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb856b9c558971c3f13ab692358926da710b046932a4e087aedcc35b040d7dff" +dependencies = [ + "glib 0.22.8", + "graphene-sys", +] + +[[package]] +name = "graphene-sys" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ffdfde88f3570d3705e0d8a2433e036d387a1f2930bbf47eafcb5f569fd04" +dependencies = [ + "glib-sys 0.22.8", + "libc", + "system-deps 7.0.8", +] + +[[package]] +name = "gsk4" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b867be1c5f14dcb8f552c0eff6e9a9b1da5f8b43943e8efc3a63c889d84952ff" +dependencies = [ + "cairo-rs 0.22.0", + "gdk4", + "glib 0.22.8", + "graphene-rs", + "gsk4-sys", + "libc", + "pango 0.22.8", +] + +[[package]] +name = "gsk4-sys" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b7c7eb2e681ee896646cfb8872b431f24d09f53ba9283289d9b10caa6707088" +dependencies = [ + "cairo-sys-rs 0.22.0", + "gdk4-sys", + "glib-sys 0.22.8", + "gobject-sys 0.22.6", + "graphene-sys", + "libc", + "pango-sys 0.22.0", + "system-deps 7.0.8", +] + +[[package]] +name = "gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +dependencies = [ + "atk", + "cairo-rs 0.18.5", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf 0.18.5", + "gio 0.18.4", + "glib 0.18.5", + "gtk-sys", + "gtk3-macros", + "libc", + "pango 0.18.3", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +dependencies = [ + "atk-sys", + "cairo-sys-rs 0.18.2", + "gdk-pixbuf-sys 0.18.0", + "gdk-sys", + "gio-sys 0.18.1", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", + "libc", + "pango-sys 0.18.0", + "system-deps 6.2.2", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "gtk4" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98a0a0466484f64b07b5b8184d43fa46be78eb0b8e04ae4e179af31d770b76d9" +dependencies = [ + "cairo-rs 0.22.0", + "field-offset", + "futures-channel", + "gdk-pixbuf 0.22.0", + "gdk4", + "gio 0.22.8", + "glib 0.22.8", + "graphene-rs", + "gsk4", + "gtk4-macros", + "gtk4-sys", + "libc", + "pango 0.22.8", +] + +[[package]] +name = "gtk4-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac7179400a36a04de039c24206bb841c5596992b907b43b23ee8d5bdc40d00e" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "gtk4-sys" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f954786af0b1984425c4446b77f5ff6594346181316be3f850caab1c6f01" +dependencies = [ + "cairo-sys-rs 0.22.0", + "gdk-pixbuf-sys 0.22.0", + "gdk4-sys", + "gio-sys 0.22.8", + "glib-sys 0.22.8", + "gobject-sys 0.22.6", + "graphene-sys", + "gsk4-sys", + "libc", + "pango-sys 0.22.0", + "system-deps 7.0.8", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "png", + "tiff", +] + +[[package]] +name = "immutable-chunkmap" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3e98b1520e49e252237edc238a39869da9f3241f2ec19dc788c1d24694d1e4" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "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 2.0.118", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[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 2.0.118", +] + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.13.0", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading 0.8.9", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "ksni" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4934310bdd016e55725482b8d35ac0c16fd058c1b955d8959aa2d953b918c85b" +dependencies = [ + "dbus", + "dbus-codegen", + "dbus-tree", + "thiserror 1.0.69", +] + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib 0.18.5", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading 0.7.4", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link 0.2.1", +] + +[[package]] +name = "libredox" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" +dependencies = [ + "bitflags 2.13.0", + "libc", + "plain", + "redox_syscall 0.9.0", +] + +[[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.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +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 = "metal" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" +dependencies = [ + "bitflags 2.13.0", + "block", + "core-graphics-types 0.1.3", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "muda" +version = "0.19.3" +dependencies = [ + "arc-swap", + "crossbeam-channel", + "dpi", + "gtk4", + "keyboard-types", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "once_cell", + "png", + "serde", + "thiserror 2.0.18", + "windows-sys 0.61.2", +] + +[[package]] +name = "naga" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.13.0", + "cfg_aliases", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "rustc-hash 1.1.0", + "spirv", + "strum", + "termcolor", + "thiserror 2.0.18", + "unicode-xid", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.13.0", + "jni-sys 0.3.1", + "log", + "ndk-sys 0.6.0+11769913", + "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.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys 0.3.1", +] + +[[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.1", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.13.0", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +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 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[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.13.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.13.0", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 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.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location 0.2.2", + "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.13.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.13.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 = [ + "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.13.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.13.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", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-contacts", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.13.0", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.13.0", + "block2 0.5.1", + "dispatch", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.13.0", + "block2 0.6.2", + "objc2 0.6.4", + "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.13.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.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.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.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.13.0", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 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.13.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 0.2.2", + "objc2-foundation 0.2.2", + "objc2-link-presentation", + "objc2-quartz-core 0.2.2", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications 0.2.2", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.13.0", + "block2 0.6.2", + "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-location 0.3.2", + "objc2-core-text", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", + "objc2-user-notifications 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.13.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "orbclient" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df339f526ea9a60e371768d50efc2f2508c7203290731565d1f7a6f71d21747" +dependencies = [ + "libc", + "libredox", +] + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +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", +] + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio 0.18.4", + "glib 0.18.5", + "libc", + "once_cell", + "pango-sys 0.18.0", +] + +[[package]] +name = "pango" +version = "0.22.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d800d8d0de2ad5d0fb046f5344dbaba14a003cf3dd27cc21d85893d35ea316c" +dependencies = [ + "gio 0.22.8", + "glib 0.22.8", + "pango-sys 0.22.0", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys 0.18.1", + "gobject-sys 0.18.0", + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "pango-sys" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd111a20ca90fedf03e09c59783c679c00900f1d8491cca5399f5e33609d5d6" +dependencies = [ + "glib-sys 0.22.8", + "gobject-sys 0.22.6", + "libc", + "system-deps 7.0.8", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[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.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.13.0", + "crc32fast", + "fdeflate", + "flate2", + "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 = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.12+spec-1.1.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" + +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quick-xml" +version = "0.39.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.0", +] + +[[package]] +name = "redox_syscall" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5102a6aaa05aa011a238e178e6bca86d2cb56fc9f586d37cb80f5bca6e07759" +dependencies = [ + "bitflags 2.13.0", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.13.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.13.0", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[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", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[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 2.0.118", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[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 = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.13.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.13.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 = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.13.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.118", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr 0.15.8", + "heck 0.5.0", + "pkg-config", + "toml 0.8.2", + "version-compare", +] + +[[package]] +name = "system-deps" +version = "7.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7" +dependencies = [ + "cfg-expr 0.20.8", + "heck 0.5.0", + "pkg-config", + "toml 1.1.2+spec-1.1.0", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.35.3" +dependencies = [ + "async-channel", + "bitflags 2.13.0", + "block2 0.6.2", + "core-foundation 0.10.1", + "core-graphics 0.25.0", + "crossbeam-channel", + "dbus", + "dispatch2", + "dlopen2", + "dpi", + "gdk4-wayland", + "gdk4-x11", + "gtk4", + "jni 0.21.1", + "libc", + "log", + "ndk", + "ndk-sys 0.6.0+11769913", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", + "objc2-ui-kit 0.3.2", + "once_cell", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "tao-macros", + "unicode-segmentation", + "url", + "windows 0.61.3", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + +[[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", + "tiny-skia-path", +] + +[[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]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.3", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.3", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.3", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tray-icon" +version = "0.24.1" +dependencies = [ + "arc-swap", + "crossbeam-channel", + "dirs", + "eframe", + "gtk4", + "image", + "ksni", + "libappindicator", + "muda", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.2", + "once_cell", + "png", + "serde", + "serde_json", + "tao", + "thiserror 2.0.18", + "windows-sys 0.61.2", + "winit", +] + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" + +[[package]] +name = "type-map" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" +dependencies = [ + "rustc-hash 2.1.3", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[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 = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.118", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +dependencies = [ + "unicode-ident", +] + +[[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.13.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.13.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.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" +dependencies = [ + "bitflags 2.13.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.13.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.13.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.13.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.13.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.4", + "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-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webbrowser" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc95580916af1e68ff6a7be07446fc5db73ebf71cf092de939bbf5f7e189f72" +dependencies = [ + "core-foundation 0.10.1", + "jni 0.22.4", + "log", + "ndk-context", + "objc2 0.6.4", + "objc2-foundation 0.3.2", + "url", + "web-sys", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "wgpu" +version = "24.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b0b3436f0729f6cdf2e6e9201f3d39dc95813fad61d826c1ed07918b4539353" +dependencies = [ + "arrayvec", + "bitflags 2.13.0", + "cfg_aliases", + "document-features", + "js-sys", + "log", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "24.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f0aa306497a238d169b9dc70659105b4a096859a34894544ca81719242e1499" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.13.0", + "cfg_aliases", + "document-features", + "indexmap", + "log", + "naga", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 2.0.18", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "24.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bitflags 2.13.0", + "bytemuck", + "cfg_aliases", + "core-graphics-types 0.1.3", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-descriptor", + "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.9", + "log", + "metal", + "naga", + "ndk-sys 0.5.0+25.2.9519653", + "objc", + "once_cell", + "ordered-float", + "parking_lot", + "profiling", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 2.0.18", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "windows 0.58.0", +] + +[[package]] +name = "wgpu-types" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c" +dependencies = [ + "bitflags 2.13.0", + "js-sys", + "log", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[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", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[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]] +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]] +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", +] + +[[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 2.0.118", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[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 2.0.118", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +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-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-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "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-version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +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.13.0", + "block2 0.5.1", + "bytemuck", + "calloop 0.13.0", + "cfg_aliases", + "concurrent-queue", + "core-foundation 0.9.4", + "core-graphics 0.23.2", + "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", + "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.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[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 = "xcursor" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" + +[[package]] +name = "xdg-home" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.13.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 = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", + "synstructure", +] + +[[package]] +name = "zbus" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.52.0", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus-lockstep" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca2c5dceb099bddaade154055c926bb8ae507a18756ba1d8963fd7b51d8ed1d" +dependencies = [ + "zbus_xml", + "zvariant", +] + +[[package]] +name = "zbus-lockstep-macros" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", + "zbus-lockstep", + "zbus_xml", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.118", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + +[[package]] +name = "zbus_xml" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3f374552b954f6abb4bd6ce979e6c9b38fb9d0cd7cc68a7d796e70c9f3a233" +dependencies = [ + "quick-xml 0.30.0", + "serde", + "static_assertions", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] + +[[package]] +name = "zvariant" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.118", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] diff --git a/ports/tray-icon/Cargo.toml b/ports/tray-icon/Cargo.toml new file mode 100644 index 000000000000..7e7c2cbd5456 --- /dev/null +++ b/ports/tray-icon/Cargo.toml @@ -0,0 +1,102 @@ +[package] +name = "tray-icon" +version = "0.24.1" +edition = "2021" +description = "Create tray icons for desktop applications" +homepage = "https://github.com/tauri-apps/tray-icon" +repository = "https://github.com/tauri-apps/tray-icon" +license = "MIT OR Apache-2.0" +categories = ["gui"] +rust-version = "1.73" +include = [ + "README.md", + "src/**/*.rs", + "Cargo.toml", + "LICENSE-APACHE", + "LICENSE-MIT", + "LICENSE.spdx", +] + +[features] +default = ["libxdo", "gtk"] +libxdo = ["muda/libxdo"] +serde = ["muda/serde", "dep:serde"] +common-controls-v6 = ["muda/common-controls-v6"] +gtk = ["muda/gtk", "dep:libappindicator"] +linux-ksni = ["dep:arc-swap", "dep:ksni", "muda/linux-ksni"] + +[dependencies] +muda = { path = "../muda", default-features = false } +crossbeam-channel = "0.5" +once_cell = "1" +thiserror = "2" +serde = { version = "1", optional = true } + +[target."cfg(target_os = \"windows\")".dependencies.windows-sys] +version = ">=0.60, <=0.61" +features = [ + "Win32_UI_WindowsAndMessaging", + "Win32_Foundation", + "Win32_System_SystemServices", + "Win32_Graphics_Gdi", + "Win32_UI_Shell", +] + +[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"netbsd\", target_os = \"openbsd\"))".dependencies] +libappindicator = { version = "0.9", optional = true } +arc-swap = { version = "1.7.1", optional = true } +ksni = { version = "0.2.2", optional = true } +dirs = "6" + +[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"netbsd\", target_os = \"openbsd\"))".dev-dependencies] +gtk = { package = "gtk4", version = "0.11" } + +[target."cfg(target_os = \"macos\")".dependencies] +objc2 = "0.6" +objc2-core-graphics = { version = "0.3", default-features = false, features = [ + "std", + "CGDirectDisplay", +] } +objc2-core-foundation = { version = "0.3", default-features = false, features = [ + "std", + "CFCGTypes", + "CFRunLoop", +] } +objc2-foundation = { version = "0.3", default-features = false, features = [ + "std", + "block2", + "objc2-core-foundation", + "NSArray", + "NSData", + "NSEnumerator", + "NSGeometry", + "NSString", + "NSThread", +] } +objc2-app-kit = { version = "0.3", default-features = false, features = [ + "std", + "objc2-core-foundation", + "NSButton", + "NSCell", + "NSControl", + "NSEvent", + "NSImage", + "NSMenu", + "NSResponder", + "NSStatusBar", + "NSStatusBarButton", + "NSStatusItem", + "NSTrackingArea", + "NSView", + "NSWindow", +] } + +[target."cfg(any(target_os = \"linux\", target_os = \"macos\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"netbsd\", target_os = \"openbsd\"))".dependencies] +png = "0.18" + +[dev-dependencies] +winit = "0.30" +tao = { path = "../tao" } +eframe = "0.31" +image = { version = "0.25", default-features = false, features = ["png"] } +serde_json = "1" diff --git a/ports/tray-icon/LICENSE-APACHE b/ports/tray-icon/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/ports/tray-icon/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/ports/tray-icon/LICENSE-MIT b/ports/tray-icon/LICENSE-MIT new file mode 100644 index 000000000000..da5faffb87e7 --- /dev/null +++ b/ports/tray-icon/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2022 Tauri Programme within The Commons Conservancy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ports/tray-icon/LICENSE.spdx b/ports/tray-icon/LICENSE.spdx new file mode 100644 index 000000000000..c6f204fdb001 --- /dev/null +++ b/ports/tray-icon/LICENSE.spdx @@ -0,0 +1,19 @@ +SPDXVersion: SPDX-2.1 +DataLicense: CC0-1.0 +PackageName: tray-icon +DataFormat: SPDXRef-1 +PackageSupplier: Organization: The Tauri Programme in the Commons Conservancy +PackageHomePage: https://tauri.app +PackageLicenseDeclared: Apache-2.0 +PackageLicenseDeclared: MIT +PackageCopyrightText: 2020-2022, The Tauri Programme in the Commons Conservancy +PackageSummary: Create tray icons for desktop applications. + +PackageComment: The package includes the following libraries; see +Relationship information. + +Created: 2022-12-05T09:00:00Z +PackageDownloadLocation: git://github.com/tauri-apps/tray-icon +PackageDownloadLocation: git+https://github.com/tauri-apps/tray-icon.git +PackageDownloadLocation: git+ssh://github.com/tauri-apps/tray-icon.git +Creator: Person: Daniel Thompson-Yvetot \ No newline at end of file diff --git a/ports/tray-icon/README.md b/ports/tray-icon/README.md new file mode 100644 index 000000000000..f249868a9fd6 --- /dev/null +++ b/ports/tray-icon/README.md @@ -0,0 +1,132 @@ +tray-icon lets you create tray icons for desktop applications. + +## Platforms supported: + +- Windows +- macOS +- Linux (gtk Only) +- FreeBSD (gtk Only) + +## Platform-specific notes: + +- On Windows and Linux or FreeBSD, an event loop must be running on the thread, on Windows, a win32 event loop and on Linux or FreeBSD, a gtk event loop. It doesn't need to be the main thread but you have to create the tray icon on the same thread as the event loop. +- On macOS, an event loop must be running on the main thread so you also need to create the tray icon on the main thread. + +### Cargo Features + +- `common-controls-v6`: Use `TaskDialogIndirect` API from `ComCtl32.dll` v6 on Windows for showing the predefined `About` menu item dialog. +- `libxdo`: Enables linking to `libxdo` which is used for the predfined `Copy`, `Cut`, `Paste` and `SelectAll` menu item, see https://github.com/tauri-apps/muda#cargo-features +- `serde`: Enables de/serializing derives. + +## Dependencies (Linux Only) + +On Linux, `gtk`, `libxdo` is used to make the predfined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work and `libappindicator` or `libayatnat-appindicator` are used to create the tray icon, so make sure to install them on your system. + +#### Arch Linux / Manjaro: + +```sh +pacman -S gtk3 xdotool libappindicator-gtk3 #or libayatana-appindicator +``` + +#### Debian / Ubuntu: + +```sh +sudo apt install libgtk-3-dev libxdo-dev libappindicator3-dev #or libayatana-appindicator3-dev +``` + +## Dependencies in FreeBSD + +Install this dependencies in order to compile `tray-icon`. Instructions using `pkg`: + +```sh +pkg install -y rust glib pkgconf gtk3 +``` + +## Examples + +#### Create a tray icon without a menu. + +```rs +use tray_icon::TrayIconBuilder; + +let tray_icon = TrayIconBuilder::new() + .with_tooltip("system-tray - tray icon library!") + .with_icon(icon) + .build() + .unwrap(); +``` + +#### Create a tray icon with a menu. + +```rs +use tray_icon::{TrayIconBuilder, menu::Menu}; + +let tray_menu = Menu::new(); +let tray_icon = TrayIconBuilder::new() + .with_menu(Box::new(tray_menu)) + .with_tooltip("system-tray - tray icon library!") + .with_icon(icon) + .build() + .unwrap(); +``` + +## Processing tray events + +You can use `TrayIconEvent::receiver` to get a reference to the `TrayIconEventReceiver` +which you can use to listen to events when a click happens on the tray icon + +```rs +use tray_icon::TrayIconEvent; + +if let Ok(event) = TrayIconEvent::receiver().try_recv() { + println!("{:?}", event); +} +``` + +You can also listen for the menu events using `MenuEvent::receiver` to get events for the tray context menu. + +```rs +use tray_icon::{TrayIconEvent, menu::{MenuEvent}}; + +if let Ok(event) = TrayIconEvent::receiver().try_recv() { + println!("tray event: {:?}", event); +} + +if let Ok(event) = MenuEvent::receiver().try_recv() { + println!("menu event: {:?}", event); +} +``` + +### Note for [winit] or [tao] users: + +You should use [`TrayIconEvent::set_event_handler`] and forward +the tray icon events to the event loop by using [`EventLoopProxy`] +so that the event loop is awakened on each tray icon event. +Same can be done for menu events using [`MenuEvent::set_event_handler`]. + +```rust +enum UserEvent { + TrayIconEvent(tray_icon::TrayIconEvent) + MenuEvent(tray_icon::menu::MenuEvent) +} + +let event_loop = EventLoop::::with_user_event().build().unwrap(); + +let proxy = event_loop.create_proxy(); +tray_icon::TrayIconEvent::set_event_handler(Some(move |event| { + proxy.send_event(UserEvent::TrayIconEvent(event)); +})); + +let proxy = event_loop.create_proxy(); +tray_icon::menu::MenuEvent::set_event_handler(Some(move |event| { + proxy.send_event(UserEvent::MenuEvent(event)); +})); +``` + +[`EventLoopProxy`]: https://docs.rs/winit/latest/winit/event_loop/struct.EventLoopProxy.html +[winit]: https://docs.rs/winit +[tao]: https://docs.rs/tao + +## License + +Apache-2.0/MIT diff --git a/ports/tray-icon/examples/egui.rs b/ports/tray-icon/examples/egui.rs new file mode 100644 index 000000000000..1f66533d8b41 --- /dev/null +++ b/ports/tray-icon/examples/egui.rs @@ -0,0 +1,128 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release + +#[cfg(not(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +)))] +use std::{cell::RefCell, rc::Rc}; + +use eframe::egui; +use tray_icon::TrayIconBuilder; + +fn main() -> Result<(), eframe::Error> { + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); + let icon = load_icon(std::path::Path::new(path)); + + // Since egui uses winit under the hood and doesn't use gtk on Linux, and we need gtk for + // the tray icon to show up, we need to spawn a thread + // where we initialize gtk and create the tray_icon + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + std::thread::spawn(|| { + use tray_icon::menu::Menu; + + gtk::init().unwrap(); + let _tray_icon = TrayIconBuilder::new() + .with_menu(Box::new(Menu::new())) + .with_icon(icon) + .build() + .unwrap(); + + gtk::main(); + }); + + #[cfg(not(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + )))] + let mut _tray_icon = Rc::new(RefCell::new(None)); + #[cfg(not(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + )))] + let tray_c = _tray_icon.clone(); + + eframe::run_native( + "My egui App", + eframe::NativeOptions::default(), + Box::new(move |_cc| { + #[cfg(not(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + )))] + { + tray_c + .borrow_mut() + .replace(TrayIconBuilder::new().with_icon(icon).build().unwrap()); + } + Ok(Box::::default()) + }), + ) +} + +struct MyApp { + name: String, + age: u32, +} + +impl Default for MyApp { + fn default() -> Self { + Self { + name: "Arthur".to_owned(), + age: 42, + } + } +} + +impl eframe::App for MyApp { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + use tray_icon::TrayIconEvent; + + if let Ok(event) = TrayIconEvent::receiver().try_recv() { + println!("tray event: {event:?}"); + } + + egui::CentralPanel::default().show(ctx, |ui| { + ui.heading("My egui Application"); + ui.horizontal(|ui| { + let name_label = ui.label("Your name: "); + ui.text_edit_singleline(&mut self.name) + .labelled_by(name_label.id); + }); + ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age")); + if ui.button("Click each year").clicked() { + self.age += 1; + } + ui.label(format!("Hello '{}', age {}", self.name, self.age)); + }); + } +} + +fn load_icon(path: &std::path::Path) -> tray_icon::Icon { + let (icon_rgba, icon_width, icon_height) = { + let image = image::open(path) + .expect("Failed to open icon path") + .into_rgba8(); + let (width, height) = image.dimensions(); + let rgba = image.into_raw(); + (rgba, width, height) + }; + tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") +} diff --git a/ports/tray-icon/examples/icon.png b/ports/tray-icon/examples/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3c3627c36d15b6ae0c04f882a6b59a339f58befd GIT binary patch literal 1481 zcmV;)1vdJLP)O(Y>E8jVW~N@9%Bs8NXt zafw8uxItV#xWpyI^@AV8XpnJZT1u55R!QHRwxJbK46+Vg=Dp(wrqerbrVHr#cF*~r z^Z&oQynC*2Hl`}hE_V(-&1%UEQLR)YjnXUV4!757=LYd7QcBK*cYb?&$&sO{cZujd zK;0P7-w|FdOAl`9SYChPe-Yrcb;MD!z|G8FQG z6mT4<030A1!VIa%ov8-<-Ln!<+m>2r1;IC2f?;z}p3Rg;Kk1oQb7a_ApXjI@h?TBJ zc_cJbzN)NBHQ8UBk$~y#2P$Hjbcdibjf~ea>F5JJ%WL{a%UhO6MEhb@PXg- zdTGz1nu8`bJY9Jf%cR%kk;6+~gLD5_IRM`*U!DOTwRgHFP&Q=UQ=>s<18|3l9d!om zt!^3T(gh?%bem7)$F4=SKOqu~Cm^p*tNRtOGCLenU#e0|?7xQNqs~BPS~M0to|)@4 zJBP+1s7m(6%1Q>}fz5W(ofod9NYWV8o3Vl=n3?D-0oL-zi_ zvQ~CA#5)TLa{8=KZ$Gf2B6IRSU_Qz(L5cNZ--7B>CaylwQ8|D%kCc@kiwYpZ6KHOw zPWcj9)!k5Alzi9@ESR1Ko*oM`P*J)T&23afb*mY-0OGs6Stv^ll^eSoYkwZA@I)-0 z^lX&J4A)+-(f-!NL;=KCbKM7JP&bE*RV904<4Kown3kxnKRm*PmZbJMQ zfb&QEZ1I|$&%#12084}F98P3k7}Q%;a|*LcDu%8LW8*thUn0DpM-JbmOD3%i zV{-!3l9A0AP;kv!5?oj;IZ$g_*eB?DA=jsojDKx*!xq?SV&%9|;es$o1Noi^gFvat zFM)0^z#`{om$Mgm+-tDk4zIgu!#|>54Bui@^R8)ciIY;1wZO@&s~@;Gd(q@6)=0xo=NFb6@M^tv$cEs?Z%1r_CW5fpeplGmH}61%A$_hGZr%o;O9AW zPAc-c;a^}^d(Tan9I$tK>ot(wC~p9_03VJ=4n|96x4Kgl*(c~UBRXyantiN1C87@- zd56mU!Am+8*B_p+0DySXTPzXXj#6eIQUp8`Zox19Vc%pw8d=Th&i68-%#ey)oocWP zPRO_d0PGfb6~YJPzXJdQpbI$4>AeyMBB5#n1l;B|IUh}gyr=-kJx1OE3i`k?%u|)y zQ%&}cGsr346Lu|%@8U4?MD;#|)HpS|6?rIgDth^ulEXyahN@E6);Ze`BF%!::with_user_event().build(); + + // set a tray event handler that forwards the event and wakes up the event loop + let proxy = event_loop.create_proxy(); + TrayIconEvent::set_event_handler(Some(move |event| { + proxy.send_event(UserEvent::TrayIconEvent(event)); + })); + + // set a menu event handler that forwards the event and wakes up the event loop + let proxy = event_loop.create_proxy(); + MenuEvent::set_event_handler(Some(move |event| { + proxy.send_event(UserEvent::MenuEvent(event)); + })); + + let tray_menu = Menu::new(); + + let quit_i = MenuItem::new("Quit", true, None); + tray_menu.append_items(&[ + &PredefinedMenuItem::about( + None, + Some(AboutMetadata { + name: Some("tao".to_string()), + copyright: Some("Copyright tao".to_string()), + ..Default::default() + }), + ), + &PredefinedMenuItem::separator(), + &quit_i, + ]); + + let mut tray_icon = None; + + let menu_channel = MenuEvent::receiver(); + let tray_channel = TrayIconEvent::receiver(); + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::NewEvents(tao::event::StartCause::Init) => { + let icon = load_icon(std::path::Path::new(path)); + + // We create the icon once the event loop is actually running + // to prevent issues like https://github.com/tauri-apps/tray-icon/issues/90 + tray_icon = Some( + TrayIconBuilder::new() + .with_menu(Box::new(tray_menu.clone())) + .with_tooltip("tao - awesome windowing lib") + .with_icon(icon) + .build() + .unwrap(), + ); + + // We have to request a redraw here to have the icon actually show up. + // Tao only exposes a redraw method on the Window so we use core-foundation directly. + #[cfg(target_os = "macos")] + unsafe { + use objc2_core_foundation::{CFRunLoopGetMain, CFRunLoopWakeUp}; + + let rl = CFRunLoopGetMain().unwrap(); + CFRunLoopWakeUp(&rl); + } + } + + Event::UserEvent(UserEvent::TrayIconEvent(event)) => { + println!("{event:?}"); + } + + Event::UserEvent(UserEvent::MenuEvent(event)) => { + println!("{event:?}"); + + if event.id == quit_i.id() { + tray_icon.take(); + *control_flow = ControlFlow::Exit; + } + } + + _ => {} + } + }) +} + +fn load_icon(path: &std::path::Path) -> tray_icon::Icon { + let (icon_rgba, icon_width, icon_height) = { + let image = image::open(path) + .expect("Failed to open icon path") + .into_rgba8(); + let (width, height) = image.dimensions(); + let rgba = image.into_raw(); + (rgba, width, height) + }; + tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") +} diff --git a/ports/tray-icon/examples/winit.rs b/ports/tray-icon/examples/winit.rs new file mode 100644 index 000000000000..b6db6deee0b9 --- /dev/null +++ b/ports/tray-icon/examples/winit.rs @@ -0,0 +1,153 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![allow(unused)] + +use tray_icon::{ + menu::{AboutMetadata, Menu, MenuEvent, MenuItem, PredefinedMenuItem}, + TrayIcon, TrayIconBuilder, TrayIconEvent, TrayIconEventReceiver, +}; +use winit::{ + application::ApplicationHandler, + event::Event, + event_loop::{ControlFlow, EventLoop, EventLoopBuilder}, +}; + +#[derive(Debug)] +enum UserEvent { + TrayIconEvent(tray_icon::TrayIconEvent), + MenuEvent(tray_icon::menu::MenuEvent), +} + +struct Application { + tray_icon: Option, +} + +impl Application { + fn new() -> Application { + Application { tray_icon: None } + } + + fn new_tray_icon() -> TrayIcon { + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/icon.png"); + let icon = load_icon(std::path::Path::new(path)); + + TrayIconBuilder::new() + .with_menu(Box::new(Self::new_tray_menu())) + .with_tooltip("winit - awesome windowing lib") + .with_icon(icon) + .with_title("x") + .build() + .unwrap() + } + + fn new_tray_menu() -> Menu { + let menu = Menu::new(); + let item1 = MenuItem::new("item1", true, None); + if let Err(err) = menu.append(&item1) { + println!("{err:?}"); + } + menu + } +} + +impl ApplicationHandler for Application { + fn resumed(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop) {} + + fn window_event( + &mut self, + _event_loop: &winit::event_loop::ActiveEventLoop, + _window_id: winit::window::WindowId, + _event: winit::event::WindowEvent, + ) { + } + + fn new_events( + &mut self, + _event_loop: &winit::event_loop::ActiveEventLoop, + cause: winit::event::StartCause, + ) { + // We create the icon once the event loop is actually running + // to prevent issues like https://github.com/tauri-apps/tray-icon/issues/90 + if winit::event::StartCause::Init == cause { + #[cfg(not(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + )))] + { + self.tray_icon = Some(Self::new_tray_icon()); + } + + // We have to request a redraw here to have the icon actually show up. + // Winit only exposes a redraw method on the Window so we use core-foundation directly. + #[cfg(target_os = "macos")] + unsafe { + use objc2_core_foundation::{CFRunLoopGetMain, CFRunLoopWakeUp}; + + let rl = CFRunLoopGetMain().unwrap(); + CFRunLoopWakeUp(&rl); + } + } + } + + fn user_event(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop, event: UserEvent) { + println!("{event:?}"); + } +} + +fn main() { + let event_loop = EventLoop::::with_user_event().build().unwrap(); + + // set a tray event handler that forwards the event and wakes up the event loop + let proxy = event_loop.create_proxy(); + TrayIconEvent::set_event_handler(Some(move |event| { + proxy.send_event(UserEvent::TrayIconEvent(event)); + })); + let proxy = event_loop.create_proxy(); + MenuEvent::set_event_handler(Some(move |event| { + proxy.send_event(UserEvent::MenuEvent(event)); + })); + + let mut app = Application::new(); + + let menu_channel = MenuEvent::receiver(); + let tray_channel = TrayIconEvent::receiver(); + + // Since winit doesn't use gtk on Linux, and we need gtk for + // the tray icon to show up, we need to spawn a thread + // where we initialize gtk and create the tray_icon + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + std::thread::spawn(|| { + gtk::init().unwrap(); + + let _tray_icon = Application::new_tray_icon(); + + gtk::main(); + }); + + if let Err(err) = event_loop.run_app(&mut app) { + println!("Error: {:?}", err); + } +} + +fn load_icon(path: &std::path::Path) -> tray_icon::Icon { + let (icon_rgba, icon_width, icon_height) = { + let image = image::open(path) + .expect("Failed to open icon path") + .into_rgba8(); + let (width, height) = image.dimensions(); + let rgba = image.into_raw(); + (rgba, width, height) + }; + tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon") +} diff --git a/ports/tray-icon/renovate.json b/ports/tray-icon/renovate.json new file mode 100644 index 000000000000..e0493a29a7fd --- /dev/null +++ b/ports/tray-icon/renovate.json @@ -0,0 +1,10 @@ +{ + "extends": ["config:recommended"], + "rangeStrategy": "replace", + "packageRules": [ + { + "semanticCommitType": "chore", + "matchPackageNames": ["*"] + } + ] +} diff --git a/ports/tray-icon/rustfmt.toml b/ports/tray-icon/rustfmt.toml new file mode 100644 index 000000000000..f8e8a75063c9 --- /dev/null +++ b/ports/tray-icon/rustfmt.toml @@ -0,0 +1,12 @@ +max_width = 100 +hard_tabs = false +tab_spaces = 4 +newline_style = "Unix" +use_small_heuristics = "Default" +reorder_imports = true +reorder_modules = true +edition = "2021" +merge_derives = true +use_try_shorthand = false +use_field_init_shorthand = false +force_explicit_abi = true diff --git a/ports/tray-icon/src/counter.rs b/ports/tray-icon/src/counter.rs new file mode 100644 index 000000000000..f2610ee8c375 --- /dev/null +++ b/ports/tray-icon/src/counter.rs @@ -0,0 +1,17 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::sync::atomic::{AtomicU32, Ordering}; + +pub struct Counter(AtomicU32); + +impl Counter { + pub const fn new() -> Self { + Self(AtomicU32::new(1)) + } + + pub fn next(&self) -> u32 { + self.0.fetch_add(1, Ordering::Relaxed) + } +} diff --git a/ports/tray-icon/src/error.rs b/ports/tray-icon/src/error.rs new file mode 100644 index 000000000000..b059e8aa1155 --- /dev/null +++ b/ports/tray-icon/src/error.rs @@ -0,0 +1,30 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use thiserror::Error; + +/// Errors returned by tray-icon. +#[non_exhaustive] +#[derive(Error, Debug)] +pub enum Error { + #[error(transparent)] + OsError(#[from] std::io::Error), + #[cfg(any( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + target_os = "macos" + ))] + #[error(transparent)] + PngEncodingError(#[from] png::EncodingError), + #[error("not on the main thread")] + NotMainThread, +} + +/// Convenient type alias of Result type for tray-icon. +pub type Result = std::result::Result; diff --git a/ports/tray-icon/src/icon.rs b/ports/tray-icon/src/icon.rs new file mode 100644 index 000000000000..192891c87e3a --- /dev/null +++ b/ports/tray-icon/src/icon.rs @@ -0,0 +1,187 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +// taken from https://github.com/rust-windowing/winit/blob/92fdf5ba85f920262a61cee4590f4a11ad5738d1/src/icon.rs + +use crate::platform_impl::PlatformIcon; +use std::{error::Error, fmt, io, mem}; + +#[repr(C)] +#[derive(Debug)] +pub(crate) struct Pixel { + pub(crate) r: u8, + pub(crate) g: u8, + pub(crate) b: u8, + pub(crate) a: u8, +} + +pub(crate) const PIXEL_SIZE: usize = mem::size_of::(); + +#[derive(Debug)] +/// An error produced when using [`Icon::from_rgba`] with invalid arguments. +pub enum BadIcon { + /// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be + /// safely interpreted as 32bpp RGBA pixels. + ByteCountNotDivisibleBy4 { byte_count: usize }, + /// Produced when the number of pixels (`rgba.len() / 4`) isn't equal to `width * height`. + /// At least one of your arguments is incorrect. + DimensionsVsPixelCount { + width: u32, + height: u32, + width_x_height: usize, + pixel_count: usize, + }, + /// Produced when underlying OS functionality failed to create the icon + OsError(io::Error), +} + +impl fmt::Display for BadIcon { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + BadIcon::ByteCountNotDivisibleBy4 { byte_count } => write!(f, + "The length of the `rgba` argument ({:?}) isn't divisible by 4, making it impossible to interpret as 32bpp RGBA pixels.", + byte_count, + ), + BadIcon::DimensionsVsPixelCount { + width, + height, + width_x_height, + pixel_count, + } => write!(f, + "The specified dimensions ({:?}x{:?}) don't match the number of pixels supplied by the `rgba` argument ({:?}). For those dimensions, the expected pixel count is {:?}.", + width, height, pixel_count, width_x_height, + ), + BadIcon::OsError(e) => write!(f, "OS error when instantiating the icon: {:?}", e), + } + } +} + +impl Error for BadIcon { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + BadIcon::OsError(e) => Some(e), + _ => None, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct RgbaIcon { + pub(crate) rgba: Vec, + pub(crate) width: u32, + pub(crate) height: u32, +} + +/// For platforms which don't have window icons (e.g. web) +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct NoIcon; + +#[allow(dead_code)] // These are not used on every platform +mod constructors { + use super::*; + + impl RgbaIcon { + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + if rgba.len() % PIXEL_SIZE != 0 { + return Err(BadIcon::ByteCountNotDivisibleBy4 { + byte_count: rgba.len(), + }); + } + let pixel_count = rgba.len() / PIXEL_SIZE; + if pixel_count != (width * height) as usize { + Err(BadIcon::DimensionsVsPixelCount { + width, + height, + width_x_height: (width * height) as usize, + pixel_count, + }) + } else { + Ok(RgbaIcon { + rgba, + width, + height, + }) + } + } + } + + impl NoIcon { + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + // Create the rgba icon anyway to validate the input + let _ = RgbaIcon::from_rgba(rgba, width, height)?; + Ok(NoIcon) + } + } +} + +/// An icon used for the window titlebar, taskbar, etc. +#[derive(Clone)] +pub struct Icon { + pub(crate) inner: PlatformIcon, +} + +impl fmt::Debug for Icon { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + fmt::Debug::fmt(&self.inner, formatter) + } +} + +impl Icon { + /// Creates an icon from 32bpp RGBA data. + /// + /// The length of `rgba` must be divisible by 4, and `width * height` must equal + /// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error. + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + Ok(Icon { + inner: PlatformIcon::from_rgba(rgba, width, height)?, + }) + } + + /// Create an icon from a file path. + /// + /// Specify `size` to load a specific icon size from the file, or `None` to load the default + /// icon size from the file. + /// + /// In cases where the specified size does not exist in the file, Windows may perform scaling + /// to get an icon of the desired size. + #[cfg(windows)] + pub fn from_path>( + path: P, + size: Option<(u32, u32)>, + ) -> Result { + let win_icon = PlatformIcon::from_path(path, size)?; + Ok(Icon { inner: win_icon }) + } + + /// Create an icon from a resource embedded in this executable or library. + /// + /// Specify `size` to load a specific icon size from the file, or `None` to load the default + /// icon size from the file. + /// + /// In cases where the specified size does not exist in the file, Windows may perform scaling + /// to get an icon of the desired size. + #[cfg(windows)] + pub fn from_resource(ordinal: u16, size: Option<(u32, u32)>) -> Result { + let win_icon = PlatformIcon::from_resource(ordinal, size)?; + Ok(Icon { inner: win_icon }) + } + + /// This is basically the same as from_resource, but takes a resource name + /// rather than oridinal id. + #[cfg(windows)] + pub fn from_resource_name( + resource_name: &str, + size: Option<(u32, u32)>, + ) -> Result { + let win_icon = PlatformIcon::from_resource_name(resource_name, size)?; + Ok(Icon { inner: win_icon }) + } + + /// Create an icon from an HICON + #[cfg(windows)] + pub fn from_handle(handle: isize) -> Self { + let win_icon = PlatformIcon::from_handle(handle as _); + Icon { inner: win_icon } + } +} diff --git a/ports/tray-icon/src/lib.rs b/ports/tray-icon/src/lib.rs new file mode 100644 index 000000000000..415bf9610a68 --- /dev/null +++ b/ports/tray-icon/src/lib.rs @@ -0,0 +1,742 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![allow(clippy::uninlined_format_args)] + +//! tray-icon lets you create tray icons for desktop applications. +//! +//! # Platforms supported: +//! +//! - Windows +//! - macOS +//! - Linux (gtk Only) +//! +//! # Platform-specific notes: +//! +//! - On Windows and Linux, an event loop must be running on the thread, on Windows, a win32 event loop and on Linux, a gtk event loop. It doesn't need to be the main thread but you have to create the tray icon on the same thread as the event loop. +//! - On macOS, an event loop must be running on the main thread so you also need to create the tray icon on the main thread. You must make sure that the event loop is already running and not just created before creating a TrayIcon to prevent issues with fullscreen apps. In Winit for example the earliest you can create icons is on [`StartCause::Init`](https://docs.rs/winit/latest/winit/event/enum.StartCause.html#variant.Init). +//! +//! # Dependencies (Linux Only) +//! +//! On Linux, `gtk`, `libxdo` is used to make the predfined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work and `libappindicator` or `libayatnat-appindicator` are used to create the tray icon, so make sure to install them on your system. +//! +//! #### Arch Linux / Manjaro: +//! +//! ```sh +//! pacman -S gtk3 xdotool libappindicator-gtk3 #or libayatana-appindicator +//! ``` +//! +//! #### Debian / Ubuntu: +//! +//! ```sh +//! sudo apt install libgtk-3-dev libxdo-dev libappindicator3-dev #or libayatana-appindicator3-dev +//! ``` +//! +//! # Examples +//! +//! #### Create a tray icon without a menu. +//! +//! ```no_run +//! use tray_icon::{TrayIconBuilder, Icon}; +//! +//! # let icon = Icon::from_rgba(Vec::new(), 0, 0).unwrap(); +//! let tray_icon = TrayIconBuilder::new() +//! .with_tooltip("system-tray - tray icon library!") +//! .with_icon(icon) +//! .build() +//! .unwrap(); +//! ``` +//! +//! #### Create a tray icon with a menu. +//! +//! ```no_run +//! use tray_icon::{TrayIconBuilder, menu::Menu,Icon}; +//! +//! # let icon = Icon::from_rgba(Vec::new(), 0, 0).unwrap(); +//! let tray_menu = Menu::new(); +//! let tray_icon = TrayIconBuilder::new() +//! .with_menu(Box::new(tray_menu)) +//! .with_tooltip("system-tray - tray icon library!") +//! .with_icon(icon) +//! .build() +//! .unwrap(); +//! ``` +//! +//! # Processing tray events +//! +//! You can use [`TrayIconEvent::receiver`] to get a reference to the [`TrayIconEventReceiver`] +//! which you can use to listen to events when a click happens on the tray icon +//! ```no_run +//! use tray_icon::TrayIconEvent; +//! +//! if let Ok(event) = TrayIconEvent::receiver().try_recv() { +//! println!("{:?}", event); +//! } +//! ``` +//! +//! You can also listen for the menu events using [`MenuEvent::receiver`](crate::menu::MenuEvent::receiver) to get events for the tray context menu. +//! +//! ```no_run +//! use tray_icon::{TrayIconEvent, menu::MenuEvent}; +//! +//! if let Ok(event) = TrayIconEvent::receiver().try_recv() { +//! println!("tray event: {:?}", event); +//! } +//! +//! if let Ok(event) = MenuEvent::receiver().try_recv() { +//! println!("menu event: {:?}", event); +//! } +//! ``` +//! +//! ### Note for [winit] or [tao] users: +//! +//! You should use [`TrayIconEvent::set_event_handler`] and forward +//! the tray icon events to the event loop by using [`EventLoopProxy`] +//! so that the event loop is awakened on each tray icon event. +//! Same can be done for menu events using [`MenuEvent::set_event_handler`]. +//! +//! ```no_run +//! # use winit::event_loop::EventLoop; +//! enum UserEvent { +//! TrayIconEvent(tray_icon::TrayIconEvent), +//! MenuEvent(tray_icon::menu::MenuEvent) +//! } +//! +//! let event_loop = EventLoop::::with_user_event().build().unwrap(); +//! +//! let proxy = event_loop.create_proxy(); +//! tray_icon::TrayIconEvent::set_event_handler(Some(move |event| { +//! proxy.send_event(UserEvent::TrayIconEvent(event)); +//! })); +//! +//! let proxy = event_loop.create_proxy(); +//! tray_icon::menu::MenuEvent::set_event_handler(Some(move |event| { +//! proxy.send_event(UserEvent::MenuEvent(event)); +//! })); +//! ``` +//! +//! [`EventLoopProxy`]: https://docs.rs/winit/latest/winit/event_loop/struct.EventLoopProxy.html +//! [winit]: https://docs.rs/winit +//! [tao]: https://docs.rs/tao + +use std::{ + cell::RefCell, + path::{Path, PathBuf}, + rc::Rc, +}; + +use counter::Counter; +use crossbeam_channel::{unbounded, Receiver, Sender}; +use once_cell::sync::{Lazy, OnceCell}; + +mod counter; +mod error; +mod icon; +mod platform_impl; +mod tray_icon_id; + +pub use self::error::*; +pub use self::icon::{BadIcon, Icon}; +pub use self::tray_icon_id::TrayIconId; + +/// Re-export of [muda](::muda) crate and used for tray context menu. +pub mod menu { + pub use muda::*; +} +pub use muda::dpi; + +static COUNTER: Counter = Counter::new(); + +/// Attributes to use when creating a tray icon. +pub struct TrayIconAttributes { + /// Tray icon tooltip + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub tooltip: Option, + + /// Tray menu + /// + /// ## Platform-specific: + /// + /// - **Linux**: once a menu is set, it cannot be removed. + pub menu: Option>, + + /// Tray icon + /// + /// ## Platform-specific: + /// + /// - **Linux:** Sometimes the icon won't be visible unless a menu is set. + /// Setting an empty [`Menu`](crate::menu::Menu) is enough. + pub icon: Option, + + /// Tray icon temp dir path. **Linux only**. + pub temp_dir_path: Option, + + /// Use the icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only**. + pub icon_is_template: bool, + + /// Whether to show the tray menu on left click or not, default is `true`. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub menu_on_left_click: bool, + + /// Whether to show the tray menu on right click or not, default is `true`. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub menu_on_right_click: bool, + + /// Tray icon title. + /// + /// ## Platform-specific + /// + /// - **Linux:** The title will not be shown unless there is an icon + /// as well. The title is useful for numerical and other frequently + /// updated information. In general, it shouldn't be shown unless a + /// user requests it as it can take up a significant amount of space + /// on the user's panel. This may not be shown in all visualizations. + /// - **Windows:** Unsupported. + pub title: Option, +} + +impl Default for TrayIconAttributes { + fn default() -> Self { + Self { + tooltip: None, + menu: None, + icon: None, + temp_dir_path: None, + icon_is_template: false, + menu_on_left_click: true, + menu_on_right_click: true, + title: None, + } + } +} + +/// [`TrayIcon`] builder struct and associated methods. +#[derive(Default)] +pub struct TrayIconBuilder { + id: TrayIconId, + attrs: TrayIconAttributes, +} + +impl TrayIconBuilder { + /// Creates a new [`TrayIconBuilder`] with default [`TrayIconAttributes`]. + /// + /// See [`TrayIcon::new`] for more info. + pub fn new() -> Self { + Self { + id: TrayIconId::new_unique(), + attrs: TrayIconAttributes::default(), + } + } + + /// Sets the unique id to build the tray icon with. + pub fn with_id>(mut self, id: I) -> Self { + self.id = id.into(); + self + } + + /// Set the a menu for this tray icon. + /// + /// ## Platform-specific: + /// + /// - **Linux**: once a menu is set, it cannot be removed or replaced but you can change its content. + pub fn with_menu(mut self, menu: Box) -> Self { + self.attrs.menu = Some(menu); + self + } + + /// Set an icon for this tray icon. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Sometimes the icon won't be visible unless a menu is set. + /// Setting an empty [`Menu`](crate::menu::Menu) is enough. + pub fn with_icon(mut self, icon: Icon) -> Self { + self.attrs.icon = Some(icon); + self + } + + /// Set a tooltip for this tray icon. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn with_tooltip>(mut self, s: S) -> Self { + self.attrs.tooltip = Some(s.as_ref().to_string()); + self + } + + /// Set the tray icon title. + /// + /// ## Platform-specific + /// + /// - **Linux:** The title will not be shown unless there is an icon + /// as well. The title is useful for numerical and other frequently + /// updated information. In general, it shouldn't be shown unless a + /// user requests it as it can take up a significant amount of space + /// on the user's panel. This may not be shown in all visualizations. + /// - **Windows:** Unsupported. + pub fn with_title>(mut self, title: S) -> Self { + self.attrs.title.replace(title.as_ref().to_string()); + self + } + + /// Set tray icon temp dir path. **Linux only**. + /// + /// On Linux, we need to write the icon to the disk and usually it will + /// be `$XDG_RUNTIME_DIR/tray-icon` or `$TEMP/tray-icon`. + pub fn with_temp_dir_path>(mut self, s: P) -> Self { + self.attrs.temp_dir_path = Some(s.as_ref().to_path_buf()); + self + } + + /// Use the icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only**. + pub fn with_icon_as_template(mut self, is_template: bool) -> Self { + self.attrs.icon_is_template = is_template; + self + } + + /// Whether to show the tray menu on left click or not, default is `true`. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn with_menu_on_left_click(mut self, enable: bool) -> Self { + self.attrs.menu_on_left_click = enable; + self + } + + /// Whether to show the tray menu on right click or not, default is `true`. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn with_menu_on_right_click(mut self, enable: bool) -> Self { + self.attrs.menu_on_right_click = enable; + self + } + + /// Access the unique id that will be assigned to the tray icon + /// this builder will create. + pub fn id(&self) -> &TrayIconId { + &self.id + } + + /// Builds and adds a new [`TrayIcon`] to the system tray. + pub fn build(self) -> Result { + TrayIcon::with_id(self.id, self.attrs) + } +} + +/// Tray icon struct and associated methods. +/// +/// This type is reference-counted and the icon is removed when the last instance is dropped. +#[derive(Clone)] +pub struct TrayIcon { + id: TrayIconId, + tray: Rc>, +} + +impl TrayIcon { + /// Builds and adds a new tray icon to the system tray. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Sometimes the icon won't be visible unless a menu is set. + /// Setting an empty [`Menu`](crate::menu::Menu) is enough. + pub fn new(attrs: TrayIconAttributes) -> Result { + let id = TrayIconId::new_unique(); + Ok(Self { + tray: Rc::new(RefCell::new(platform_impl::TrayIcon::new( + id.clone(), + attrs, + )?)), + id, + }) + } + + /// Builds and adds a new tray icon to the system tray with the specified Id. + /// + /// See [`TrayIcon::new`] for more info. + pub fn with_id>(id: I, attrs: TrayIconAttributes) -> Result { + let id = id.into(); + Ok(Self { + tray: Rc::new(RefCell::new(platform_impl::TrayIcon::new( + id.clone(), + attrs, + )?)), + id, + }) + } + + /// Returns the id associated with this tray icon. + pub fn id(&self) -> &TrayIconId { + &self.id + } + + /// Set new tray icon. If `None` is provided, it will remove the icon. + pub fn set_icon(&self, icon: Option) -> Result<()> { + self.tray.borrow_mut().set_icon(icon) + } + + /// Set new tray menu. + /// + /// ## Platform-specific: + /// + /// - **Linux**: once a menu is set it cannot be removed so `None` has no effect + pub fn set_menu(&self, menu: Option>) { + self.tray.borrow_mut().set_menu(menu) + } + + /// Sets the tooltip for this tray icon. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported + pub fn set_tooltip>(&self, tooltip: Option) -> Result<()> { + self.tray.borrow_mut().set_tooltip(tooltip) + } + + /// Sets the tooltip for this tray icon. + /// + /// ## Platform-specific: + /// + /// - **Linux:** The title will not be shown unless there is an icon + /// as well. The title is useful for numerical and other frequently + /// updated information. In general, it shouldn't be shown unless a + /// user requests it as it can take up a significant amount of space + /// on the user's panel. This may not be shown in all visualizations. + /// - **Windows:** Unsupported + pub fn set_title>(&self, title: Option) { + self.tray.borrow_mut().set_title(title) + } + + /// Show or hide this tray icon + pub fn set_visible(&self, visible: bool) -> Result<()> { + self.tray.borrow_mut().set_visible(visible) + } + + /// Sets the tray icon temp dir path. **Linux only**. + /// + /// On Linux, we need to write the icon to the disk and usually it will + /// be `$XDG_RUNTIME_DIR/tray-icon` or `$TEMP/tray-icon`. + pub fn set_temp_dir_path>(&self, path: Option

) { + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + self.tray.borrow_mut().set_temp_dir_path(path); + #[cfg(not(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + )))] + let _ = path; + } + + /// Set the current icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only**. + pub fn set_icon_as_template(&self, is_template: bool) { + #[cfg(target_os = "macos")] + self.tray.borrow_mut().set_icon_as_template(is_template); + #[cfg(not(target_os = "macos"))] + let _ = is_template; + } + + pub fn set_icon_with_as_template(&self, icon: Option, is_template: bool) -> Result<()> { + #[cfg(target_os = "macos")] + return self + .tray + .borrow_mut() + .set_icon_with_as_template(icon, is_template); + #[cfg(not(target_os = "macos"))] + { + let _ = icon; + let _ = is_template; + Ok(()) + } + } + + /// Disable or enable showing the tray menu on left click. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn set_show_menu_on_left_click(&self, enable: bool) { + #[cfg(any(target_os = "macos", target_os = "windows"))] + self.tray.borrow_mut().set_show_menu_on_left_click(enable); + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + let _ = enable; + } + + /// Disable or enable showing the tray menu on right click. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn set_show_menu_on_right_click(&self, enable: bool) { + #[cfg(any(target_os = "macos", target_os = "windows"))] + self.tray.borrow_mut().set_show_menu_on_right_click(enable); + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + let _ = enable; + } + + /// Manually show the tray menu at the current cursor position. + /// + /// This is useful when you want to control when the menu is displayed, + /// for example after updating menu items dynamically. + /// + /// ## Platform-specific: + /// + /// - **Linux:** Unsupported. + pub fn show_menu(&self) { + #[cfg(any(target_os = "macos", target_os = "windows"))] + self.tray.borrow().show_menu(); + } + + /// Get tray icon rect. + /// + /// ## Platform-specific: + /// + /// - **Linux**: Unsupported. + pub fn rect(&self) -> Option { + self.tray.borrow().rect() + } + + /// Get the tray icon's underlying [window handle](windows_sys::Win32::Foundation::HWND) **Windows only**. + /// + /// This window handle is valid as long as the tray icon. + #[cfg(windows)] + pub fn window_handle(&self) -> windows_sys::Win32::Foundation::HWND { + self.tray.borrow().hwnd() + } + + /// Get the tray icon's underlying [NSStatusItem](objc2_app_kit::NSStatusItem) **macOS only**. + /// + /// Returns `None` if the status item is not available. + #[cfg(target_os = "macos")] + pub fn ns_status_item(&self) -> Option> { + self.tray.borrow().ns_status_item().cloned() + } + + /// Get the tray icon's underlying [AppIndicator](libappindicator::AppIndicator) **Linux only**. + /// + /// # Safety + /// + /// The returned pointer is valid as long as the `TrayIcon` is. + #[cfg(all(unix, not(target_os = "macos"), not(feature = "linux-ksni")))] + pub unsafe fn app_indicator(&self) -> *const libappindicator::AppIndicator { + self.tray.borrow().app_indicator() as *const _ + } +} + +/// Describes a tray icon event. +/// +/// ## Platform-specific: +/// +/// - **Linux**: Unsupported. The event is not emmited even though the icon is shown +/// and will still show a context menu on right click. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] +#[non_exhaustive] +pub enum TrayIconEvent { + /// A click happened on the tray icon. + #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] + Click { + /// Id of the tray icon which triggered this event. + id: TrayIconId, + /// Physical Position of this event. + position: dpi::PhysicalPosition, + /// Position and size of the tray icon. + rect: Rect, + /// Mouse button that triggered this event. + button: MouseButton, + /// Mouse button state when this event was triggered. + button_state: MouseButtonState, + }, + /// A double click happened on the tray icon. **Windows Only** + DoubleClick { + /// Id of the tray icon which triggered this event. + id: TrayIconId, + /// Physical Position of this event. + position: dpi::PhysicalPosition, + /// Position and size of the tray icon. + rect: Rect, + /// Mouse button that triggered this event. + button: MouseButton, + }, + /// The mouse entered the tray icon region. + Enter { + /// Id of the tray icon which triggered this event. + id: TrayIconId, + /// Physical Position of this event. + position: dpi::PhysicalPosition, + /// Position and size of the tray icon. + rect: Rect, + }, + /// The mouse moved over the tray icon region. + Move { + /// Id of the tray icon which triggered this event. + id: TrayIconId, + /// Physical Position of this event. + position: dpi::PhysicalPosition, + /// Position and size of the tray icon. + rect: Rect, + }, + /// The mouse left the tray icon region. + Leave { + /// Id of the tray icon which triggered this event. + id: TrayIconId, + /// Physical Position of this event. + position: dpi::PhysicalPosition, + /// Position and size of the tray icon. + rect: Rect, + }, +} + +/// Describes the mouse button state. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Default)] +pub enum MouseButtonState { + #[default] + Up, + Down, +} + +/// Describes which mouse button triggered the event.. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Default)] +pub enum MouseButton { + #[default] + Left, + Right, + Middle, +} + +/// Describes a rectangle including position (x - y axis) and size. +#[derive(Debug, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Rect { + pub size: dpi::PhysicalSize, + pub position: dpi::PhysicalPosition, +} + +impl Default for Rect { + fn default() -> Self { + Self { + size: dpi::PhysicalSize::new(0, 0), + position: dpi::PhysicalPosition::new(0., 0.), + } + } +} + +/// A reciever that could be used to listen to tray events. +pub type TrayIconEventReceiver = Receiver; +type TrayIconEventHandler = Box; + +static TRAY_CHANNEL: Lazy<(Sender, TrayIconEventReceiver)> = Lazy::new(unbounded); +static TRAY_EVENT_HANDLER: OnceCell> = OnceCell::new(); + +impl TrayIconEvent { + /// Returns the id of the tray icon which triggered this event. + pub fn id(&self) -> &TrayIconId { + match self { + TrayIconEvent::Click { id, .. } => id, + TrayIconEvent::DoubleClick { id, .. } => id, + TrayIconEvent::Enter { id, .. } => id, + TrayIconEvent::Move { id, .. } => id, + TrayIconEvent::Leave { id, .. } => id, + } + } + + /// Gets a reference to the event channel's [`TrayIconEventReceiver`] + /// which can be used to listen for tray events. + /// + /// ## Note + /// + /// This will not receive any events if [`TrayIconEvent::set_event_handler`] has been called with a `Some` value. + pub fn receiver<'a>() -> &'a TrayIconEventReceiver { + &TRAY_CHANNEL.1 + } + + /// Set a handler to be called for new events. Useful for implementing custom event sender. + /// + /// ## Note + /// + /// Calling this function with a `Some` value, + /// will not send new events to the channel associated with [`TrayIconEvent::receiver`] + pub fn set_event_handler(f: Option) { + if let Some(f) = f { + let _ = TRAY_EVENT_HANDLER.set(Some(Box::new(f))); + } else { + let _ = TRAY_EVENT_HANDLER.set(None); + } + } + + #[allow(unused)] + pub(crate) fn send(event: TrayIconEvent) { + if let Some(handler) = TRAY_EVENT_HANDLER.get_or_init(|| None) { + handler(event); + } else { + let _ = TRAY_CHANNEL.0.send(event); + } + } +} + +#[cfg(test)] +mod tests { + + #[cfg(feature = "serde")] + #[test] + fn it_serializes() { + use super::*; + let event = TrayIconEvent::Click { + button: MouseButton::Left, + button_state: MouseButtonState::Down, + id: TrayIconId::new("id"), + position: dpi::PhysicalPosition::default(), + rect: Rect::default(), + }; + + let value = serde_json::to_value(&event).unwrap(); + assert_eq!( + value, + serde_json::json!({ + "type": "Click", + "button": "Left", + "buttonState": "Down", + "id": "id", + "position": { + "x": 0.0, + "y": 0.0, + }, + "rect": { + "size": { + "width": 0, + "height": 0, + }, + "position": { + "x": 0.0, + "y": 0.0, + }, + } + }) + ) + } +} diff --git a/ports/tray-icon/src/platform_impl/gtk/icon.rs b/ports/tray-icon/src/platform_impl/gtk/icon.rs new file mode 100644 index 000000000000..9a9c6dcdefc5 --- /dev/null +++ b/ports/tray-icon/src/platform_impl/gtk/icon.rs @@ -0,0 +1,38 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::{fs::File, io::BufWriter, path::Path}; + +use crate::icon::BadIcon; + +#[derive(Debug, Clone)] +pub struct PlatformIcon { + rgba: Vec, + width: i32, + height: i32, +} + +impl PlatformIcon { + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + Ok(Self { + rgba, + width: width as i32, + height: height as i32, + }) + } + + pub fn write_to_png(&self, path: impl AsRef) -> crate::Result<()> { + let png = File::create(path)?; + let w = &mut BufWriter::new(png); + + let mut encoder = png::Encoder::new(w, self.width as _, self.height as _); + encoder.set_color(png::ColorType::Rgba); + encoder.set_depth(png::BitDepth::Eight); + + let mut writer = encoder.write_header()?; + writer.write_image_data(&self.rgba)?; + + Ok(()) + } +} diff --git a/ports/tray-icon/src/platform_impl/gtk/mod.rs b/ports/tray-icon/src/platform_impl/gtk/mod.rs new file mode 100644 index 000000000000..945544301469 --- /dev/null +++ b/ports/tray-icon/src/platform_impl/gtk/mod.rs @@ -0,0 +1,159 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +mod icon; +use std::path::{Path, PathBuf}; + +use crate::icon::Icon; +pub(crate) use icon::PlatformIcon; + +use crate::{TrayIconAttributes, TrayIconId}; +use libappindicator::{AppIndicator, AppIndicatorStatus}; + +pub struct TrayIcon { + id: TrayIconId, + indicator: AppIndicator, + temp_dir_path: Option, + path: PathBuf, + counter: u32, + menu: Option>, +} + +impl TrayIcon { + pub fn new(id: TrayIconId, attrs: TrayIconAttributes) -> crate::Result { + let mut indicator = AppIndicator::new(&format!("tray-icon tray app {}", id.as_ref()), ""); + indicator.set_status(AppIndicatorStatus::Active); + + let (parent_path, icon_path) = temp_icon_path(attrs.temp_dir_path.as_ref(), &id, 0)?; + + if let Some(icon) = attrs.icon { + icon.inner.write_to_png(&icon_path)?; + } + + indicator.set_icon_theme_path(&parent_path.to_string_lossy()); + indicator.set_icon_full(&icon_path.to_string_lossy(), "icon"); + + if let Some(menu) = &attrs.menu { + indicator.set_menu(&mut menu.gtk_context_menu()); + } + + if let Some(title) = attrs.title { + indicator.set_label(title.as_str(), ""); + } + + Ok(Self { + id, + indicator, + path: icon_path, + temp_dir_path: attrs.temp_dir_path, + counter: 0, + menu: attrs.menu, + }) + } + pub fn set_icon(&mut self, icon: Option) -> crate::Result<()> { + let _ = std::fs::remove_file(&self.path); + + self.counter += 1; + + let (parent_path, icon_path) = + temp_icon_path(self.temp_dir_path.as_ref(), &self.id, self.counter)?; + + if let Some(icon) = icon { + icon.inner.write_to_png(&icon_path)?; + } + + self.indicator + .set_icon_theme_path(&parent_path.to_string_lossy()); + self.indicator + .set_icon_full(&icon_path.to_string_lossy(), "tray icon"); + self.path = icon_path; + + Ok(()) + } + + pub fn set_menu(&mut self, menu: Option>) { + if let Some(menu) = &menu { + self.indicator.set_menu(&mut menu.gtk_context_menu()); + } + self.menu = menu; + } + + pub fn set_tooltip>(&mut self, _tooltip: Option) -> crate::Result<()> { + Ok(()) + } + + pub fn set_title>(&mut self, title: Option) { + self.indicator + .set_label(title.as_ref().map(|t| t.as_ref()).unwrap_or(""), ""); + } + + pub fn set_visible(&mut self, visible: bool) -> crate::Result<()> { + if visible { + self.indicator.set_status(AppIndicatorStatus::Active); + } else { + self.indicator.set_status(AppIndicatorStatus::Passive); + } + + Ok(()) + } + + pub fn set_temp_dir_path>(&mut self, path: Option

) { + self.temp_dir_path = path.map(|p| p.as_ref().to_path_buf()); + } + + pub fn rect(&self) -> Option { + None + } + + pub fn app_indicator(&self) -> &AppIndicator { + &self.indicator + } +} + +impl Drop for TrayIcon { + fn drop(&mut self) { + self.indicator.set_status(AppIndicatorStatus::Passive); + let _ = std::fs::remove_file(&self.path); + } +} + +/// Generates an icon path in one of the following dirs: +/// 1. If `temp_icon_dir` is `Some` use that. +/// 2. `$XDG_RUNTIME_DIR/tray-icon` +/// 3. `/tmp/tray-icon` +fn temp_icon_path( + temp_icon_dir: Option<&PathBuf>, + id: &TrayIconId, + counter: u32, +) -> std::io::Result<(PathBuf, PathBuf)> { + let parent_path = match temp_icon_dir.as_ref() { + Some(path) => path.to_path_buf(), + None => dirs::runtime_dir() + .unwrap_or_else(std::env::temp_dir) + .join("tray-icon"), + }; + + std::fs::create_dir_all(&parent_path)?; + let icon_path = parent_path.join(format!("tray-icon-{}-{}.png", id.as_ref(), counter)); + Ok((parent_path, icon_path)) +} + +#[test] +fn temp_icon_path_preference_order() { + let runtime_dir = option_env!("XDG_RUNTIME_DIR"); + let override_dir = PathBuf::from("/tmp/tao-tests"); + + let (dir1, _file1) = temp_icon_path(Some(&override_dir), &"00".into(), 00).unwrap(); + let (dir2, _file1) = temp_icon_path(None, &"00".into(), 00).unwrap(); + std::env::remove_var("XDG_RUNTIME_DIR"); + let (dir3, _file2) = temp_icon_path(None, &"00".into(), 00).unwrap(); + + assert_eq!(dir1, override_dir); + if let Some(runtime_dir) = runtime_dir { + std::env::set_var("XDG_RUNTIME_DIR", runtime_dir); + assert_eq!(dir2, PathBuf::from(format!("{}/tray-icon", runtime_dir))); + } + + assert_eq!(dir3, PathBuf::from("/tmp/tray-icon")); +} diff --git a/ports/tray-icon/src/platform_impl/linux/icon.rs b/ports/tray-icon/src/platform_impl/linux/icon.rs new file mode 100644 index 000000000000..4cb8d9dbbb62 --- /dev/null +++ b/ports/tray-icon/src/platform_impl/linux/icon.rs @@ -0,0 +1,62 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::icon::BadIcon; + +#[derive(Debug, Clone)] +pub struct PlatformIcon { + argb: Vec, + width: i32, + height: i32, +} + +impl PlatformIcon { + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + if !rgba.len().is_multiple_of(4) { + return Err(BadIcon::ByteCountNotDivisibleBy4 { + byte_count: rgba.len(), + }); + } + + let mut bytes = rgba; + for i in 0..(bytes.len() / 4) { + let j = i * 4; + let a = bytes[j + 3]; + bytes[j + 3] = bytes[j + 2]; + bytes[j + 2] = bytes[j + 1]; + bytes[j + 1] = bytes[j]; + bytes[j] = a; + } + + Ok(Self { + argb: bytes, + width: width as i32, + height: height as i32, + }) + } + + pub fn into_rgba(self) -> (Vec, u32, u32) { + let mut bytes = self.argb; + for i in 0..(bytes.len() / 4) { + let j = i * 4; + let a = bytes[j]; + bytes[j] = bytes[j + 1]; + bytes[j + 1] = bytes[j + 2]; + bytes[j + 2] = bytes[j + 3]; + bytes[j + 3] = a; + } + + (bytes, self.width as u32, self.height as u32) + } +} + +impl From for ksni::Icon { + fn from(icon: PlatformIcon) -> Self { + ksni::Icon { + width: icon.width, + height: icon.height, + data: icon.argb, + } + } +} diff --git a/ports/tray-icon/src/platform_impl/linux/menu.rs b/ports/tray-icon/src/platform_impl/linux/menu.rs new file mode 100644 index 000000000000..75c35ec7ccc5 --- /dev/null +++ b/ports/tray-icon/src/platform_impl/linux/menu.rs @@ -0,0 +1,53 @@ +use std::sync::Arc; + +use arc_swap::ArcSwap; + +use super::tray::Tray; + +pub fn muda_to_ksni_menu_item( + item: Arc>, +) -> ksni::menu::MenuItem { + match &**item.load() { + muda::CompatMenuItem::Standard(menu_item) => { + let id = menu_item.id.clone(); + ksni::menu::StandardItem { + label: menu_item.label.clone(), + enabled: menu_item.enabled, + icon_data: menu_item.icon.clone().unwrap_or_default(), + activate: Box::new(move |_| send_menu_event(&id)), + ..Default::default() + } + .into() + } + muda::CompatMenuItem::Checkmark(check_menu_item) => { + let id = check_menu_item.id.clone(); + ksni::menu::CheckmarkItem { + label: check_menu_item.label.clone(), + enabled: check_menu_item.enabled, + checked: check_menu_item.checked, + activate: Box::new(move |_| send_menu_event(&id)), + ..Default::default() + } + .into() + } + muda::CompatMenuItem::SubMenu(submenu) => ksni::menu::SubMenu { + label: submenu.label.clone(), + enabled: submenu.enabled, + submenu: submenu + .submenu + .iter() + .cloned() + .map(muda_to_ksni_menu_item) + .collect(), + ..Default::default() + } + .into(), + muda::CompatMenuItem::Separator => ksni::menu::MenuItem::Separator, + } +} + +fn send_menu_event(id: &str) { + muda::send_menu_event(muda::MenuEvent { + id: muda::MenuId(id.to_string()), + }) +} diff --git a/ports/tray-icon/src/platform_impl/linux/mod.rs b/ports/tray-icon/src/platform_impl/linux/mod.rs new file mode 100644 index 000000000000..ab43fc32bb63 --- /dev/null +++ b/ports/tray-icon/src/platform_impl/linux/mod.rs @@ -0,0 +1,124 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +mod icon; +mod menu; +mod tray; + +use std::{ + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + thread, +}; + +pub(crate) use icon::PlatformIcon; +use tray::Tray; + +use crate::{icon::Icon, TrayIconAttributes, TrayIconId}; + +pub struct TrayIcon { + tray_handle: ksni::Handle, + shutdown: Arc, +} + +impl TrayIcon { + pub fn new(id: TrayIconId, attrs: TrayIconAttributes) -> crate::Result { + let icon = attrs.icon.map(|icon| icon.inner.into()); + let title = attrs.title.unwrap_or_default(); + let tooltip = attrs.tooltip.unwrap_or_default(); + let menu = attrs + .menu + .as_ref() + .map(|menu| menu.compat_items()) + .unwrap_or_default(); + + let shutdown = Arc::new(AtomicBool::new(false)); + let tray_service = ksni::TrayService::new(Tray::new(id, icon, title, tooltip, menu)); + let tray_handle = tray_service.handle(); + tray_service.spawn(); + + let update_tray_handle = tray_handle.clone(); + let update_shutdown = shutdown.clone(); + thread::spawn(move || { + while muda::recv_menu_update().is_ok() { + if update_shutdown.load(Ordering::Relaxed) { + break; + } + update_tray_handle.update(|_| {}); + } + }); + + Ok(Self { + tray_handle, + shutdown, + }) + } + + pub fn set_icon(&mut self, icon: Option) -> crate::Result<()> { + let icon = icon.map(|icon| icon.inner.into()); + self.tray_handle.update(|tray| { + tray.set_icon(icon); + }); + Ok(()) + } + + pub fn set_menu(&mut self, menu: Option>) { + let menu = menu + .as_ref() + .map(|menu| menu.compat_items()) + .unwrap_or_default(); + self.tray_handle.update(|tray| { + tray.set_menu(menu); + }); + } + + pub fn set_tooltip>(&mut self, tooltip: Option) -> crate::Result<()> { + let tooltip = tooltip + .as_ref() + .map(AsRef::as_ref) + .unwrap_or_default() + .to_string(); + self.tray_handle.update(|tray| { + tray.set_tooltip(tooltip); + }); + Ok(()) + } + + pub fn set_title>(&mut self, title: Option) { + let title = title + .as_ref() + .map(AsRef::as_ref) + .unwrap_or_default() + .to_string(); + self.tray_handle.update(|tray| { + tray.set_title(title); + }); + } + + pub fn set_visible(&mut self, visible: bool) -> crate::Result<()> { + self.tray_handle.update(|tray| { + if visible { + tray.set_status(ksni::Status::Active); + } else { + tray.set_status(ksni::Status::Passive); + } + }); + Ok(()) + } + + pub fn set_temp_dir_path>(&mut self, _path: Option

) {} + + pub fn rect(&self) -> Option { + None + } +} + +impl Drop for TrayIcon { + fn drop(&mut self) { + self.shutdown.store(true, Ordering::Relaxed); + muda::send_menu_update(); + } +} diff --git a/ports/tray-icon/src/platform_impl/linux/tray.rs b/ports/tray-icon/src/platform_impl/linux/tray.rs new file mode 100644 index 000000000000..0b8eb036611d --- /dev/null +++ b/ports/tray-icon/src/platform_impl/linux/tray.rs @@ -0,0 +1,112 @@ +use std::sync::Arc; + +use arc_swap::ArcSwap; + +use crate::{MouseButton, MouseButtonState, TrayIconEvent, TrayIconId}; + +use super::menu::muda_to_ksni_menu_item; + +pub struct Tray { + id: TrayIconId, + icon: Vec, + title: String, + status: ksni::Status, + tooltip: String, + menu: Vec>>, +} + +impl Tray { + pub fn new( + id: TrayIconId, + icon: Option, + title: String, + tooltip: String, + menu: Vec>>, + ) -> Self { + Self { + id, + icon: icon.into_iter().collect(), + title, + status: ksni::Status::Active, + tooltip, + menu, + } + } + + pub fn set_icon(&mut self, icon: Option) { + self.icon = icon.into_iter().collect(); + } + + pub fn set_title(&mut self, title: String) { + self.title = title; + } + + pub fn set_status(&mut self, status: ksni::Status) { + self.status = status; + } + + pub fn set_tooltip(&mut self, tooltip: String) { + self.tooltip = tooltip; + } + + pub fn set_menu(&mut self, menu: Vec>>) { + self.menu = menu; + } +} + +impl ksni::Tray for Tray { + fn id(&self) -> String { + self.id.0.clone() + } + + fn status(&self) -> ksni::Status { + self.status + } + + fn icon_pixmap(&self) -> Vec { + self.icon.clone() + } + + fn title(&self) -> String { + self.title.clone() + } + + fn tool_tip(&self) -> ksni::ToolTip { + ksni::ToolTip { + icon_pixmap: self.icon.clone(), + title: self.title.clone(), + description: self.tooltip.clone(), + ..Default::default() + } + } + + fn menu(&self) -> Vec> { + self.menu + .iter() + .cloned() + .map(muda_to_ksni_menu_item) + .collect() + } + + fn activate(&mut self, x: i32, y: i32) { + let event = TrayIconEvent::Click { + id: self.id.clone(), + position: muda::dpi::PhysicalPosition::new(x as f64, y as f64), + rect: Default::default(), + button: MouseButton::Left, + button_state: MouseButtonState::Up, + }; + TrayIconEvent::send(event); + } + + fn secondary_activate(&mut self, x: i32, y: i32) { + let event = TrayIconEvent::Click { + id: self.id.clone(), + position: muda::dpi::PhysicalPosition::new(x as f64, y as f64), + rect: Default::default(), + button: MouseButton::Middle, + button_state: MouseButtonState::Up, + }; + TrayIconEvent::send(event); + } +} diff --git a/ports/tray-icon/src/platform_impl/macos/icon.rs b/ports/tray-icon/src/platform_impl/macos/icon.rs new file mode 100644 index 000000000000..a639379955f4 --- /dev/null +++ b/ports/tray-icon/src/platform_impl/macos/icon.rs @@ -0,0 +1,35 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::icon::{BadIcon, RgbaIcon}; +use std::io::Cursor; + +#[derive(Debug, Clone)] +pub struct PlatformIcon(RgbaIcon); + +impl PlatformIcon { + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + Ok(PlatformIcon(RgbaIcon::from_rgba(rgba, width, height)?)) + } + + pub fn get_size(&self) -> (u32, u32) { + (self.0.width, self.0.height) + } + + pub fn to_png(&self) -> crate::Result> { + let mut png = Vec::new(); + + { + let mut encoder = + png::Encoder::new(Cursor::new(&mut png), self.0.width as _, self.0.height as _); + encoder.set_color(png::ColorType::Rgba); + encoder.set_depth(png::BitDepth::Eight); + + let mut writer = encoder.write_header()?; + writer.write_image_data(&self.0.rgba)?; + } + + Ok(png) + } +} diff --git a/ports/tray-icon/src/platform_impl/macos/mod.rs b/ports/tray-icon/src/platform_impl/macos/mod.rs new file mode 100644 index 000000000000..a3517c81a592 --- /dev/null +++ b/ports/tray-icon/src/platform_impl/macos/mod.rs @@ -0,0 +1,612 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +mod icon; +use std::cell::{Cell, RefCell}; + +use objc2::rc::Retained; +use objc2::{define_class, msg_send, AllocAnyThread, DeclaredClass, Message}; +use objc2_app_kit::{ + NSCellImagePosition, NSEvent, NSImage, NSMenu, NSStatusBar, NSStatusItem, NSTrackingArea, + NSTrackingAreaOptions, NSVariableStatusItemLength, NSView, NSWindow, +}; +use objc2_core_foundation::{CGPoint, CGRect, CGSize}; +use objc2_core_graphics::{CGDisplayPixelsHigh, CGMainDisplayID}; +use objc2_foundation::{MainThreadMarker, NSData, NSSize, NSString}; + +pub(crate) use self::icon::PlatformIcon; +use crate::Error; +use crate::{ + icon::Icon, menu, MouseButton, MouseButtonState, Rect, TrayIconAttributes, TrayIconEvent, + TrayIconId, +}; + +pub struct TrayIcon { + ns_status_item: Option>, + tray_target: Option>, + id: TrayIconId, + attrs: TrayIconAttributes, + mtm: MainThreadMarker, +} + +impl TrayIcon { + pub fn new(id: TrayIconId, attrs: TrayIconAttributes) -> crate::Result { + let mtm = MainThreadMarker::new().ok_or(Error::NotMainThread)?; + let (ns_status_item, tray_target) = Self::create(&id, &attrs, mtm)?; + + let tray_icon = Self { + ns_status_item: Some(ns_status_item), + tray_target: Some(tray_target), + id, + attrs, + mtm, + }; + + Ok(tray_icon) + } + + fn create( + id: &TrayIconId, + attrs: &TrayIconAttributes, + mtm: MainThreadMarker, + ) -> crate::Result<(Retained, Retained)> { + let ns_status_item = unsafe { + NSStatusBar::systemStatusBar().statusItemWithLength(NSVariableStatusItemLength) + }; + + set_icon_for_ns_status_item_button( + &ns_status_item, + attrs.icon.as_ref(), + attrs.icon_is_template, + mtm, + )?; + + if let Some(menu) = &attrs.menu { + unsafe { + ns_status_item.setMenu((menu.ns_menu() as *const NSMenu).as_ref()); + } + } + + Self::set_tooltip_inner(&ns_status_item, attrs.tooltip.as_deref(), mtm)?; + Self::set_title_inner(&ns_status_item, attrs.title.as_deref(), mtm); + + let tray_target = unsafe { + let button = ns_status_item.button(mtm).unwrap(); + + let frame = button.frame(); + + let target = mtm.alloc().set_ivars(TrayTargetIvars { + id: NSString::from_str(&id.0), + menu: RefCell::new( + attrs + .menu + .as_deref() + .and_then(|menu| Retained::retain(menu.ns_menu().cast::())), + ), + status_item: ns_status_item.retain(), + menu_on_left_click: Cell::new(attrs.menu_on_left_click), + menu_on_right_click: Cell::new(attrs.menu_on_right_click), + }); + let tray_target: Retained = msg_send![super(target), initWithFrame: frame]; + tray_target.setWantsLayer(true); + + button.addSubview(&tray_target); + + tray_target + }; + + Ok((ns_status_item, tray_target)) + } + + fn remove(&mut self) { + if let (Some(ns_status_item), Some(tray_target)) = (&self.ns_status_item, &self.tray_target) + { + unsafe { + NSStatusBar::systemStatusBar().removeStatusItem(ns_status_item); + tray_target.removeFromSuperview(); + } + } + + self.ns_status_item = None; + self.tray_target = None; + } + + pub fn set_icon(&mut self, icon: Option) -> crate::Result<()> { + if let (Some(ns_status_item), Some(tray_target)) = (&self.ns_status_item, &self.tray_target) + { + set_icon_for_ns_status_item_button(ns_status_item, icon.as_ref(), false, self.mtm)?; + tray_target.update_dimensions(); + } + self.attrs.icon = icon; + Ok(()) + } + + pub fn set_menu(&mut self, menu: Option>) { + if let (Some(ns_status_item), Some(tray_target)) = (&self.ns_status_item, &self.tray_target) + { + unsafe { + let menu = menu + .as_ref() + .and_then(|m| m.ns_menu().cast::().as_ref()) + .map(|menu| menu.retain()); + ns_status_item.setMenu(menu.as_deref()); + if let Some(menu) = &menu { + let () = msg_send![menu, setDelegate: &**ns_status_item]; + } + + *tray_target.ivars().menu.borrow_mut() = menu; + } + } + self.attrs.menu = menu; + } + + pub fn set_tooltip>(&mut self, tooltip: Option) -> crate::Result<()> { + let tooltip = tooltip.map(|s| s.as_ref().to_string()); + if let (Some(ns_status_item), Some(tray_target)) = (&self.ns_status_item, &self.tray_target) + { + Self::set_tooltip_inner(ns_status_item, tooltip.as_deref(), self.mtm)?; + tray_target.update_dimensions(); + } + self.attrs.tooltip = tooltip; + Ok(()) + } + + fn set_tooltip_inner>( + ns_status_item: &NSStatusItem, + tooltip: Option, + mtm: MainThreadMarker, + ) -> crate::Result<()> { + unsafe { + let tooltip = tooltip.map(|tooltip| NSString::from_str(tooltip.as_ref())); + if let Some(button) = ns_status_item.button(mtm) { + button.setToolTip(tooltip.as_deref()); + } + } + Ok(()) + } + + pub fn set_title>(&mut self, title: Option) { + let title = title.map(|s| s.as_ref().to_string()); + if let (Some(ns_status_item), Some(tray_target)) = (&self.ns_status_item, &self.tray_target) + { + Self::set_title_inner(ns_status_item, title.as_deref(), self.mtm); + tray_target.update_dimensions(); + } + self.attrs.title = title; + } + + fn set_title_inner>( + ns_status_item: &NSStatusItem, + title: Option, + mtm: MainThreadMarker, + ) { + if let Some(title) = title { + unsafe { + if let Some(button) = ns_status_item.button(mtm) { + button.setTitle(&NSString::from_str(title.as_ref())); + } + } + } + } + + pub fn set_visible(&mut self, visible: bool) -> crate::Result<()> { + if visible { + if self.ns_status_item.is_none() { + let (ns_status_item, tray_target) = Self::create(&self.id, &self.attrs, self.mtm)?; + self.ns_status_item = Some(ns_status_item); + self.tray_target = Some(tray_target); + } + } else { + self.remove(); + } + + Ok(()) + } + + pub fn set_icon_as_template(&mut self, is_template: bool) { + if let Some(ns_status_item) = &self.ns_status_item { + unsafe { + let button = ns_status_item.button(self.mtm).unwrap(); + if let Some(nsimage) = button.image() { + nsimage.setTemplate(is_template); + button.setImage(Some(&nsimage)); + } + } + } + self.attrs.icon_is_template = is_template; + } + + pub fn set_icon_with_as_template( + &mut self, + icon: Option, + is_template: bool, + ) -> crate::Result<()> { + if let (Some(ns_status_item), Some(tray_target)) = (&self.ns_status_item, &self.tray_target) + { + set_icon_for_ns_status_item_button( + ns_status_item, + icon.as_ref(), + is_template, + self.mtm, + )?; + tray_target.update_dimensions(); + } + self.attrs.icon = icon; + self.attrs.icon_is_template = is_template; + Ok(()) + } + + pub fn set_show_menu_on_left_click(&mut self, enable: bool) { + if let Some(tray_target) = &self.tray_target { + tray_target.ivars().menu_on_left_click.set(enable); + } + self.attrs.menu_on_left_click = enable; + } + + pub fn set_show_menu_on_right_click(&mut self, enable: bool) { + if let Some(tray_target) = &self.tray_target { + tray_target.ivars().menu_on_right_click.set(enable); + } + self.attrs.menu_on_right_click = enable; + } + + pub fn show_menu(&self) { + if let Some(ns_status_item) = &self.ns_status_item { + unsafe { + let button = ns_status_item.button(self.mtm).unwrap(); + button.performClick(None); + } + } + } + + pub fn rect(&self) -> Option { + let ns_status_item = self.ns_status_item.as_deref()?; + unsafe { + let button = ns_status_item.button(self.mtm).unwrap(); + let window = button.window(); + window.map(|window| get_tray_rect(&window)) + } + } + + pub fn ns_status_item(&self) -> Option<&Retained> { + self.ns_status_item.as_ref() + } +} + +impl Drop for TrayIcon { + fn drop(&mut self) { + self.remove() + } +} + +fn set_icon_for_ns_status_item_button( + ns_status_item: &NSStatusItem, + icon: Option<&Icon>, + icon_is_template: bool, + mtm: MainThreadMarker, +) -> crate::Result<()> { + let button = unsafe { ns_status_item.button(mtm).unwrap() }; + + if let Some(icon) = icon { + let png_icon = icon.inner.to_png()?; + + let (width, height) = icon.inner.get_size(); + + let icon_height: f64 = 18.0; + let icon_width: f64 = (width as f64) / (height as f64 / icon_height); + + unsafe { + // build our icon + let nsdata = NSData::from_vec(png_icon); + + let nsimage = NSImage::initWithData(NSImage::alloc(), &nsdata).unwrap(); + let new_size = NSSize::new(icon_width, icon_height); + + button.setImage(Some(&nsimage)); + nsimage.setSize(new_size); + // The image is to the right of the title + button.setImagePosition(NSCellImagePosition::ImageLeft); + nsimage.setTemplate(icon_is_template); + } + } else { + unsafe { button.setImage(None) }; + } + + Ok(()) +} + +#[derive(Debug)] +struct TrayTargetIvars { + id: Retained, + menu: RefCell>>, + status_item: Retained, + menu_on_left_click: Cell, + menu_on_right_click: Cell, +} + +define_class!( + #[unsafe(super(NSView))] + #[name = "TaoTrayTarget"] + #[ivars = TrayTargetIvars] + struct TrayTarget; + + /// Mouse events on NSResponder + impl TrayTarget { + #[unsafe(method(mouseDown:))] + fn on_mouse_down(&self, event: &NSEvent) { + send_mouse_event( + self, + event, + MouseEventType::Click, + Some(MouseClickEvent { + button: MouseButton::Left, + state: MouseButtonState::Down, + }), + ); + on_tray_click(self, MouseButton::Left); + } + + #[unsafe(method(mouseUp:))] + fn on_mouse_up(&self, event: &NSEvent) { + let mtm = MainThreadMarker::from(self); + unsafe { + let button = self.ivars().status_item.button(mtm).unwrap(); + button.highlight(false); + } + send_mouse_event( + self, + event, + MouseEventType::Click, + Some(MouseClickEvent { + button: MouseButton::Left, + state: MouseButtonState::Up, + }), + ); + } + + #[unsafe(method(rightMouseDown:))] + fn on_right_mouse_down(&self, event: &NSEvent) { + send_mouse_event( + self, + event, + MouseEventType::Click, + Some(MouseClickEvent { + button: MouseButton::Right, + state: MouseButtonState::Down, + }), + ); + on_tray_click(self, MouseButton::Right); + } + + #[unsafe(method(rightMouseUp:))] + fn on_right_mouse_up(&self, event: &NSEvent) { + send_mouse_event( + self, + event, + MouseEventType::Click, + Some(MouseClickEvent { + button: MouseButton::Right, + state: MouseButtonState::Up, + }), + ); + } + + #[unsafe(method(otherMouseDown:))] + fn on_other_mouse_down(&self, event: &NSEvent) { + let button_number = unsafe { event.buttonNumber() }; + if button_number == 2 { + send_mouse_event( + self, + event, + MouseEventType::Click, + Some(MouseClickEvent { + button: MouseButton::Middle, + state: MouseButtonState::Down, + }), + ); + } + } + + #[unsafe(method(otherMouseUp:))] + fn on_other_mouse_up(&self, event: &NSEvent) { + let button_number = unsafe { event.buttonNumber() }; + if button_number == 2 { + send_mouse_event( + self, + event, + MouseEventType::Click, + Some(MouseClickEvent { + button: MouseButton::Middle, + state: MouseButtonState::Up, + }), + ); + } + } + + #[unsafe(method(mouseEntered:))] + fn on_mouse_entered(&self, event: &NSEvent) { + send_mouse_event(self, event, MouseEventType::Enter, None); + } + + #[unsafe(method(mouseExited:))] + fn on_mouse_exited(&self, event: &NSEvent) { + send_mouse_event(self, event, MouseEventType::Leave, None); + } + + #[unsafe(method(mouseMoved:))] + fn on_mouse_moved(&self, event: &NSEvent) { + send_mouse_event(self, event, MouseEventType::Move, None); + } + } + + /// Tracking mouse enter/exit/move events + impl TrayTarget { + #[unsafe(method(updateTrackingAreas))] + fn update_tracking_areas(&self) { + unsafe { + let areas = self.trackingAreas(); + for area in areas { + self.removeTrackingArea(&area); + } + + let _: () = msg_send![super(self), updateTrackingAreas]; + + let options = NSTrackingAreaOptions::MouseEnteredAndExited + | NSTrackingAreaOptions::MouseMoved + | NSTrackingAreaOptions::ActiveAlways + | NSTrackingAreaOptions::InVisibleRect; + let rect = CGRect { + origin: CGPoint { x: 0.0, y: 0.0 }, + size: CGSize { + width: 0.0, + height: 0.0, + }, + }; + let area = NSTrackingArea::initWithRect_options_owner_userInfo( + NSTrackingArea::alloc(), + rect, + options, + Some(self), + None, + ); + self.addTrackingArea(&area); + } + } + } +); + +impl TrayTarget { + fn update_dimensions(&self) { + let mtm = MainThreadMarker::from(self); + unsafe { + let button = self.ivars().status_item.button(mtm).unwrap(); + self.setFrame(button.frame()); + } + } +} + +fn on_tray_click(this: &TrayTarget, button: MouseButton) { + let mtm = MainThreadMarker::from(this); + unsafe { + let ns_button = this.ivars().status_item.button(mtm).unwrap(); + + let menu_on_left_click = this.ivars().menu_on_left_click.get(); + let menu_on_right_click = this.ivars().menu_on_right_click.get(); + if (menu_on_right_click && button == MouseButton::Right) + || (menu_on_left_click && button == MouseButton::Left) + { + let has_items = if let Some(menu) = &*this.ivars().menu.borrow() { + menu.numberOfItems() > 0 + } else { + false + }; + if has_items { + ns_button.performClick(None); + } else { + ns_button.highlight(true); + } + } else { + ns_button.highlight(true); + } + } +} + +fn get_tray_rect(window: &NSWindow) -> Rect { + let frame = window.frame(); + let scale_factor = window.backingScaleFactor(); + + Rect { + size: crate::dpi::LogicalSize::new(frame.size.width, frame.size.height) + .to_physical(scale_factor), + position: crate::dpi::LogicalPosition::new( + frame.origin.x, + flip_window_screen_coordinates(frame.origin.y) - frame.size.height, + ) + .to_physical(scale_factor), + } +} + +fn send_mouse_event( + this: &TrayTarget, + event: &NSEvent, + mouse_event_type: MouseEventType, + click_event: Option, +) { + let mtm = MainThreadMarker::from(this); + unsafe { + let tray_id = TrayIconId(this.ivars().id.to_string()); + + // icon position & size + let window = event.window(mtm).unwrap(); + let icon_rect = get_tray_rect(&window); + + // cursor position + let mouse_location = NSEvent::mouseLocation(); + let scale_factor = window.backingScaleFactor(); + let cursor_position = crate::dpi::LogicalPosition::new( + mouse_location.x, + flip_window_screen_coordinates(mouse_location.y), + ) + .to_physical(scale_factor); + + let event = match mouse_event_type { + MouseEventType::Click => { + let click_event = click_event.unwrap(); + TrayIconEvent::Click { + id: tray_id, + position: cursor_position, + rect: icon_rect, + button: click_event.button, + button_state: click_event.state, + } + } + MouseEventType::Enter => TrayIconEvent::Enter { + id: tray_id, + position: cursor_position, + rect: icon_rect, + }, + MouseEventType::Leave => TrayIconEvent::Leave { + id: tray_id, + position: cursor_position, + rect: icon_rect, + }, + MouseEventType::Move => TrayIconEvent::Move { + id: tray_id, + position: cursor_position, + rect: icon_rect, + }, + }; + + TrayIconEvent::send(event); + } +} + +#[derive(Debug)] +enum MouseEventType { + Click, + Enter, + Leave, + Move, +} + +#[derive(Debug)] +struct MouseClickEvent { + button: MouseButton, + state: MouseButtonState, +} + +/// Core graphics screen coordinates are relative to the top-left corner of +/// the so-called "main" display, with y increasing downwards - which is +/// exactly what we want in Winit. +/// +/// However, `NSWindow` and `NSScreen` changes these coordinates to: +/// 1. Be relative to the bottom-left corner of the "main" screen. +/// 2. Be relative to the bottom-left corner of the window/screen itself. +/// 3. Have y increasing upwards. +/// +/// This conversion happens to be symmetric, so we only need this one function +/// to convert between the two coordinate systems. +fn flip_window_screen_coordinates(y: f64) -> f64 { + unsafe { CGDisplayPixelsHigh(CGMainDisplayID()) as f64 - y } +} diff --git a/ports/tray-icon/src/platform_impl/mod.rs b/ports/tray-icon/src/platform_impl/mod.rs new file mode 100644 index 000000000000..5fb657afeb32 --- /dev/null +++ b/ports/tray-icon/src/platform_impl/mod.rs @@ -0,0 +1,26 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#[cfg(target_os = "windows")] +#[path = "windows/mod.rs"] +mod platform; +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +#[path = "gtk/mod.rs"] +mod platform; +#[cfg(all(target_os = "linux", not(feature = "linux-ksni")))] +#[path = "gtk/mod.rs"] +mod platform; +#[cfg(all(target_os = "linux", feature = "linux-ksni"))] +#[path = "linux/mod.rs"] +mod platform; +#[cfg(target_os = "macos")] +#[path = "macos/mod.rs"] +mod platform; + +pub(crate) use self::platform::*; diff --git a/ports/tray-icon/src/platform_impl/windows/icon.rs b/ports/tray-icon/src/platform_impl/windows/icon.rs new file mode 100644 index 000000000000..deaa50ccb3bf --- /dev/null +++ b/ports/tray-icon/src/platform_impl/windows/icon.rs @@ -0,0 +1,158 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +// taken from https://github.com/rust-windowing/winit/blob/92fdf5ba85f920262a61cee4590f4a11ad5738d1/src/platform_impl/windows/icon.rs + +use std::{fmt, io, mem, path::Path, sync::Arc}; + +use windows_sys::{ + core::PCWSTR, + Win32::UI::WindowsAndMessaging::{ + CreateIcon, DestroyIcon, LoadImageW, HICON, IMAGE_ICON, LR_DEFAULTSIZE, LR_LOADFROMFILE, + }, +}; + +use crate::icon::*; + +use super::util; + +impl Pixel { + fn convert_to_bgra(&mut self) { + mem::swap(&mut self.r, &mut self.b); + } +} + +impl RgbaIcon { + fn into_windows_icon(self) -> Result { + let rgba = self.rgba; + let pixel_count = rgba.len() / PIXEL_SIZE; + let mut and_mask = Vec::with_capacity(pixel_count); + let pixels = + unsafe { std::slice::from_raw_parts_mut(rgba.as_ptr() as *mut Pixel, pixel_count) }; + for pixel in pixels { + and_mask.push(pixel.a.wrapping_sub(u8::MAX)); // invert alpha channel + pixel.convert_to_bgra(); + } + assert_eq!(and_mask.len(), pixel_count); + let handle = unsafe { + CreateIcon( + std::ptr::null_mut(), + self.width as i32, + self.height as i32, + 1, + (PIXEL_SIZE * 8) as u8, + and_mask.as_ptr(), + rgba.as_ptr(), + ) + }; + if !handle.is_null() { + Ok(WinIcon::from_handle(handle)) + } else { + Err(BadIcon::OsError(io::Error::last_os_error())) + } + } +} + +#[derive(Debug)] +struct RaiiIcon { + handle: HICON, +} + +#[derive(Clone)] +pub(crate) struct WinIcon { + inner: Arc, +} + +unsafe impl Send for WinIcon {} + +impl WinIcon { + pub fn as_raw_handle(&self) -> HICON { + self.inner.handle + } + + pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + let rgba_icon = RgbaIcon::from_rgba(rgba, width, height)?; + rgba_icon.into_windows_icon() + } + + pub(crate) fn from_handle(handle: HICON) -> Self { + Self { + #[allow(clippy::arc_with_non_send_sync)] + inner: Arc::new(RaiiIcon { handle }), + } + } + + pub(crate) fn from_path>( + path: P, + size: Option<(u32, u32)>, + ) -> Result { + // width / height of 0 along with LR_DEFAULTSIZE tells windows to load the default icon size + let (width, height) = size.unwrap_or((0, 0)); + + let wide_path = util::encode_wide(path.as_ref()); + + let handle = unsafe { + LoadImageW( + std::ptr::null_mut(), + wide_path.as_ptr(), + IMAGE_ICON, + width as i32, + height as i32, + LR_DEFAULTSIZE | LR_LOADFROMFILE, + ) + }; + if !handle.is_null() { + Ok(WinIcon::from_handle(handle as HICON)) + } else { + Err(BadIcon::OsError(io::Error::last_os_error())) + } + } + + fn from_resource_inner_name(name: PCWSTR, size: Option<(u32, u32)>) -> Result { + // width / height of 0 along with LR_DEFAULTSIZE tells windows to load the default icon size + let (width, height) = size.unwrap_or((0, 0)); + let handle = unsafe { + LoadImageW( + util::get_instance_handle(), + name, + IMAGE_ICON, + width as i32, + height as i32, + LR_DEFAULTSIZE, + ) + }; + if !handle.is_null() { + Ok(WinIcon::from_handle(handle as HICON)) + } else { + Err(BadIcon::OsError(io::Error::last_os_error())) + } + } + + pub(crate) fn from_resource( + resource_id: u16, + size: Option<(u32, u32)>, + ) -> Result { + Self::from_resource_inner_name(resource_id as PCWSTR, size) + } + + pub(crate) fn from_resource_name( + resource_name: &str, + size: Option<(u32, u32)>, + ) -> Result { + let wide_name = util::encode_wide(resource_name); + Self::from_resource_inner_name(wide_name.as_ptr(), size) + } +} + +impl Drop for RaiiIcon { + fn drop(&mut self) { + unsafe { DestroyIcon(self.handle) }; + } +} + +impl fmt::Debug for WinIcon { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + (*self.inner).fmt(formatter) + } +} diff --git a/ports/tray-icon/src/platform_impl/windows/mod.rs b/ports/tray-icon/src/platform_impl/windows/mod.rs new file mode 100644 index 000000000000..b45b56d4cdc5 --- /dev/null +++ b/ports/tray-icon/src/platform_impl/windows/mod.rs @@ -0,0 +1,658 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +mod icon; +mod util; +use std::{mem::size_of, ptr}; + +use once_cell::sync::Lazy; +use windows_sys::{ + s, + Win32::{ + Foundation::{FALSE, HWND, LPARAM, LRESULT, POINT, RECT, S_OK, TRUE, WPARAM}, + UI::{ + Shell::{ + Shell_NotifyIconGetRect, Shell_NotifyIconW, NIF_ICON, NIF_MESSAGE, NIF_STATE, + NIF_TIP, NIM_ADD, NIM_DELETE, NIM_MODIFY, NIS_HIDDEN, NOTIFYICONDATAW, + NOTIFYICONIDENTIFIER, + }, + WindowsAndMessaging::{ + ChangeWindowMessageFilterEx, CreateWindowExW, DefWindowProcW, DestroyWindow, + GetCursorPos, KillTimer, PostMessageW, RegisterClassW, RegisterWindowMessageA, + SendMessageW, SetForegroundWindow, SetTimer, TrackPopupMenu, CREATESTRUCTW, + CW_USEDEFAULT, GWL_USERDATA, HICON, HMENU, MSGFLT_ALLOW, TPM_BOTTOMALIGN, + TPM_LEFTALIGN, WM_CREATE, WM_DESTROY, WM_LBUTTONDBLCLK, WM_LBUTTONDOWN, + WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEMOVE, + WM_NCCREATE, WM_NULL, WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_TIMER, + WNDCLASSW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, + WS_OVERLAPPED, + }, + }, + }, +}; + +use crate::{ + dpi::PhysicalPosition, icon::Icon, menu, MouseButton, MouseButtonState, Rect, + TrayIconAttributes, TrayIconEvent, TrayIconId, COUNTER, +}; + +pub(crate) use self::icon::WinIcon as PlatformIcon; + +const WM_USER_TRAYICON: u32 = 6002; +const WM_USER_UPDATE_TRAYMENU: u32 = 6003; +const WM_USER_UPDATE_TRAYICON: u32 = 6004; +const WM_USER_SHOW_TRAYICON: u32 = 6005; +const WM_USER_UPDATE_TRAYTOOLTIP: u32 = 6006; +const WM_USER_LEAVE_TIMER_ID: u32 = 6007; +const WM_USER_SHOW_MENU_ON_LEFT_CLICK: u32 = 6008; +const WM_USER_SHOW_MENU_ON_RIGHT_CLICK: u32 = 6009; +/// When the taskbar is created, it registers a message with the "TaskbarCreated" string and then broadcasts this message to all top-level windows +/// When the application receives this message, it should assume that any taskbar icons it added have been removed and add them again. +static S_U_TASKBAR_RESTART: Lazy = + Lazy::new(|| unsafe { RegisterWindowMessageA(s!("TaskbarCreated")) }); + +struct TrayUserData { + internal_id: u32, + id: TrayIconId, + hwnd: HWND, + hpopupmenu: Option, + icon: Option, + tooltip: Option, + entered: bool, + last_position: Option>, + menu_on_left_click: bool, + menu_on_right_click: bool, + visible: bool, +} + +impl TrayUserData { + fn set_tray_visible(&mut self, visible: bool) { + self.visible = visible; + let nid = NOTIFYICONDATAW { + uFlags: NIF_STATE, + hWnd: self.hwnd, + uID: self.internal_id, + dwState: if visible { 0 } else { NIS_HIDDEN }, + dwStateMask: NIS_HIDDEN, + cbSize: size_of::() as u32, + ..Default::default() + }; + unsafe { Shell_NotifyIconW(NIM_MODIFY, &nid) }; + } +} + +pub struct TrayIcon { + hwnd: HWND, + menu: Option>, + internal_id: u32, +} + +impl TrayIcon { + pub fn new(id: TrayIconId, attrs: TrayIconAttributes) -> crate::Result { + let internal_id = COUNTER.next(); + + let class_name = util::encode_wide("tray_icon_app"); + unsafe { + let hinstance = util::get_instance_handle(); + + let wnd_class = WNDCLASSW { + lpfnWndProc: Some(tray_proc), + lpszClassName: class_name.as_ptr(), + hInstance: hinstance, + ..std::mem::zeroed() + }; + + RegisterClassW(&wnd_class); + + let traydata = TrayUserData { + id, + internal_id, + hwnd: std::ptr::null_mut(), + hpopupmenu: attrs.menu.as_ref().map(|m| m.hpopupmenu() as _), + icon: attrs.icon.clone(), + tooltip: attrs.tooltip.clone(), + entered: false, + last_position: None, + menu_on_left_click: attrs.menu_on_left_click, + menu_on_right_click: attrs.menu_on_right_click, + visible: true, + }; + + let hwnd = CreateWindowExW( + WS_EX_NOACTIVATE | WS_EX_TRANSPARENT | WS_EX_LAYERED | + // WS_EX_TOOLWINDOW prevents this window from ever showing up in the taskbar, which + // we want to avoid. If you remove this style, this window won't show up in the + // taskbar *initially*, but it can show up at some later point. This can sometimes + // happen on its own after several hours have passed, although this has proven + // difficult to reproduce. Alternatively, it can be manually triggered by killing + // `explorer.exe` and then starting the process back up. + // It is unclear why the bug is triggered by waiting for several hours. + WS_EX_TOOLWINDOW, + class_name.as_ptr(), + ptr::null(), + WS_OVERLAPPED, + CW_USEDEFAULT, + 0, + CW_USEDEFAULT, + 0, + std::ptr::null_mut(), + std::ptr::null_mut(), + hinstance, + Box::into_raw(Box::new(traydata)) as _, + ); + if hwnd.is_null() { + return Err(crate::Error::OsError(std::io::Error::last_os_error())); + } + + // Allow "TaskbarCreated" through UIPI so elevated apps can re-register on explorer restart. + ChangeWindowMessageFilterEx(hwnd, *S_U_TASKBAR_RESTART, MSGFLT_ALLOW, ptr::null_mut()); + + let hicon = attrs.icon.as_ref().map(|i| i.inner.as_raw_handle()); + + if !register_tray_icon(hwnd, internal_id, &hicon, &attrs.tooltip, true) { + // Explorer/taskbar may not be ready yet (e.g., app starts before explorer.exe). + // Keep the window alive and wait for TaskbarCreated to re-register. + } + + if let Some(menu) = &attrs.menu { + menu.attach_menu_subclass_for_hwnd(hwnd as _); + } + + Ok(Self { + hwnd, + internal_id, + menu: attrs.menu, + }) + } + } + + pub fn set_icon(&mut self, icon: Option) -> crate::Result<()> { + unsafe { + let mut nid = NOTIFYICONDATAW { + uFlags: NIF_ICON, + hWnd: self.hwnd, + uID: self.internal_id, + cbSize: size_of::() as u32, + ..std::mem::zeroed() + }; + + if let Some(hicon) = icon.as_ref().map(|i| i.inner.as_raw_handle()) { + nid.hIcon = hicon; + } + + if Shell_NotifyIconW(NIM_MODIFY, &nid) == 0 { + return Err(crate::Error::OsError(std::io::Error::last_os_error())); + } + + // send the new icon to the subclass proc to store it in the tray data + SendMessageW( + self.hwnd, + WM_USER_UPDATE_TRAYICON, + Box::into_raw(Box::new(icon)) as _, + 0, + ); + } + + Ok(()) + } + + pub fn set_menu(&mut self, menu: Option>) { + // Safety: self.hwnd is valid as long as as the TrayIcon is + if let Some(menu) = &self.menu { + unsafe { menu.detach_menu_subclass_from_hwnd(self.hwnd as _) }; + } + if let Some(menu) = &menu { + unsafe { menu.attach_menu_subclass_for_hwnd(self.hwnd as _) }; + } + + unsafe { + // send the new menu to the subclass proc where we will update there + SendMessageW( + self.hwnd, + WM_USER_UPDATE_TRAYMENU, + Box::into_raw(Box::new(menu.as_ref().map(|m| m.hpopupmenu()))) as _, + 0, + ); + } + + self.menu = menu; + } + + pub fn set_tooltip>(&mut self, tooltip: Option) -> crate::Result<()> { + unsafe { + let mut nid = NOTIFYICONDATAW { + uFlags: NIF_TIP, + hWnd: self.hwnd, + uID: self.internal_id, + cbSize: size_of::() as u32, + ..std::mem::zeroed() + }; + if let Some(tooltip) = &tooltip { + let tip = util::encode_wide(tooltip.as_ref()); + #[allow(clippy::manual_memcpy)] + for i in 0..tip.len().min(128) { + nid.szTip[i] = tip[i]; + } + } + + if Shell_NotifyIconW(NIM_MODIFY, &nid) == 0 { + return Err(crate::Error::OsError(std::io::Error::last_os_error())); + } + + // send the new tooltip to the subclass proc to store it in the tray data + SendMessageW( + self.hwnd, + WM_USER_UPDATE_TRAYTOOLTIP, + Box::into_raw(Box::new(tooltip.map(|t| t.as_ref().to_string()))) as _, + 0, + ); + } + + Ok(()) + } + + pub fn set_show_menu_on_left_click(&mut self, enable: bool) { + unsafe { + SendMessageW( + self.hwnd, + WM_USER_SHOW_MENU_ON_LEFT_CLICK, + enable as usize, + 0, + ); + } + } + + pub fn set_show_menu_on_right_click(&mut self, enable: bool) { + unsafe { + SendMessageW( + self.hwnd, + WM_USER_SHOW_MENU_ON_RIGHT_CLICK, + enable as usize, + 0, + ); + } + } + + pub fn show_menu(&self) { + if let Some(menu) = &self.menu { + unsafe { + if let Some(rect) = get_tray_rect(self.internal_id, self.hwnd) { + show_tray_menu(self.hwnd, menu.hpopupmenu() as _, rect.left, rect.top); + } + } + } + } + + pub fn set_title>(&mut self, _title: Option) {} + + pub fn set_visible(&mut self, visible: bool) -> crate::Result<()> { + unsafe { + SendMessageW(self.hwnd, WM_USER_SHOW_TRAYICON, visible as usize, 0); + } + Ok(()) + } + + pub fn rect(&self) -> Option { + get_tray_rect(self.internal_id, self.hwnd).map(Into::into) + } + + pub fn hwnd(&self) -> HWND { + self.hwnd + } +} + +impl Drop for TrayIcon { + fn drop(&mut self) { + unsafe { + remove_tray_icon(self.hwnd, self.internal_id); + + if let Some(menu) = &self.menu { + menu.detach_menu_subclass_from_hwnd(self.hwnd as _); + } + + // destroy the hidden window used by the tray + DestroyWindow(self.hwnd); + } + } +} + +unsafe extern "system" fn tray_proc( + hwnd: HWND, + msg: u32, + wparam: WPARAM, + lparam: LPARAM, +) -> LRESULT { + let userdata_ptr = unsafe { util::get_window_long(hwnd, GWL_USERDATA) }; + let userdata_ptr = match (userdata_ptr, msg) { + (0, WM_NCCREATE) => { + let createstruct = unsafe { &mut *(lparam as *mut CREATESTRUCTW) }; + let userdata = unsafe { &mut *(createstruct.lpCreateParams as *mut TrayUserData) }; + userdata.hwnd = hwnd; + util::set_window_long(hwnd, GWL_USERDATA, createstruct.lpCreateParams as _); + return DefWindowProcW(hwnd, msg, wparam, lparam); + } + // Getting here should quite frankly be impossible, + // but we'll make window creation fail here just in case. + (0, WM_CREATE) => return -1, + (_, WM_CREATE) => return DefWindowProcW(hwnd, msg, wparam, lparam), + (0, _) => return DefWindowProcW(hwnd, msg, wparam, lparam), + _ => userdata_ptr as *mut TrayUserData, + }; + + let userdata = &mut *(userdata_ptr); + + match msg { + WM_DESTROY => { + drop(Box::from_raw(userdata_ptr)); + return 0; + } + WM_USER_UPDATE_TRAYMENU => { + let hpopupmenu = Box::from_raw(wparam as *mut Option); + userdata.hpopupmenu = (*hpopupmenu).map(|h| h as *mut _); + } + WM_USER_UPDATE_TRAYICON => { + let icon = Box::from_raw(wparam as *mut Option); + userdata.icon = *icon; + } + WM_USER_SHOW_TRAYICON => userdata.set_tray_visible(wparam as i32 == TRUE), + WM_USER_UPDATE_TRAYTOOLTIP => { + let tooltip = Box::from_raw(wparam as *mut Option); + userdata.tooltip = *tooltip; + } + _ if msg == *S_U_TASKBAR_RESTART => { + remove_tray_icon(userdata.hwnd, userdata.internal_id); + register_tray_icon( + userdata.hwnd, + userdata.internal_id, + &userdata.icon.as_ref().map(|i| i.inner.as_raw_handle()), + &userdata.tooltip, + userdata.visible, + ); + } + WM_USER_SHOW_MENU_ON_LEFT_CLICK => { + userdata.menu_on_left_click = wparam != 0; + } + WM_USER_SHOW_MENU_ON_RIGHT_CLICK => { + userdata.menu_on_right_click = wparam != 0; + } + + WM_USER_TRAYICON + if matches!( + lparam as u32, + WM_LBUTTONDOWN + | WM_RBUTTONDOWN + | WM_MBUTTONDOWN + | WM_LBUTTONUP + | WM_RBUTTONUP + | WM_MBUTTONUP + | WM_LBUTTONDBLCLK + | WM_RBUTTONDBLCLK + | WM_MBUTTONDBLCLK + | WM_MOUSEMOVE + ) => + { + let mut cursor = POINT { x: 0, y: 0 }; + if GetCursorPos(&mut cursor as _) == 0 { + return 0; + } + + let id = userdata.id.clone(); + let position = PhysicalPosition::new(cursor.x as f64, cursor.y as f64); + + let rect = match get_tray_rect(userdata.internal_id, hwnd) { + Some(rect) => Rect::from(rect), + None => return 0, + }; + + let event = match lparam as u32 { + WM_LBUTTONDOWN => TrayIconEvent::Click { + id, + rect, + position, + button: MouseButton::Left, + button_state: MouseButtonState::Down, + }, + WM_RBUTTONDOWN => TrayIconEvent::Click { + id, + rect, + position, + button: MouseButton::Right, + button_state: MouseButtonState::Down, + }, + WM_MBUTTONDOWN => TrayIconEvent::Click { + id, + rect, + position, + button: MouseButton::Middle, + button_state: MouseButtonState::Down, + }, + WM_LBUTTONUP => TrayIconEvent::Click { + id, + rect, + position, + button: MouseButton::Left, + button_state: MouseButtonState::Up, + }, + WM_RBUTTONUP => TrayIconEvent::Click { + id, + rect, + position, + button: MouseButton::Right, + button_state: MouseButtonState::Up, + }, + WM_MBUTTONUP => TrayIconEvent::Click { + id, + rect, + position, + button: MouseButton::Middle, + button_state: MouseButtonState::Up, + }, + WM_LBUTTONDBLCLK => TrayIconEvent::DoubleClick { + id, + rect, + position, + button: MouseButton::Left, + }, + WM_RBUTTONDBLCLK => TrayIconEvent::DoubleClick { + id, + rect, + position, + button: MouseButton::Right, + }, + WM_MBUTTONDBLCLK => TrayIconEvent::DoubleClick { + id, + rect, + position, + button: MouseButton::Middle, + }, + WM_MOUSEMOVE if !userdata.entered => { + userdata.entered = true; + TrayIconEvent::Enter { id, rect, position } + } + WM_MOUSEMOVE if userdata.entered => { + // handle extra WM_MOUSEMOVE events, ignore if position hasn't changed + let cursor_moved = userdata.last_position != Some(position); + userdata.last_position = Some(position); + if cursor_moved { + // Set or update existing timer, where we check if cursor left + SetTimer(hwnd, WM_USER_LEAVE_TIMER_ID as _, 15, Some(tray_timer_proc)); + + TrayIconEvent::Move { id, rect, position } + } else { + return 0; + } + } + + _ => unreachable!(), + }; + + TrayIconEvent::send(event); + + if (userdata.menu_on_right_click && lparam as u32 == WM_RBUTTONUP) + || (userdata.menu_on_left_click && lparam as u32 == WM_LBUTTONUP) + { + if let Some(menu) = userdata.hpopupmenu { + show_tray_menu(hwnd, menu, cursor.x, cursor.y); + } + } + } + + WM_TIMER if wparam as u32 == WM_USER_LEAVE_TIMER_ID => { + if let Some(position) = userdata.last_position.take() { + let mut cursor = POINT { x: 0, y: 0 }; + if GetCursorPos(&mut cursor as _) == 0 { + return 0; + } + + let rect = match get_tray_rect(userdata.internal_id, hwnd) { + Some(r) => r, + None => return 0, + }; + + let in_x = (rect.left..rect.right).contains(&cursor.x); + let in_y = (rect.top..rect.bottom).contains(&cursor.y); + + if !in_x || !in_y { + KillTimer(hwnd, WM_USER_LEAVE_TIMER_ID as _); + userdata.entered = false; + + TrayIconEvent::send(TrayIconEvent::Leave { + id: userdata.id.clone(), + rect: rect.into(), + position, + }); + } + } + + return 0; + } + + _ => {} + } + + DefWindowProcW(hwnd, msg, wparam, lparam) +} + +unsafe extern "system" fn tray_timer_proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: u32) { + tray_proc(hwnd, msg, wparam, lparam as _); +} + +#[inline] +unsafe fn show_tray_menu(hwnd: HWND, menu: HMENU, x: i32, y: i32) { + // bring the hidden window to the foreground so the pop up menu + // would automatically hide on click outside + SetForegroundWindow(hwnd); + TrackPopupMenu( + menu, + // align bottom / right, maybe we could expose this later.. + TPM_BOTTOMALIGN | TPM_LEFTALIGN, + x, + y, + 0, + hwnd, + std::ptr::null_mut(), + ); + // The shell docs recommend posting a benign message after TrackPopupMenu + // for notification area menus so the task switch is finalized correctly. + PostMessageW(hwnd, WM_NULL, 0, 0); +} + +#[inline] +unsafe fn register_tray_icon( + hwnd: HWND, + tray_id: u32, + hicon: &Option, + tooltip: &Option, + visible: bool, +) -> bool { + let mut h_icon = std::ptr::null_mut(); + let mut flags = NIF_MESSAGE; + let mut sz_tip: [u16; 128] = [0; 128]; + + if let Some(hicon) = hicon { + flags |= NIF_ICON; + h_icon = *hicon; + } + + if let Some(tooltip) = tooltip { + flags |= NIF_TIP; + let tip = util::encode_wide(tooltip); + #[allow(clippy::manual_memcpy)] + for i in 0..tip.len().min(128) { + sz_tip[i] = tip[i]; + } + } + + #[allow(non_snake_case)] + let dwState = if !visible { + flags |= NIF_STATE; + NIS_HIDDEN + } else { + 0 + }; + + let mut nid = NOTIFYICONDATAW { + uFlags: flags, + hWnd: hwnd, + uID: tray_id, + uCallbackMessage: WM_USER_TRAYICON, + hIcon: h_icon, + szTip: sz_tip, + dwState, + dwStateMask: dwState, + cbSize: size_of::() as u32, + ..std::mem::zeroed() + }; + + Shell_NotifyIconW(NIM_ADD, &mut nid as _) == TRUE +} + +#[inline] +unsafe fn remove_tray_icon(hwnd: HWND, id: u32) { + let nid = NOTIFYICONDATAW { + uFlags: NIF_ICON, + hWnd: hwnd, + uID: id, + cbSize: size_of::() as u32, + ..std::mem::zeroed() + }; + + if Shell_NotifyIconW(NIM_DELETE, &nid) == FALSE { + eprintln!("Error removing system tray icon"); + } +} + +#[inline] +fn get_tray_rect(id: u32, hwnd: HWND) -> Option { + let nid = NOTIFYICONIDENTIFIER { + hWnd: hwnd, + cbSize: size_of::() as _, + uID: id, + ..unsafe { std::mem::zeroed() } + }; + + let mut rect = RECT { + left: 0, + bottom: 0, + right: 0, + top: 0, + }; + if unsafe { Shell_NotifyIconGetRect(&nid, &mut rect) } == S_OK { + Some(rect) + } else { + None + } +} + +impl From for Rect { + fn from(rect: RECT) -> Self { + Self { + position: crate::dpi::PhysicalPosition::new(rect.left.into(), rect.top.into()), + size: crate::dpi::PhysicalSize::new( + rect.right.saturating_sub(rect.left) as u32, + rect.bottom.saturating_sub(rect.top) as u32, + ), + } + } +} diff --git a/ports/tray-icon/src/platform_impl/windows/util.rs b/ports/tray-icon/src/platform_impl/windows/util.rs new file mode 100644 index 000000000000..0088ea7d9da1 --- /dev/null +++ b/ports/tray-icon/src/platform_impl/windows/util.rs @@ -0,0 +1,55 @@ +// Copyright 2022-2022 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use windows_sys::Win32::{Foundation::HWND, UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX}; + +pub fn encode_wide>(string: S) -> Vec { + std::os::windows::prelude::OsStrExt::encode_wide(string.as_ref()) + .chain(std::iter::once(0)) + .collect() +} + +// taken from winit's code base +// https://github.com/rust-windowing/winit/blob/ee88e38f13fbc86a7aafae1d17ad3cd4a1e761df/src/platform_impl/windows/util.rs#L138 +pub fn get_instance_handle() -> windows_sys::Win32::Foundation::HMODULE { + // Gets the instance handle by taking the address of the + // pseudo-variable created by the microsoft linker: + // https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483 + + // This is preferred over GetModuleHandle(NULL) because it also works in DLLs: + // https://stackoverflow.com/questions/21718027/getmodulehandlenull-vs-hinstance + + extern "C" { + static __ImageBase: windows_sys::Win32::System::SystemServices::IMAGE_DOS_HEADER; + } + + unsafe { &__ImageBase as *const _ as _ } +} + +#[inline(always)] +pub unsafe fn get_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX) -> isize { + #[cfg(target_pointer_width = "64")] + return unsafe { windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW(hwnd, nindex) }; + #[cfg(target_pointer_width = "32")] + return unsafe { + windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongW(hwnd, nindex) as isize + }; +} + +#[inline(always)] +pub unsafe fn set_window_long( + hwnd: HWND, + nindex: WINDOW_LONG_PTR_INDEX, + dwnewlong: isize, +) -> isize { + #[cfg(target_pointer_width = "64")] + return unsafe { + windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW(hwnd, nindex, dwnewlong) + }; + #[cfg(target_pointer_width = "32")] + return unsafe { + windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongW(hwnd, nindex, dwnewlong as i32) + as isize + }; +} diff --git a/ports/tray-icon/src/tray_icon_id.rs b/ports/tray-icon/src/tray_icon_id.rs new file mode 100644 index 000000000000..8a2d18dabc93 --- /dev/null +++ b/ports/tray-icon/src/tray_icon_id.rs @@ -0,0 +1,92 @@ +use std::{convert::Infallible, str::FromStr}; + +use crate::COUNTER; + +/// An unique id that is associated with a tray icon. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct TrayIconId(pub String); + +impl TrayIconId { + /// Create a new tray icon id. + pub fn new>(id: S) -> Self { + Self(id.as_ref().to_string()) + } + + /// Generate id based on process id for internal use + pub(crate) fn new_unique() -> Self { + Self(format!("{}-{}", std::process::id(), COUNTER.next())) + } +} + +impl AsRef for TrayIconId { + fn as_ref(&self) -> &str { + self.0.as_ref() + } +} + +impl From for TrayIconId { + fn from(value: T) -> Self { + Self::new(value.to_string()) + } +} + +impl FromStr for TrayIconId { + type Err = Infallible; + + fn from_str(s: &str) -> std::result::Result { + Ok(Self::new(s)) + } +} + +impl PartialEq<&str> for TrayIconId { + fn eq(&self, other: &&str) -> bool { + self.0 == *other + } +} + +impl PartialEq<&str> for &TrayIconId { + fn eq(&self, other: &&str) -> bool { + self.0 == *other + } +} + +impl PartialEq for TrayIconId { + fn eq(&self, other: &String) -> bool { + self.0 == *other + } +} + +impl PartialEq for &TrayIconId { + fn eq(&self, other: &String) -> bool { + self.0 == *other + } +} + +impl PartialEq<&String> for TrayIconId { + fn eq(&self, other: &&String) -> bool { + self.0 == **other + } +} + +impl PartialEq<&TrayIconId> for TrayIconId { + fn eq(&self, other: &&TrayIconId) -> bool { + other.0 == self.0 + } +} + +#[cfg(test)] +mod test { + use crate::TrayIconId; + + #[test] + fn is_eq() { + assert_eq!(TrayIconId::new("t"), "t",); + assert_eq!(TrayIconId::new("t"), String::from("t")); + assert_eq!(TrayIconId::new("t"), &String::from("t")); + assert_eq!(TrayIconId::new("t"), TrayIconId::new("t")); + assert_eq!(TrayIconId::new("t"), &TrayIconId::new("t")); + assert_eq!(&TrayIconId::new("t"), &TrayIconId::new("t")); + assert_eq!(TrayIconId::new("t").as_ref(), "t"); + } +} From ca90534ad50ecbbd7dbe70f4332da2d5b579bb4a Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Tue, 7 Jul 2026 16:44:21 -0400 Subject: [PATCH 02/46] chore: satisfy root formatting checks for GTK integration --- crates/tauri/Cargo.toml | 4 +++- ports/muda/.changes/config.json | 2 +- ports/muda/.changes/gtk4.md | 2 +- ports/muda/.changes/readme.md | 2 +- ports/muda/.github/workflows/audit.yml | 6 +++++- ports/muda/.github/workflows/clippy-fmt.yml | 4 ++++ ports/muda/.github/workflows/covector-status.yml | 8 ++++++-- .../.github/workflows/covector-version-or-publish.yml | 6 +++++- ports/muda/.github/workflows/test.yml | 8 ++++++-- ports/muda/Cargo.toml | 9 ++++++++- ports/muda/examples/gtk.rs | 4 ++++ ports/muda/examples/tao.rs | 4 ++++ ports/muda/examples/windows-common-controls-v6/build.rs | 4 ++++ .../muda/examples/windows-common-controls-v6/src/main.rs | 4 ++++ ports/muda/examples/winit.rs | 4 ++++ ports/muda/examples/wry.rs | 4 ++++ ports/muda/src/about_metadata.rs | 4 ++++ ports/muda/src/accelerator.rs | 4 ++++ ports/muda/src/builders/check.rs | 4 ++++ ports/muda/src/builders/icon.rs | 4 ++++ ports/muda/src/builders/mod.rs | 4 ++++ ports/muda/src/builders/normal.rs | 4 ++++ ports/muda/src/builders/submenu.rs | 4 ++++ ports/muda/src/error.rs | 4 ++++ ports/muda/src/icon.rs | 4 ++++ ports/muda/src/items/check.rs | 4 ++++ ports/muda/src/items/compat.rs | 4 ++++ ports/muda/src/items/icon.rs | 4 ++++ ports/muda/src/items/mod.rs | 4 ++++ ports/muda/src/items/normal.rs | 4 ++++ ports/muda/src/items/predefined.rs | 4 ++++ ports/muda/src/items/submenu.rs | 4 ++++ ports/muda/src/lib.rs | 4 ++++ ports/muda/src/menu.rs | 4 ++++ ports/muda/src/menu_id.rs | 4 ++++ ports/muda/src/platform_impl/gtk/about_dialog.rs | 4 ++++ ports/muda/src/platform_impl/gtk/accelerator.rs | 4 ++++ ports/muda/src/platform_impl/gtk/icon.rs | 4 ++++ ports/muda/src/platform_impl/gtk/mnemonic.rs | 4 ++++ ports/muda/src/platform_impl/gtk/mod.rs | 4 ++++ ports/muda/src/platform_impl/macos/accelerator.rs | 4 ++++ ports/muda/src/platform_impl/macos/icon.rs | 4 ++++ ports/muda/src/platform_impl/macos/mod.rs | 4 ++++ ports/muda/src/platform_impl/macos/util.rs | 4 ++++ ports/muda/src/platform_impl/mod.rs | 4 ++++ ports/muda/src/platform_impl/windows/accelerator.rs | 4 ++++ ports/muda/src/platform_impl/windows/dark_menu_bar.rs | 4 ++++ ports/muda/src/platform_impl/windows/icon.rs | 4 ++++ ports/muda/src/platform_impl/windows/mod.rs | 4 ++++ ports/muda/src/platform_impl/windows/util.rs | 4 ++++ ports/muda/src/util.rs | 4 ++++ ports/tray-icon/.changes/config.json | 2 +- ports/tray-icon/.changes/perf-macos-avoid-allocating.md | 2 +- ports/tray-icon/.changes/readme.md | 2 +- ports/tray-icon/.github/workflows/audit.yml | 6 +++++- ports/tray-icon/.github/workflows/clippy-fmt.yml | 4 ++++ ports/tray-icon/.github/workflows/covector-status.yml | 6 +++++- .../.github/workflows/covector-version-or-publish.yml | 4 ++++ ports/tray-icon/.github/workflows/test.yml | 6 +++++- ports/tray-icon/examples/egui.rs | 4 ++++ ports/tray-icon/examples/tao.rs | 4 ++++ ports/tray-icon/examples/winit.rs | 4 ++++ ports/tray-icon/src/counter.rs | 4 ++++ ports/tray-icon/src/error.rs | 4 ++++ ports/tray-icon/src/icon.rs | 4 ++++ ports/tray-icon/src/lib.rs | 4 ++++ ports/tray-icon/src/platform_impl/gtk/icon.rs | 4 ++++ ports/tray-icon/src/platform_impl/gtk/mod.rs | 4 ++++ ports/tray-icon/src/platform_impl/linux/icon.rs | 4 ++++ ports/tray-icon/src/platform_impl/linux/menu.rs | 4 ++++ ports/tray-icon/src/platform_impl/linux/mod.rs | 4 ++++ ports/tray-icon/src/platform_impl/linux/tray.rs | 4 ++++ ports/tray-icon/src/platform_impl/macos/icon.rs | 4 ++++ ports/tray-icon/src/platform_impl/macos/mod.rs | 4 ++++ ports/tray-icon/src/platform_impl/mod.rs | 4 ++++ ports/tray-icon/src/platform_impl/windows/icon.rs | 4 ++++ ports/tray-icon/src/platform_impl/windows/mod.rs | 4 ++++ ports/tray-icon/src/platform_impl/windows/util.rs | 4 ++++ ports/tray-icon/src/tray_icon_id.rs | 4 ++++ 79 files changed, 310 insertions(+), 17 deletions(-) diff --git a/crates/tauri/Cargo.toml b/crates/tauri/Cargo.toml index a36a24a79fbd..8b9d862db938 100644 --- a/crates/tauri/Cargo.toml +++ b/crates/tauri/Cargo.toml @@ -99,7 +99,9 @@ tray-icon = { version = "0.24", default-features = false, features = [ # linux [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies] gtk = { package = "gtk4", version = "0.11", features = ["v4_10"] } -webkit = { package = "webkit6", version = "0.6", features = ["v2_42"], optional = true } +webkit = { package = "webkit6", version = "0.6", features = [ + "v2_42", +], optional = true } # darwin [target.'cfg(target_vendor = "apple")'.dependencies] diff --git a/ports/muda/.changes/config.json b/ports/muda/.changes/config.json index 8d336d283e36..d8e9dd99777e 100644 --- a/ports/muda/.changes/config.json +++ b/ports/muda/.changes/config.json @@ -49,4 +49,4 @@ ] } } -} \ No newline at end of file +} diff --git a/ports/muda/.changes/gtk4.md b/ports/muda/.changes/gtk4.md index cc149bb84713..939a960d6a22 100644 --- a/ports/muda/.changes/gtk4.md +++ b/ports/muda/.changes/gtk4.md @@ -1,5 +1,5 @@ --- -"muda": minor +'muda': minor --- Port the Linux backend from GTK3 to GTK4 (`gtk4` 0.11, `glib` 0.22). Every public method keeps its name and signature shape; the gtk types in returns and bounds follow the toolkit (`PopoverMenu`/`PopoverMenuBar`, `Widget` bounds), and `ContextMenu::gtk_context_menu` is retained on GTK4. Raises MSRV to 1.92. diff --git a/ports/muda/.changes/readme.md b/ports/muda/.changes/readme.md index b969dbd76abc..315ca709f948 100644 --- a/ports/muda/.changes/readme.md +++ b/ports/muda/.changes/readme.md @@ -10,7 +10,7 @@ Use the following format: ```md --- -"muda": patch +'muda': patch --- Change summary goes here diff --git a/ports/muda/.github/workflows/audit.yml b/ports/muda/.github/workflows/audit.yml index fd10e86e6e59..564f6924847d 100644 --- a/ports/muda/.github/workflows/audit.yml +++ b/ports/muda/.github/workflows/audit.yml @@ -1,3 +1,7 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + # Copyright 2022-2022 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT @@ -30,4 +34,4 @@ jobs: - uses: actions/checkout@v4 - uses: rustsec/audit-check@v1 with: - token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/ports/muda/.github/workflows/clippy-fmt.yml b/ports/muda/.github/workflows/clippy-fmt.yml index 35cc66e730c5..bf6d302e3cea 100644 --- a/ports/muda/.github/workflows/clippy-fmt.yml +++ b/ports/muda/.github/workflows/clippy-fmt.yml @@ -1,3 +1,7 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + # Copyright 2022-2022 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT diff --git a/ports/muda/.github/workflows/covector-status.yml b/ports/muda/.github/workflows/covector-status.yml index 41d265a1b735..e05bc09900d4 100644 --- a/ports/muda/.github/workflows/covector-status.yml +++ b/ports/muda/.github/workflows/covector-status.yml @@ -1,3 +1,7 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + # Copyright 2022-2022 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT @@ -15,6 +19,6 @@ jobs: uses: jbolda/covector/packages/action@covector-v0 id: covector with: - command: "status" + command: 'status' token: ${{ secrets.GITHUB_TOKEN }} - comment: true \ No newline at end of file + comment: true diff --git a/ports/muda/.github/workflows/covector-version-or-publish.yml b/ports/muda/.github/workflows/covector-version-or-publish.yml index e063fa0e3fac..7b894667acc0 100644 --- a/ports/muda/.github/workflows/covector-version-or-publish.yml +++ b/ports/muda/.github/workflows/covector-version-or-publish.yml @@ -1,3 +1,7 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + # Copyright 2022-2022 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT @@ -56,4 +60,4 @@ jobs: labels: 'version updates' branch: 'release' body: ${{ steps.covector.outputs.change }} - sign-commits: true \ No newline at end of file + sign-commits: true diff --git a/ports/muda/.github/workflows/test.yml b/ports/muda/.github/workflows/test.yml index ebf3e90df0f6..90852bfbcb71 100644 --- a/ports/muda/.github/workflows/test.yml +++ b/ports/muda/.github/workflows/test.yml @@ -1,3 +1,7 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + # Copyright 2022-2022 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT @@ -22,7 +26,7 @@ jobs: strategy: fail-fast: false matrix: - platform: ["windows-latest", "macos-latest", "ubuntu-latest"] + platform: ['windows-latest', 'macos-latest', 'ubuntu-latest'] runs-on: ${{ matrix.platform }} @@ -37,7 +41,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.92" + toolchain: '1.92' - run: cargo build - uses: dtolnay/rust-toolchain@stable diff --git a/ports/muda/Cargo.toml b/ports/muda/Cargo.toml index fefa059ceb90..efbd46af02c0 100644 --- a/ports/muda/Cargo.toml +++ b/ports/muda/Cargo.toml @@ -10,7 +10,14 @@ repository = "https://github.com/tauri-apps/muda" documentation = "https://docs.rs/muda" categories = ["gui"] rust-version = "1.92" -include = ["README.md", "src/**/*.rs", "Cargo.toml", "LICENSE-APACHE", "LICENSE-MIT", "LICENSE.spdx"] +include = [ + "README.md", + "src/**/*.rs", + "Cargo.toml", + "LICENSE-APACHE", + "LICENSE-MIT", + "LICENSE.spdx", +] [features] default = ["libxdo", "gtk"] diff --git a/ports/muda/examples/gtk.rs b/ports/muda/examples/gtk.rs index 95345f0e7427..4265c749568d 100644 --- a/ports/muda/examples/gtk.rs +++ b/ports/muda/examples/gtk.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + #[cfg(target_os = "linux")] use gtk::prelude::*; #[cfg(target_os = "linux")] diff --git a/ports/muda/examples/tao.rs b/ports/muda/examples/tao.rs index 4da1cb496246..5005bded6aee 100644 --- a/ports/muda/examples/tao.rs +++ b/ports/muda/examples/tao.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/examples/windows-common-controls-v6/build.rs b/ports/muda/examples/windows-common-controls-v6/build.rs index f9b40498929f..57bd52722747 100644 --- a/ports/muda/examples/windows-common-controls-v6/build.rs +++ b/ports/muda/examples/windows-common-controls-v6/build.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + fn main() { #[cfg(target_os = "windows")] embed_resource::compile("manifest.rc", embed_resource::NONE); diff --git a/ports/muda/examples/windows-common-controls-v6/src/main.rs b/ports/muda/examples/windows-common-controls-v6/src/main.rs index 22959ff64757..06e141636fc0 100644 --- a/ports/muda/examples/windows-common-controls-v6/src/main.rs +++ b/ports/muda/examples/windows-common-controls-v6/src/main.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/examples/winit.rs b/ports/muda/examples/winit.rs index 188e9d11cdb5..642cd706d0b5 100644 --- a/ports/muda/examples/winit.rs +++ b/ports/muda/examples/winit.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/examples/wry.rs b/ports/muda/examples/wry.rs index 42517722082c..38d8d1ab2686 100644 --- a/ports/muda/examples/wry.rs +++ b/ports/muda/examples/wry.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/about_metadata.rs b/ports/muda/src/about_metadata.rs index 15f6539e4475..2dca5940b3d7 100644 --- a/ports/muda/src/about_metadata.rs +++ b/ports/muda/src/about_metadata.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + //! Types and functions to create [`AboutMetadata`] for the [`PredefinedMenuItem::about`](crate::PredefinedMenuItem::about) dialog. use crate::icon::Icon; diff --git a/ports/muda/src/accelerator.rs b/ports/muda/src/accelerator.rs index a0ac3e57c8ce..35b0c98bd725 100644 --- a/ports/muda/src/accelerator.rs +++ b/ports/muda/src/accelerator.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/builders/check.rs b/ports/muda/src/builders/check.rs index f539653ef02a..74fadcea6129 100644 --- a/ports/muda/src/builders/check.rs +++ b/ports/muda/src/builders/check.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/builders/icon.rs b/ports/muda/src/builders/icon.rs index 7bdfcb1daec3..3935133b3bda 100644 --- a/ports/muda/src/builders/icon.rs +++ b/ports/muda/src/builders/icon.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/builders/mod.rs b/ports/muda/src/builders/mod.rs index c5557a028834..614aacf00ca4 100644 --- a/ports/muda/src/builders/mod.rs +++ b/ports/muda/src/builders/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/builders/normal.rs b/ports/muda/src/builders/normal.rs index 0c2aa47b7e6e..694e12a40ed5 100644 --- a/ports/muda/src/builders/normal.rs +++ b/ports/muda/src/builders/normal.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/builders/submenu.rs b/ports/muda/src/builders/submenu.rs index cceabbc42b1a..0e77dba6334f 100644 --- a/ports/muda/src/builders/submenu.rs +++ b/ports/muda/src/builders/submenu.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/error.rs b/ports/muda/src/error.rs index 56d006ab2a9a..0e244ace27d7 100644 --- a/ports/muda/src/error.rs +++ b/ports/muda/src/error.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/icon.rs b/ports/muda/src/icon.rs index 0262dfa65bf1..51335908bd8c 100644 --- a/ports/muda/src/icon.rs +++ b/ports/muda/src/icon.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/items/check.rs b/ports/muda/src/items/check.rs index 67c76931b304..c5822c2f46a4 100644 --- a/ports/muda/src/items/check.rs +++ b/ports/muda/src/items/check.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.inner // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/items/compat.rs b/ports/muda/src/items/compat.rs index 34fc1f121b4c..3c0ee6db41e5 100644 --- a/ports/muda/src/items/compat.rs +++ b/ports/muda/src/items/compat.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + use std::sync::Arc; use arc_swap::ArcSwap; diff --git a/ports/muda/src/items/icon.rs b/ports/muda/src/items/icon.rs index d1ce54321946..1c2f0e08356b 100644 --- a/ports/muda/src/items/icon.rs +++ b/ports/muda/src/items/icon.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.inner // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/items/mod.rs b/ports/muda/src/items/mod.rs index eb1153d74b07..f600a517f1ad 100644 --- a/ports/muda/src/items/mod.rs +++ b/ports/muda/src/items/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/items/normal.rs b/ports/muda/src/items/normal.rs index 581dc524dd1f..8f1ce8b28926 100644 --- a/ports/muda/src/items/normal.rs +++ b/ports/muda/src/items/normal.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + use std::{cell::RefCell, mem, rc::Rc}; use crate::{ diff --git a/ports/muda/src/items/predefined.rs b/ports/muda/src/items/predefined.rs index acb02831ac69..7d6d4f86e822 100644 --- a/ports/muda/src/items/predefined.rs +++ b/ports/muda/src/items/predefined.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.inner // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/items/submenu.rs b/ports/muda/src/items/submenu.rs index af8e97858f3b..e63b8d68a7ec 100644 --- a/ports/muda/src/items/submenu.rs +++ b/ports/muda/src/items/submenu.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.inner // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/lib.rs b/ports/muda/src/lib.rs index 5257a2e64408..b2632948e1e3 100644 --- a/ports/muda/src/lib.rs +++ b/ports/muda/src/lib.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/menu.rs b/ports/muda/src/menu.rs index 765b2fc09dfc..b6c1281f2188 100644 --- a/ports/muda/src/menu.rs +++ b/ports/muda/src/menu.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.inner // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/menu_id.rs b/ports/muda/src/menu_id.rs index 6c98f5c0e805..03fd2ffe4b23 100644 --- a/ports/muda/src/menu_id.rs +++ b/ports/muda/src/menu_id.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + use std::{convert::Infallible, str::FromStr}; /// An unique id that is associated with a menu or a menu item. diff --git a/ports/muda/src/platform_impl/gtk/about_dialog.rs b/ports/muda/src/platform_impl/gtk/about_dialog.rs index 357ae5942455..2fcb0e40f042 100644 --- a/ports/muda/src/platform_impl/gtk/about_dialog.rs +++ b/ports/muda/src/platform_impl/gtk/about_dialog.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/gtk/accelerator.rs b/ports/muda/src/platform_impl/gtk/accelerator.rs index f4f9f2d2309d..338ad304f252 100644 --- a/ports/muda/src/platform_impl/gtk/accelerator.rs +++ b/ports/muda/src/platform_impl/gtk/accelerator.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/gtk/icon.rs b/ports/muda/src/platform_impl/gtk/icon.rs index ba321b0ba013..e5217d9db9b0 100644 --- a/ports/muda/src/platform_impl/gtk/icon.rs +++ b/ports/muda/src/platform_impl/gtk/icon.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2014-2021 The winit contributors // Copyright 2021-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 diff --git a/ports/muda/src/platform_impl/gtk/mnemonic.rs b/ports/muda/src/platform_impl/gtk/mnemonic.rs index 012e5db37a75..9adff262f6a9 100644 --- a/ports/muda/src/platform_impl/gtk/mnemonic.rs +++ b/ports/muda/src/platform_impl/gtk/mnemonic.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/gtk/mod.rs b/ports/muda/src/platform_impl/gtk/mod.rs index 7d8164d2d86b..0015d4c711d5 100644 --- a/ports/muda/src/platform_impl/gtk/mod.rs +++ b/ports/muda/src/platform_impl/gtk/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/macos/accelerator.rs b/ports/muda/src/platform_impl/macos/accelerator.rs index bf96f6633d80..72c2164c2590 100644 --- a/ports/muda/src/platform_impl/macos/accelerator.rs +++ b/ports/muda/src/platform_impl/macos/accelerator.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/macos/icon.rs b/ports/muda/src/platform_impl/macos/icon.rs index 94b1a8e4fdfb..3ba0bfb1cb99 100644 --- a/ports/muda/src/platform_impl/macos/icon.rs +++ b/ports/muda/src/platform_impl/macos/icon.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/macos/mod.rs b/ports/muda/src/platform_impl/macos/mod.rs index 56e370cf5a4d..d40204fc5af7 100644 --- a/ports/muda/src/platform_impl/macos/mod.rs +++ b/ports/muda/src/platform_impl/macos/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/macos/util.rs b/ports/muda/src/platform_impl/macos/util.rs index c6c9d735f54c..da021aa70004 100644 --- a/ports/muda/src/platform_impl/macos/util.rs +++ b/ports/muda/src/platform_impl/macos/util.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/mod.rs b/ports/muda/src/platform_impl/mod.rs index 2288fcbca9ad..8c5700c0b382 100644 --- a/ports/muda/src/platform_impl/mod.rs +++ b/ports/muda/src/platform_impl/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/windows/accelerator.rs b/ports/muda/src/platform_impl/windows/accelerator.rs index 230394ee868a..3fb7a99b36ff 100644 --- a/ports/muda/src/platform_impl/windows/accelerator.rs +++ b/ports/muda/src/platform_impl/windows/accelerator.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/windows/dark_menu_bar.rs b/ports/muda/src/platform_impl/windows/dark_menu_bar.rs index 9e2346b56517..55968f3c6fd8 100644 --- a/ports/muda/src/platform_impl/windows/dark_menu_bar.rs +++ b/ports/muda/src/platform_impl/windows/dark_menu_bar.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/windows/icon.rs b/ports/muda/src/platform_impl/windows/icon.rs index c1c32a228caa..94683349c2ff 100644 --- a/ports/muda/src/platform_impl/windows/icon.rs +++ b/ports/muda/src/platform_impl/windows/icon.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/windows/mod.rs b/ports/muda/src/platform_impl/windows/mod.rs index 9544deed410a..35584de244f4 100644 --- a/ports/muda/src/platform_impl/windows/mod.rs +++ b/ports/muda/src/platform_impl/windows/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/platform_impl/windows/util.rs b/ports/muda/src/platform_impl/windows/util.rs index 08d5a7b35520..fdbfb82ef07a 100644 --- a/ports/muda/src/platform_impl/windows/util.rs +++ b/ports/muda/src/platform_impl/windows/util.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/muda/src/util.rs b/ports/muda/src/util.rs index fd5bb100d350..d996f14eb911 100644 --- a/ports/muda/src/util.rs +++ b/ports/muda/src/util.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/.changes/config.json b/ports/tray-icon/.changes/config.json index d768478def87..dff99705d97f 100644 --- a/ports/tray-icon/.changes/config.json +++ b/ports/tray-icon/.changes/config.json @@ -49,4 +49,4 @@ ] } } -} \ No newline at end of file +} diff --git a/ports/tray-icon/.changes/perf-macos-avoid-allocating.md b/ports/tray-icon/.changes/perf-macos-avoid-allocating.md index 4b5f0a236b47..fca107ea7ff0 100644 --- a/ports/tray-icon/.changes/perf-macos-avoid-allocating.md +++ b/ports/tray-icon/.changes/perf-macos-avoid-allocating.md @@ -1,5 +1,5 @@ --- -"tray-icon": patch +'tray-icon': patch --- Avoid unnecessary cloning when applying tray icons, titles, and tooltips on macOS. diff --git a/ports/tray-icon/.changes/readme.md b/ports/tray-icon/.changes/readme.md index a03e6b1d5bf7..aedf1384b494 100644 --- a/ports/tray-icon/.changes/readme.md +++ b/ports/tray-icon/.changes/readme.md @@ -10,7 +10,7 @@ Use the following format: ```md --- -"tray-icon": patch +'tray-icon': patch --- Change summary goes here diff --git a/ports/tray-icon/.github/workflows/audit.yml b/ports/tray-icon/.github/workflows/audit.yml index fd10e86e6e59..564f6924847d 100644 --- a/ports/tray-icon/.github/workflows/audit.yml +++ b/ports/tray-icon/.github/workflows/audit.yml @@ -1,3 +1,7 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + # Copyright 2022-2022 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT @@ -30,4 +34,4 @@ jobs: - uses: actions/checkout@v4 - uses: rustsec/audit-check@v1 with: - token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/ports/tray-icon/.github/workflows/clippy-fmt.yml b/ports/tray-icon/.github/workflows/clippy-fmt.yml index 8065661ecf31..431e63bc9f80 100644 --- a/ports/tray-icon/.github/workflows/clippy-fmt.yml +++ b/ports/tray-icon/.github/workflows/clippy-fmt.yml @@ -1,3 +1,7 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + # Copyright 2022-2022 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/.github/workflows/covector-status.yml b/ports/tray-icon/.github/workflows/covector-status.yml index b33f108a93e5..e05bc09900d4 100644 --- a/ports/tray-icon/.github/workflows/covector-status.yml +++ b/ports/tray-icon/.github/workflows/covector-status.yml @@ -1,3 +1,7 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + # Copyright 2022-2022 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT @@ -15,6 +19,6 @@ jobs: uses: jbolda/covector/packages/action@covector-v0 id: covector with: - command: "status" + command: 'status' token: ${{ secrets.GITHUB_TOKEN }} comment: true diff --git a/ports/tray-icon/.github/workflows/covector-version-or-publish.yml b/ports/tray-icon/.github/workflows/covector-version-or-publish.yml index d85dca0d3637..0ae05c135c8e 100644 --- a/ports/tray-icon/.github/workflows/covector-version-or-publish.yml +++ b/ports/tray-icon/.github/workflows/covector-version-or-publish.yml @@ -1,3 +1,7 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + # Copyright 2022-2022 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/.github/workflows/test.yml b/ports/tray-icon/.github/workflows/test.yml index 9cb9c552ba69..b8052598112b 100644 --- a/ports/tray-icon/.github/workflows/test.yml +++ b/ports/tray-icon/.github/workflows/test.yml @@ -1,3 +1,7 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + # Copyright 2022-2022 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT @@ -22,7 +26,7 @@ jobs: strategy: fail-fast: false matrix: - platform: ["windows-latest", "macos-latest", "ubuntu-latest"] + platform: ['windows-latest', 'macos-latest', 'ubuntu-latest'] runs-on: ${{ matrix.platform }} diff --git a/ports/tray-icon/examples/egui.rs b/ports/tray-icon/examples/egui.rs index 1f66533d8b41..2dde2d565b23 100644 --- a/ports/tray-icon/examples/egui.rs +++ b/ports/tray-icon/examples/egui.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release #[cfg(not(any( diff --git a/ports/tray-icon/examples/tao.rs b/ports/tray-icon/examples/tao.rs index 2fad15466d23..784d685c232c 100644 --- a/ports/tray-icon/examples/tao.rs +++ b/ports/tray-icon/examples/tao.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/examples/winit.rs b/ports/tray-icon/examples/winit.rs index b6db6deee0b9..24a4ec1a12b5 100644 --- a/ports/tray-icon/examples/winit.rs +++ b/ports/tray-icon/examples/winit.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/counter.rs b/ports/tray-icon/src/counter.rs index f2610ee8c375..8a49fbe42a48 100644 --- a/ports/tray-icon/src/counter.rs +++ b/ports/tray-icon/src/counter.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/error.rs b/ports/tray-icon/src/error.rs index b059e8aa1155..d0fd2847df92 100644 --- a/ports/tray-icon/src/error.rs +++ b/ports/tray-icon/src/error.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/icon.rs b/ports/tray-icon/src/icon.rs index 192891c87e3a..3a92f0827ba0 100644 --- a/ports/tray-icon/src/icon.rs +++ b/ports/tray-icon/src/icon.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/lib.rs b/ports/tray-icon/src/lib.rs index 415bf9610a68..13d80c966e36 100644 --- a/ports/tray-icon/src/lib.rs +++ b/ports/tray-icon/src/lib.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/platform_impl/gtk/icon.rs b/ports/tray-icon/src/platform_impl/gtk/icon.rs index 9a9c6dcdefc5..de554a05e5aa 100644 --- a/ports/tray-icon/src/platform_impl/gtk/icon.rs +++ b/ports/tray-icon/src/platform_impl/gtk/icon.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/platform_impl/gtk/mod.rs b/ports/tray-icon/src/platform_impl/gtk/mod.rs index 945544301469..5d05d7786704 100644 --- a/ports/tray-icon/src/platform_impl/gtk/mod.rs +++ b/ports/tray-icon/src/platform_impl/gtk/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/platform_impl/linux/icon.rs b/ports/tray-icon/src/platform_impl/linux/icon.rs index 4cb8d9dbbb62..c46357672da6 100644 --- a/ports/tray-icon/src/platform_impl/linux/icon.rs +++ b/ports/tray-icon/src/platform_impl/linux/icon.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/platform_impl/linux/menu.rs b/ports/tray-icon/src/platform_impl/linux/menu.rs index 75c35ec7ccc5..bd53cd90275e 100644 --- a/ports/tray-icon/src/platform_impl/linux/menu.rs +++ b/ports/tray-icon/src/platform_impl/linux/menu.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + use std::sync::Arc; use arc_swap::ArcSwap; diff --git a/ports/tray-icon/src/platform_impl/linux/mod.rs b/ports/tray-icon/src/platform_impl/linux/mod.rs index ab43fc32bb63..03f885798b08 100644 --- a/ports/tray-icon/src/platform_impl/linux/mod.rs +++ b/ports/tray-icon/src/platform_impl/linux/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/platform_impl/linux/tray.rs b/ports/tray-icon/src/platform_impl/linux/tray.rs index 0b8eb036611d..da656b162307 100644 --- a/ports/tray-icon/src/platform_impl/linux/tray.rs +++ b/ports/tray-icon/src/platform_impl/linux/tray.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + use std::sync::Arc; use arc_swap::ArcSwap; diff --git a/ports/tray-icon/src/platform_impl/macos/icon.rs b/ports/tray-icon/src/platform_impl/macos/icon.rs index a639379955f4..76c8be7c8871 100644 --- a/ports/tray-icon/src/platform_impl/macos/icon.rs +++ b/ports/tray-icon/src/platform_impl/macos/icon.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/platform_impl/macos/mod.rs b/ports/tray-icon/src/platform_impl/macos/mod.rs index a3517c81a592..9658307cb06e 100644 --- a/ports/tray-icon/src/platform_impl/macos/mod.rs +++ b/ports/tray-icon/src/platform_impl/macos/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/platform_impl/mod.rs b/ports/tray-icon/src/platform_impl/mod.rs index 5fb657afeb32..f0c115de65d4 100644 --- a/ports/tray-icon/src/platform_impl/mod.rs +++ b/ports/tray-icon/src/platform_impl/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/platform_impl/windows/icon.rs b/ports/tray-icon/src/platform_impl/windows/icon.rs index deaa50ccb3bf..c04b6cd3f651 100644 --- a/ports/tray-icon/src/platform_impl/windows/icon.rs +++ b/ports/tray-icon/src/platform_impl/windows/icon.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/platform_impl/windows/mod.rs b/ports/tray-icon/src/platform_impl/windows/mod.rs index b45b56d4cdc5..a45da9e48761 100644 --- a/ports/tray-icon/src/platform_impl/windows/mod.rs +++ b/ports/tray-icon/src/platform_impl/windows/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/platform_impl/windows/util.rs b/ports/tray-icon/src/platform_impl/windows/util.rs index 0088ea7d9da1..cdeed1ba23c6 100644 --- a/ports/tray-icon/src/platform_impl/windows/util.rs +++ b/ports/tray-icon/src/platform_impl/windows/util.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Copyright 2022-2022 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT diff --git a/ports/tray-icon/src/tray_icon_id.rs b/ports/tray-icon/src/tray_icon_id.rs index 8a2d18dabc93..0d70d6c14eed 100644 --- a/ports/tray-icon/src/tray_icon_id.rs +++ b/ports/tray-icon/src/tray_icon_id.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + use std::{convert::Infallible, str::FromStr}; use crate::COUNTER; From 434384b4e69788d5fca434fc1d81431a4309c181 Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Tue, 7 Jul 2026 16:59:09 -0400 Subject: [PATCH 03/46] ci: align GTK jobs with Rust 1.92 --- .github/workflows/bench.yml | 1 + .github/workflows/check-generated-files.yml | 1 + .github/workflows/covector-version-or-publish.yml | 2 ++ .github/workflows/docker.yml | 2 ++ .github/workflows/publish-cli-js.yml | 3 +++ .github/workflows/publish-cli-rs.yml | 1 + .github/workflows/test-android.yml | 5 +++-- .github/workflows/test-cli-js.yml | 1 + .github/workflows/test-cli-rs.yml | 2 +- .github/workflows/test-core.yml | 10 +++++----- .github/workflows/udeps.yml | 2 ++ Cargo.toml | 2 +- 12 files changed, 23 insertions(+), 9 deletions(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 8a151c64a1e8..52b3e86326f9 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -53,6 +53,7 @@ jobs: - name: install WebKitGTK and xvfb (ubuntu only) if: contains(matrix.platform.target, 'gnu') run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y --no-install-recommends \ libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev \ diff --git a/.github/workflows/check-generated-files.yml b/.github/workflows/check-generated-files.yml index 8be89c93f959..f8698f38ba2f 100644 --- a/.github/workflows/check-generated-files.yml +++ b/.github/workflows/check-generated-files.yml @@ -72,6 +72,7 @@ jobs: - name: install Linux dependencies run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y libgtk-4-dev diff --git a/.github/workflows/covector-version-or-publish.yml b/.github/workflows/covector-version-or-publish.yml index ca100e0f6e01..7f3746ab345c 100644 --- a/.github/workflows/covector-version-or-publish.yml +++ b/.github/workflows/covector-version-or-publish.yml @@ -35,6 +35,7 @@ jobs: - name: install Linux dependencies if: matrix.platform == 'ubuntu-latest' run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev libfuse2 librsvg2-dev @@ -87,6 +88,7 @@ jobs: - name: install Linux dependencies run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev librsvg2-dev diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index d0e2db6fcab1..caa97179b88e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -24,6 +24,7 @@ jobs: - name: install Linux dependencies run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y libgtk-4-dev @@ -107,6 +108,7 @@ jobs: - name: install dependencies run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev diff --git a/.github/workflows/publish-cli-js.yml b/.github/workflows/publish-cli-js.yml index d4299309a1de..69c3fcc2b98c 100644 --- a/.github/workflows/publish-cli-js.yml +++ b/.github/workflows/publish-cli-js.yml @@ -57,6 +57,7 @@ jobs: target: aarch64-unknown-linux-gnu build: pnpm build --target=aarch64-unknown-linux-gnu --cross-compile setup: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu -y - host: ubuntu-latest @@ -69,6 +70,7 @@ jobs: target: riscv64gc-unknown-linux-gnu build: pnpm build --target=riscv64gc-unknown-linux-gnu --cross-compile setup: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu -y name: stable - ${{ matrix.settings.target }} - node@20 @@ -208,6 +210,7 @@ jobs: - name: install system dependencies (gnu) if: ${{ endsWith(matrix.target, 'gnu') }} run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev librsvg2-dev diff --git a/.github/workflows/publish-cli-rs.yml b/.github/workflows/publish-cli-rs.yml index 582c6902ae0f..09cd792f0166 100644 --- a/.github/workflows/publish-cli-rs.yml +++ b/.github/workflows/publish-cli-rs.yml @@ -61,6 +61,7 @@ jobs: - name: install Linux dependencies if: ${{ !matrix.config.cross && startsWith(matrix.config.os, 'ubuntu') }} run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y libgtk-4-dev diff --git a/.github/workflows/test-android.yml b/.github/workflows/test-android.yml index b81632f4dc8b..8012e6602440 100644 --- a/.github/workflows/test-android.yml +++ b/.github/workflows/test-android.yml @@ -33,12 +33,13 @@ jobs: steps: - uses: actions/checkout@v4 - - name: install Rust 1.90 - uses: dtolnay/rust-toolchain@1.90 + - name: install Rust 1.92 + uses: dtolnay/rust-toolchain@1.92 - name: install Linux dependencies if: matrix.platform == 'ubuntu-latest' run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev diff --git a/.github/workflows/test-cli-js.yml b/.github/workflows/test-cli-js.yml index 5630d4481990..6618074e377e 100644 --- a/.github/workflows/test-cli-js.yml +++ b/.github/workflows/test-cli-js.yml @@ -48,6 +48,7 @@ jobs: - name: install Linux dependencies if: matrix.platform == 'ubuntu-latest' run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev librsvg2-dev diff --git a/.github/workflows/test-cli-rs.yml b/.github/workflows/test-cli-rs.yml index 6fecb3ef1020..be20fcf3d396 100644 --- a/.github/workflows/test-cli-rs.yml +++ b/.github/workflows/test-cli-rs.yml @@ -47,7 +47,7 @@ jobs: - uses: actions/checkout@v4 - name: 'Setup Rust' - uses: dtolnay/rust-toolchain@1.90 + uses: dtolnay/rust-toolchain@1.92 with: targets: ${{ matrix.platform.target }} diff --git a/.github/workflows/test-core.yml b/.github/workflows/test-core.yml index 77e98195b767..202df9e64e17 100644 --- a/.github/workflows/test-core.yml +++ b/.github/workflows/test-core.yml @@ -40,35 +40,35 @@ jobs: - { target: x86_64-pc-windows-msvc, os: windows-latest, - toolchain: '1.90', + toolchain: '1.92', cargo: cargo, command: 'test' } - { target: x86_64-unknown-linux-gnu, os: ubuntu-latest, - toolchain: '1.90', + toolchain: '1.92', cargo: cargo, command: 'test' } - { target: aarch64-apple-darwin, os: macos-14, - toolchain: '1.90', + toolchain: '1.92', cargo: cargo, command: 'test' } - { target: aarch64-apple-ios, os: macos-latest, - toolchain: '1.90', + toolchain: '1.92', cargo: cargo, command: 'build' } - { target: aarch64-linux-android, os: ubuntu-latest, - toolchain: '1.90', + toolchain: '1.92', cargo: cross, command: 'build' } diff --git a/.github/workflows/udeps.yml b/.github/workflows/udeps.yml index e20c743228e7..4e6b316bae5d 100644 --- a/.github/workflows/udeps.yml +++ b/.github/workflows/udeps.yml @@ -133,6 +133,7 @@ jobs: - name: install dependencies run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y libgtk-4-dev @@ -148,6 +149,7 @@ jobs: - name: Install required packages run: | + sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev diff --git a/Cargo.toml b/Cargo.toml index 85dae9c32460..32d93e8a5a46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ repository = "https://github.com/tauri-apps/tauri" categories = ["gui", "web-programming"] license = "Apache-2.0 OR MIT" edition = "2021" -rust-version = "1.90" +rust-version = "1.92" # default to small, optimized workspace release binaries [profile.release] From 818257c5e6b88774bb220cd5b7740819c965cc88 Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Tue, 7 Jul 2026 17:28:14 -0400 Subject: [PATCH 04/46] fix(wry): use Tao Android activity ids --- ports/wry/Cargo.toml | 1 + ports/wry/src/android/main_pipe.rs | 20 -------------------- ports/wry/src/android/mod.rs | 21 +++++++-------------- ports/wry/src/lib.rs | 23 +++++++++++++++++++++++ 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/ports/wry/Cargo.toml b/ports/wry/Cargo.toml index d82135863f9f..fe6bcdaf2165 100644 --- a/ports/wry/Cargo.toml +++ b/ports/wry/Cargo.toml @@ -189,6 +189,7 @@ base64 = "0.22" jni = "0.21" ndk = "0.9" tao-macros = "0.1" +tao = { path = "../tao" } libc = "0.2" dom_query = { version = "0.28.0", default-features = false } diff --git a/ports/wry/src/android/main_pipe.rs b/ports/wry/src/android/main_pipe.rs index 3efc30608def..213457532e79 100644 --- a/ports/wry/src/android/main_pipe.rs +++ b/ports/wry/src/android/main_pipe.rs @@ -84,26 +84,6 @@ pub fn register_activity_proxy( } } -pub fn activity_id_for_window_manager(window_manager: JObject) -> Option { - for (activity_id, proxy) in ACTIVITY_PROXY.lock().unwrap().iter() { - let vm = unsafe { JavaVM::from_raw(proxy.java_vm.cast()) }.unwrap(); - let mut env = vm.attach_current_thread_as_daemon().unwrap(); - let equals = env - .call_method( - proxy.window_manager.as_obj(), - "equals", - "(Ljava/lang/Object;)Z", - &[(&window_manager).into()], - ) - .and_then(|v| v.z()) - .unwrap_or_default(); - if equals { - return Some(*activity_id); - } - } - None -} - pub fn first_activity_id() -> Option { ACTIVITY_PROXY.lock().unwrap().keys().next().cloned() } diff --git a/ports/wry/src/android/mod.rs b/ports/wry/src/android/mod.rs index 03917f260773..b7983c3fbc4c 100644 --- a/ports/wry/src/android/mod.rs +++ b/ports/wry/src/android/mod.rs @@ -8,7 +8,7 @@ use super::{PageLoadEvent, WebViewAttributes, RGBA}; use crate::{ - custom_protocol_workaround, inject_initialization_scripts::inject_scripts_into_html, Error, + custom_protocol_workaround, inject_initialization_scripts::inject_scripts_into_html, PermissionKind, PermissionResponse, RequestAsyncResponder, Result, }; use crossbeam_channel::*; @@ -28,12 +28,13 @@ use std::{ sync::{mpsc::channel, Arc, Mutex}, time::Duration, }; +use tao::platform::android::WindowExtAndroid; pub(crate) mod binding; mod main_pipe; use main_pipe::{ - activity_id_for_window_manager, first_activity_id, register_activity_proxy, ActivityId, - CreateWebViewAttributes, MainPipe, WebViewMessage, + first_activity_id, register_activity_proxy, ActivityId, CreateWebViewAttributes, MainPipe, + WebViewMessage, }; use crate::util::Counter; @@ -154,7 +155,7 @@ pub(crate) struct InnerWebView { impl InnerWebView { pub fn new_as_child( - window: &impl HasWindowHandle, + window: &(impl HasWindowHandle + WindowExtAndroid), attributes: WebViewAttributes, pl_attrs: super::PlatformSpecificWebViewAttributes, ) -> Result { @@ -162,19 +163,11 @@ impl InnerWebView { } pub fn new( - window: &impl HasWindowHandle, + window: &(impl HasWindowHandle + WindowExtAndroid), attributes: WebViewAttributes, pl_attrs: super::PlatformSpecificWebViewAttributes, ) -> Result { - let window_manager = match window.window_handle()?.as_raw() { - raw_window_handle::RawWindowHandle::AndroidNdk(window_manager) => { - window_manager.a_native_window - } - _ => return Err(Error::UnsupportedWindowHandle), - }; - let window_manager = unsafe { JObject::from_raw(window_manager.as_ptr().cast()) }; - let activity_id = - activity_id_for_window_manager(window_manager).expect("no available activity"); + let activity_id = window.activity_id(); let WebViewAttributes { url, html, diff --git a/ports/wry/src/lib.rs b/ports/wry/src/lib.rs index f668dbba1358..479a84e7bc7e 100644 --- a/ports/wry/src/lib.rs +++ b/ports/wry/src/lib.rs @@ -1534,12 +1534,23 @@ impl<'a> WebViewBuilder<'a> { /// /// - Panics if the provided handle was not supported or invalid. /// - Panics on Linux, if [`gtk::init`] was not called in this thread. + #[cfg(not(target_os = "android"))] pub fn build(self, window: &'a W) -> Result { self.error?; InnerWebView::new(window, self.attrs, self.platform_specific).map(|webview| WebView { webview }) } + #[cfg(target_os = "android")] + pub fn build(self, window: &'a W) -> Result + where + W: HasWindowHandle + tao::platform::android::WindowExtAndroid, + { + self.error?; + + InnerWebView::new(window, self.attrs, self.platform_specific).map(|webview| WebView { webview }) + } + /// Consume the builder and create the [`WebView`] as a child window inside the provided [`HasWindowHandle`]. /// /// ## Platform-specific @@ -1562,12 +1573,24 @@ impl<'a> WebViewBuilder<'a> { /// /// - Panics if the provided handle was not support or invalid. /// - Panics on Linux, if [`gtk::init`] was not called in this thread. + #[cfg(not(target_os = "android"))] pub fn build_as_child(self, window: &'a W) -> Result { self.error?; InnerWebView::new_as_child(window, self.attrs, self.platform_specific) .map(|webview| WebView { webview }) } + + #[cfg(target_os = "android")] + pub fn build_as_child(self, window: &'a W) -> Result + where + W: HasWindowHandle + tao::platform::android::WindowExtAndroid, + { + self.error?; + + InnerWebView::new_as_child(window, self.attrs, self.platform_specific) + .map(|webview| WebView { webview }) + } } #[cfg(any(target_os = "macos", target_os = "ios"))] From 81c038e962107a271424393181d203e0b55679fe Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Tue, 7 Jul 2026 17:43:24 -0400 Subject: [PATCH 05/46] fix(ci): restore integration checks --- Cargo.lock | 11 ++++++----- crates/tauri-runtime-wry/src/lib.rs | 4 ++-- crates/tauri/src/lib.rs | 12 ++++++------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1b37afd49811..03c523ed7352 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8706,20 +8706,20 @@ dependencies = [ [[package]] name = "specta" -version = "2.0.0-rc.25" +version = "2.0.0-rc.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f9a30cbcbb7011f1da7d73483983bf838af123883e45f2b36ed76328df9c50" +checksum = "4ccbb212565d2dc177bc15ecb7b039d66c4490da892436a4eee5b394d620c9bc" dependencies = [ "paste", - "rustc_version", "specta-macros", + "thiserror 1.0.69", ] [[package]] name = "specta-macros" -version = "2.0.0-rc.25" +version = "2.0.0-rc.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce14957ecc2897f1f848b8255b6531d13ddf49cbcf506b7c2c9fb1d005593bb" +checksum = "68999d29816965eb9e5201f60aec02a76512139811661a7e8e653abc810b8f72" dependencies = [ "Inflector", "proc-macro2", @@ -11568,6 +11568,7 @@ dependencies = [ "raw-window-handle", "sha2 0.10.9", "soup3", + "tao", "tao-macros 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 2.0.18", "tracing", diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 3fa6c211aacf..e269456ad9e5 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -5155,7 +5155,7 @@ You may have it installed on another user account, but it is not available for t target_os = "ios", target_os = "android" ))] - WebviewKind::WindowChild => webview_builder.build_as_child(&window), + WebviewKind::WindowChild => webview_builder.build_as_child(window), WebviewKind::WindowContent => { #[cfg(any( target_os = "windows", @@ -5163,7 +5163,7 @@ You may have it installed on another user account, but it is not available for t target_os = "ios", target_os = "android" ))] - let builder = webview_builder.build(&window); + let builder = webview_builder.build(window); #[cfg(not(any( target_os = "windows", target_os = "macos", diff --git a/crates/tauri/src/lib.rs b/crates/tauri/src/lib.rs index 8a3691b6e948..75e7b042d82c 100644 --- a/crates/tauri/src/lib.rs +++ b/crates/tauri/src/lib.rs @@ -1102,34 +1102,34 @@ pub mod test; #[cfg(feature = "specta")] const _: () = { - use specta::{datatype::DataType, function::FunctionArg, Types}; + use specta::{datatype::DataType, function::FunctionArg, TypeMap}; impl FunctionArg for crate::State<'_, T> { - fn to_datatype(_: &mut Types) -> Option { + fn to_datatype(_: &mut TypeMap) -> Option { None } } impl FunctionArg for crate::AppHandle { - fn to_datatype(_: &mut Types) -> Option { + fn to_datatype(_: &mut TypeMap) -> Option { None } } impl FunctionArg for crate::Window { - fn to_datatype(_: &mut Types) -> Option { + fn to_datatype(_: &mut TypeMap) -> Option { None } } impl FunctionArg for crate::Webview { - fn to_datatype(_: &mut Types) -> Option { + fn to_datatype(_: &mut TypeMap) -> Option { None } } impl FunctionArg for crate::WebviewWindow { - fn to_datatype(_: &mut Types) -> Option { + fn to_datatype(_: &mut TypeMap) -> Option { None } } From 6d23850b1e0eb0091d9e0e8fabfe20f7b0d9bbe9 Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Tue, 7 Jul 2026 18:10:53 -0400 Subject: [PATCH 06/46] fix(ci): patch vendored ports in template builds --- .github/workflows/bench.yml | 2 + crates/tauri-cli/src/init.rs | 88 +++++++++++++------ .../app/src-tauri/Cargo.crate-manifest | 4 + 3 files changed, 66 insertions(+), 28 deletions(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 52b3e86326f9..3c5c59653293 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -87,6 +87,8 @@ jobs: cargo +nightly build --release -Z build-std=std,panic_abort -Z build-std-features= --target ${{ matrix.platform.target }} --manifest-path bench/tests/helloworld/src-tauri/Cargo.toml - name: run benchmarks + env: + WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS: ${{ contains(matrix.platform.target, 'gnu') && '1' || '' }} run: ${{ matrix.platform.runner }}cargo run --manifest-path ./bench/Cargo.toml --bin run_benchmark - name: clone benchmarks_results diff --git a/crates/tauri-cli/src/init.rs b/crates/tauri-cli/src/init.rs index a809ba317b7e..268f5fb9ca07 100644 --- a/crates/tauri-cli/src/init.rs +++ b/crates/tauri-cli/src/init.rs @@ -200,34 +200,62 @@ pub fn command(mut options: Options) -> Result<()> { template_target_path ); } else { - let (tauri_dep, tauri_build_dep, tauri_utils_dep, tauri_plugin_dep) = - if let Some(tauri_path) = &options.tauri_path { - ( - format!( - r#"{{ path = {:?} }}"#, - resolve_tauri_path(tauri_path, "crates/tauri") - ), - format!( - "{{ path = {:?} }}", - resolve_tauri_path(tauri_path, "crates/tauri-build") - ), - format!( - "{{ path = {:?} }}", - resolve_tauri_path(tauri_path, "crates/tauri-utils") - ), - format!( - "{{ path = {:?} }}", - resolve_tauri_path(tauri_path, "crates/tauri-plugin") - ), - ) - } else { - ( - format!(r#"{{ version = "{}" }}"#, metadata.tauri), - format!(r#"{{ version = "{}" }}"#, metadata.tauri_build), - r#"{{ version = "2" }}"#.to_string(), - r#"{{ version = "2" }}"#.to_string(), - ) - }; + let ( + tauri_dep, + tauri_build_dep, + tauri_utils_dep, + tauri_plugin_dep, + muda_dep, + tao_dep, + tray_icon_dep, + wry_dep, + ) = if let Some(tauri_path) = &options.tauri_path { + ( + format!( + r#"{{ path = {:?} }}"#, + resolve_tauri_path(tauri_path, "crates/tauri") + ), + format!( + "{{ path = {:?} }}", + resolve_tauri_path(tauri_path, "crates/tauri-build") + ), + format!( + "{{ path = {:?} }}", + resolve_tauri_path(tauri_path, "crates/tauri-utils") + ), + format!( + "{{ path = {:?} }}", + resolve_tauri_path(tauri_path, "crates/tauri-plugin") + ), + format!( + "{{ path = {:?} }}", + resolve_tauri_path(tauri_path, "ports/muda") + ), + format!( + "{{ path = {:?} }}", + resolve_tauri_path(tauri_path, "ports/tao") + ), + format!( + "{{ path = {:?} }}", + resolve_tauri_path(tauri_path, "ports/tray-icon") + ), + format!( + "{{ path = {:?} }}", + resolve_tauri_path(tauri_path, "ports/wry") + ), + ) + } else { + ( + format!(r#"{{ version = "{}" }}"#, metadata.tauri), + format!(r#"{{ version = "{}" }}"#, metadata.tauri_build), + r#"{{ version = "2" }}"#.to_string(), + r#"{{ version = "2" }}"#.to_string(), + String::new(), + String::new(), + String::new(), + String::new(), + ) + }; let _ = remove_dir_all(&template_target_path); let mut handlebars = Handlebars::new(); @@ -241,6 +269,10 @@ pub fn command(mut options: Options) -> Result<()> { data.insert("tauri_build_dep", to_json(tauri_build_dep)); data.insert("tauri_utils_dep", to_json(tauri_utils_dep)); data.insert("tauri_plugin_dep", to_json(tauri_plugin_dep)); + data.insert("muda_dep", to_json(muda_dep)); + data.insert("tao_dep", to_json(tao_dep)); + data.insert("tray_icon_dep", to_json(tray_icon_dep)); + data.insert("wry_dep", to_json(wry_dep)); data.insert( "frontend_dist", to_json(options.frontend_dist.as_deref().unwrap_or("../dist")), diff --git a/crates/tauri-cli/templates/app/src-tauri/Cargo.crate-manifest b/crates/tauri-cli/templates/app/src-tauri/Cargo.crate-manifest index bf092645cdd1..87d59422e664 100644 --- a/crates/tauri-cli/templates/app/src-tauri/Cargo.crate-manifest +++ b/crates/tauri-cli/templates/app/src-tauri/Cargo.crate-manifest @@ -25,7 +25,11 @@ tauri = {{ tauri_dep }} tauri-plugin-log = "2" {{#if patch_tauri_dep}} [patch.crates-io] +muda = {{ muda_dep }} +tao = {{ tao_dep }} tauri = {{ tauri_dep }} tauri-utils = {{ tauri_utils_dep }} tauri-plugin = {{ tauri_plugin_dep }} +tray-icon = {{ tray_icon_dep }} +wry = {{ wry_dep }} {{/if}} From 33a92fe7fc5a78ca6ea780cce191bf045cd64b95 Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Tue, 7 Jul 2026 18:23:01 -0400 Subject: [PATCH 07/46] fix(bundler): use bundled GTK4 linuxdeploy plugin --- .../tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs index 99bb57895df7..a5e0f59a0653 100644 --- a/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs +++ b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs @@ -237,10 +237,7 @@ fn prepare_tools(tools_path: &Path, arch: &str, verbose: bool) -> crate::Result< } let gtk = tools_path.join("linuxdeploy-plugin-gtk.sh"); - if !gtk.exists() { - let data = download("https://raw.githubusercontent.com/tauri-apps/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh")?; - write_and_make_executable(>k, data)?; - } + write_and_make_executable(>k, include_bytes!("linuxdeploy-plugin-gtk.sh").to_vec())?; let gstreamer = tools_path.join("linuxdeploy-plugin-gstreamer.sh"); if !gstreamer.exists() { From fbe1c704a73f458744c625e7e99c593f65557cfd Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Tue, 7 Jul 2026 18:36:14 -0400 Subject: [PATCH 08/46] fix(ci): repair macOS Android NDK symlinks --- .github/workflows/test-android.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-android.yml b/.github/workflows/test-android.yml index 8012e6602440..daec5b9c407f 100644 --- a/.github/workflows/test-android.yml +++ b/.github/workflows/test-android.yml @@ -67,7 +67,12 @@ jobs: - name: Restore Android Symlinks if: matrix.platform == 'ubuntu-latest' || matrix.platform == 'macos-latest' run: | - directory="${{ steps.setup-ndk.outputs.ndk-path }}/toolchains/llvm/prebuilt/linux-x86_64/bin" + case "$RUNNER_OS" in + Linux) prebuilt="linux-x86_64" ;; + macOS) prebuilt="darwin-x86_64" ;; + esac + + directory="${{ steps.setup-ndk.outputs.ndk-path }}/toolchains/llvm/prebuilt/${prebuilt}/bin" find "$directory" -type l | while read link; do current_target=$(readlink "$link") new_target="$directory/$(basename "$current_target")" From ebaab325dca82704fcb5a2e94e7e5e9267f8868f Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Tue, 7 Jul 2026 19:30:52 -0400 Subject: [PATCH 09/46] fix(ports): address GTK4 review findings --- .github/workflows/udeps.yml | 2 +- crates/tauri-runtime-wry/src/lib.rs | 10 +- crates/tauri-runtime-wry/src/monitor/linux.rs | 2 + crates/tauri-runtime/src/window.rs | 10 +- ports/muda/Cargo.lock | 1 + ports/muda/src/error.rs | 12 ++ ports/muda/src/icon.rs | 42 ++++++- .../src/platform_impl/gtk/about_dialog.rs | 16 +-- ports/muda/src/platform_impl/gtk/mod.rs | 109 ++++++++++++++---- ports/muda/src/platform_impl/macos/util.rs | 29 ++++- .../platform_impl/windows/dark_menu_bar.rs | 2 +- ports/tray-icon/LICENSE.spdx | 7 +- ports/tray-icon/README.md | 4 +- ports/tray-icon/src/lib.rs | 24 +++- ports/tray-icon/src/platform_impl/gtk/icon.rs | 45 +++++++- .../tray-icon/src/platform_impl/linux/mod.rs | 31 ++++- .../src/platform_impl/windows/mod.rs | 32 +++-- 17 files changed, 308 insertions(+), 70 deletions(-) diff --git a/.github/workflows/udeps.yml b/.github/workflows/udeps.yml index 4e6b316bae5d..a4b52f00fb8c 100644 --- a/.github/workflows/udeps.yml +++ b/.github/workflows/udeps.yml @@ -151,7 +151,7 @@ jobs: run: | sudo find /etc/apt/sources.list.d -maxdepth 1 -type f -exec grep -l "packages.microsoft.com" {} \; | xargs -r sudo rm -f sudo apt-get update - sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev libxdo-dev - name: Run udeps run: cargo udeps --manifest-path ${{ matrix.path }}/Cargo.toml --all-targets --all-features diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index e269456ad9e5..7b0626412da3 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -948,7 +948,10 @@ impl WindowBuilder for WindowBuilderWrapper { self } - /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size) on creation + /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size) on creation. + /// + /// On Linux/GTK4, this currently falls back to the full monitor geometry because + /// GDK4 no longer exposes a portable taskbar/panel-aware work area. /// /// ## Platform-specific /// @@ -960,7 +963,10 @@ impl WindowBuilder for WindowBuilderWrapper { self } - /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size) + /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size). + /// + /// On Linux/GTK4, this currently falls back to the full monitor geometry because + /// GDK4 no longer exposes a portable taskbar/panel-aware work area. /// on creation with a margin /// /// ## Platform-specific diff --git a/crates/tauri-runtime-wry/src/monitor/linux.rs b/crates/tauri-runtime-wry/src/monitor/linux.rs index 7b1d3df76686..e8645d9bf719 100644 --- a/crates/tauri-runtime-wry/src/monitor/linux.rs +++ b/crates/tauri-runtime-wry/src/monitor/linux.rs @@ -8,6 +8,8 @@ use tauri_runtime::dpi::{LogicalPosition, LogicalSize, PhysicalRect}; impl super::MonitorExt for tao::monitor::MonitorHandle { fn work_area(&self) -> PhysicalRect { + // GTK4/GDK4 no longer exposes a portable work-area API, so Linux falls + // back to full monitor geometry and does not account for panels/taskbars. let rect = self.gdk_monitor().geometry(); let scale_factor = self.scale_factor(); PhysicalRect { diff --git a/crates/tauri-runtime/src/window.rs b/crates/tauri-runtime/src/window.rs index 18e7cbae4429..94cf98381aef 100644 --- a/crates/tauri-runtime/src/window.rs +++ b/crates/tauri-runtime/src/window.rs @@ -287,7 +287,10 @@ pub trait WindowBuilder: WindowBuilderBase { #[must_use] fn inner_size_constraints(self, constraints: WindowSizeConstraints) -> Self; - /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size) on creation + /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size) on creation. + /// + /// On Linux/GTK4, this currently falls back to the full monitor geometry because + /// GDK4 no longer exposes a portable taskbar/panel-aware work area. /// /// ## Platform-specific /// @@ -295,7 +298,10 @@ pub trait WindowBuilder: WindowBuilderBase { #[must_use] fn prevent_overflow(self) -> Self; - /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size) + /// Prevent the window from overflowing the working area (e.g. monitor size - taskbar size). + /// + /// On Linux/GTK4, this currently falls back to the full monitor geometry because + /// GDK4 no longer exposes a portable taskbar/panel-aware work area. /// on creation with a margin /// /// ## Platform-specific diff --git a/ports/muda/Cargo.lock b/ports/muda/Cargo.lock index 06058496eec1..296be1728e22 100644 --- a/ports/muda/Cargo.lock +++ b/ports/muda/Cargo.lock @@ -3763,6 +3763,7 @@ dependencies = [ "raw-window-handle", "sha2", "soup3", + "tao", "tao-macros 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 2.0.18", "url", diff --git a/ports/muda/src/error.rs b/ports/muda/src/error.rs index 0e244ace27d7..d2a9557b28c1 100644 --- a/ports/muda/src/error.rs +++ b/ports/muda/src/error.rs @@ -46,6 +46,18 @@ pub enum Error { ))] #[error("This menu has already been initialized for this gtk window`")] AlreadyInitialized, + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + #[error("Unsupported gtk menu container")] + UnsupportedGtkContainer, #[error(transparent)] AcceleratorParseError(#[from] AcceleratorParseError), #[error("Gtk Window doesn't have an application")] diff --git a/ports/muda/src/icon.rs b/ports/muda/src/icon.rs index 51335908bd8c..be592e3bc22f 100644 --- a/ports/muda/src/icon.rs +++ b/ports/muda/src/icon.rs @@ -88,7 +88,21 @@ impl fmt::Display for BadIcon { impl Error for BadIcon { fn source(&self) -> Option<&(dyn Error + 'static)> { - Some(self) + match self { + BadIcon::OsError(e) => Some(e), + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "gtk" + ))] + BadIcon::PngEncodingError(e) => Some(e), + _ => None, + } } } @@ -99,6 +113,32 @@ pub(crate) struct RgbaIcon { pub(crate) height: u32, } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn bad_icon_validation_errors_have_no_source() { + assert!(BadIcon::ByteCountNotDivisibleBy4 { byte_count: 1 } + .source() + .is_none()); + assert!(BadIcon::DimensionsVsPixelCount { + width: 2, + height: 2, + width_x_height: 4, + pixel_count: 3, + } + .source() + .is_none()); + } + + #[test] + fn bad_icon_os_error_exposes_inner_source() { + let error = BadIcon::OsError(io::Error::new(io::ErrorKind::Other, "icon error")); + assert!(error.source().is_some()); + } +} + /// For platforms which don't have window icons (e.g. web) #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct NoIcon; diff --git a/ports/muda/src/platform_impl/gtk/about_dialog.rs b/ports/muda/src/platform_impl/gtk/about_dialog.rs index 2fcb0e40f042..b08be07902ca 100644 --- a/ports/muda/src/platform_impl/gtk/about_dialog.rs +++ b/ports/muda/src/platform_impl/gtk/about_dialog.rs @@ -50,20 +50,8 @@ impl AboutDialog { dialog.set_program_name(Some(name)); } - if let Some(ref version) = metadata.version { - dialog.set_version(Some(version)); - } - - if let Some(ref short_version) = metadata.short_version { - // GTK4 doesn't have a separate short version, but we can include it - // in the version string if both are set - if metadata.version.is_some() { - // Version is already set, we could append short_version but - // GTK4's AboutDialog handles this differently than macOS - let _ = short_version; // Acknowledge unused on GTK4 - } else { - dialog.set_version(Some(short_version)); - } + if let Some(version) = metadata.full_version() { + dialog.set_version(Some(&version)); } if let Some(ref copyright) = metadata.copyright { diff --git a/ports/muda/src/platform_impl/gtk/mod.rs b/ports/muda/src/platform_impl/gtk/mod.rs index 0015d4c711d5..47db75273255 100644 --- a/ports/muda/src/platform_impl/gtk/mod.rs +++ b/ports/muda/src/platform_impl/gtk/mod.rs @@ -165,9 +165,10 @@ impl Menu { } pub fn add_menu_item(&mut self, item: &dyn IsMenuItem, op: AddOp) -> crate::Result<()> { + let child = item.child(); match op { - AddOp::Append => self.children.push(item.child()), - AddOp::Insert(i) => self.children.insert(i, item.child()), + AddOp::Append => self.children.push(child.clone()), + AddOp::Insert(i) => self.children.insert(i, child.clone()), } for (menu_id, menu_bar) in &self.instances { @@ -178,6 +179,10 @@ impl Menu { AddOp::Append => parent_menu.append_item(>k_item), AddOp::Insert(position) => parent_menu.insert_item(position as i32, >k_item), } + + if let Some((id, row)) = child.borrow().custom_child() { + menu_bar.add_custom_child(&id, &row); + } } #[cfg(all(feature = "linux-ksni", target_os = "linux"))] @@ -303,6 +308,8 @@ impl Menu { } else if container.type_().name() == "GtkStack" { let gtk_box = container.dynamic_cast_ref::().unwrap(); gtk_box.add_child(menu_bar); + } else { + return Err(crate::Error::UnsupportedGtkContainer); } } else { window.set_child(Some(menu_bar)); @@ -412,7 +419,12 @@ impl Menu { // Rebuild the context instance every time so it reflects the current // labels, icons, and checked state rather than a stale first build. - self.instances.remove(&self.ctx_menu_id); + if let Some(old) = self.instances.remove(&self.ctx_menu_id) { + let old_context_menu = old.context_menu(); + if old_context_menu.parent().is_some() { + old_context_menu.unparent(); + } + } { let action_group = action_group_from_app(&app); @@ -510,6 +522,12 @@ impl GtkMenuChild { _ => unreachable!("This is a bug report to https://github.com/tauri-apps/muda"), } } + + fn add_custom_child(&self, id: &str, widget: &impl IsA) { + if let GtkMenuChild::ContextMenu { widget: w, .. } = self { + w.add_child(widget, id); + } + } } pub struct MenuChild { @@ -666,9 +684,10 @@ impl MenuChild { } pub fn add_menu_item(&mut self, item: &dyn IsMenuItem, op: AddOp) -> crate::Result<()> { + let child = item.child(); match op { - AddOp::Append => self.children.push(item.child()), - AddOp::Insert(i) => self.children.insert(i, item.child()), + AddOp::Append => self.children.push(child.clone()), + AddOp::Insert(i) => self.children.insert(i, child.clone()), } #[cfg(all(feature = "linux-ksni", target_os = "linux"))] @@ -684,6 +703,10 @@ impl MenuChild { AddOp::Append => parent_menu.append_item(>k_item), AddOp::Insert(position) => parent_menu.insert_item(position as i32, >k_item), } + + if let Some((id, row)) = child.borrow().custom_child() { + gtk_child.add_custom_child(&id, &row); + } } } @@ -787,24 +810,36 @@ impl MenuChild { return false; // TODO: better error }; - if !self.instances.contains_key(&self.ctx_menu_id) { - let menu = gio::Menu::new(); - let widget = gtk::PopoverMenu::from_model(Some(&menu)); + if let Some(old) = self.instances.remove(&self.ctx_menu_id) { + if let Some(old) = old.first() { + let old_context_menu = old.context_menu(); + if old_context_menu.parent().is_some() { + old_context_menu.unparent(); + } + } + } - let action_group = action_group_from_app(&app); - window.insert_action_group(DEFAULT_ACTION_GROUP, Some(&action_group)); + let menu = gio::Menu::new(); + let widget = gtk::PopoverMenu::from_model(Some(&menu)); - let menu = GtkMenuChild::ContextMenu { - id: self.ctx_menu_id, - widget, - menu, - app, - }; + let action_group = action_group_from_app(&app); + window.insert_action_group(DEFAULT_ACTION_GROUP, Some(&action_group)); - self.instances.insert(self.ctx_menu_id, vec![menu]); + let menu = GtkMenuChild::ContextMenu { + id: self.ctx_menu_id, + widget, + menu, + app, + }; - for item in self.items() { - let _ = self.add_menu_item_with_id(item.as_ref(), self.ctx_menu_id); + self.instances.insert(self.ctx_menu_id, vec![menu]); + + for item in self.items() { + let _ = self.add_menu_item_with_id(item.as_ref(), self.ctx_menu_id); + } + if let Some(menus) = self.instances.get(&self.ctx_menu_id) { + if let Some(menu) = menus.first() { + self.bind_custom_children(menu); } } @@ -832,6 +867,19 @@ impl MenuChild { } impl MenuChild { + fn bind_custom_children(&self, menu: &GtkMenuChild) { + fn walk(children: &[Rc>], menu: &GtkMenuChild) { + for child in children { + let child = child.borrow(); + if let Some((id, row)) = child.custom_child() { + menu.add_custom_child(&id, &row); + } + walk(&child.children, menu); + } + } + walk(&self.children, menu); + } + pub fn new( text: &str, enabled: bool, @@ -912,6 +960,9 @@ impl MenuChild { // GIO MenuItems are immutable after insertion, so we need to remove and reinsert let detailed_action = self.detailed_action(); + let custom_child_id = self.icon.as_ref().map(|_| self.id.as_ref().to_string()); + let custom_child_icon = self.icon.clone(); + let custom_child_text = self.text.clone(); for children in self.instances.values_mut() { for child in children.iter_mut() { @@ -941,8 +992,9 @@ impl MenuChild { ); // Copy icon if present - if let Some(icon) = &self.icon { + if let (Some(id), Some(icon)) = (&custom_child_id, &custom_child_icon) { new_item.set_icon(&icon.inner.to_bytes_icon()); + new_item.set_attribute_value("custom", Some(&id.to_variant())); } // Insert at same position @@ -954,6 +1006,11 @@ impl MenuChild { GtkMenuChild::Submenu { item, .. } => *item = new_item, _ => {} } + + if let (Some(id), Some(icon)) = (&custom_child_id, &custom_child_icon) { + let row = custom_menu_row(icon, &custom_child_text, &detailed_action); + child.add_custom_child(id, &row); + } } } } @@ -1372,6 +1429,9 @@ impl MenuChild { // GIO MenuItems are immutable after insertion, so we need to remove and reinsert let detailed_action = self.detailed_action(); + let custom_child_id = self.id.as_ref().to_string(); + let custom_child_icon = self.icon.clone(); + let custom_child_text = self.text.clone(); for children in self.instances.values_mut() { for child in children.iter_mut() { @@ -1401,8 +1461,10 @@ impl MenuChild { ); // Set icon if present - if let Some(icon) = &self.icon { + if let Some(icon) = &custom_child_icon { new_item.set_icon(&icon.inner.to_bytes_icon()); + new_item + .set_attribute_value("custom", Some(&custom_child_id.to_variant())); } // Insert at same position @@ -1414,6 +1476,11 @@ impl MenuChild { GtkMenuChild::Submenu { item, .. } => *item = new_item, _ => {} } + + if let Some(icon) = &custom_child_icon { + let row = custom_menu_row(icon, &custom_child_text, &detailed_action); + child.add_custom_child(&custom_child_id, &row); + } } } } diff --git a/ports/muda/src/platform_impl/macos/util.rs b/ports/muda/src/platform_impl/macos/util.rs index da021aa70004..b4a94f8f81aa 100644 --- a/ports/muda/src/platform_impl/macos/util.rs +++ b/ports/muda/src/platform_impl/macos/util.rs @@ -12,9 +12,28 @@ use std::str; /// /// `&` can be escaped as `&&` to prevent stripping, in which case a single `&` will be output. pub fn strip_mnemonic>(string: S) -> String { - string - .as_ref() - .replace("&&", "[~~]") - .replace('&', "") - .replace("[~~]", "&") + let string = string.as_ref(); + let mut result = String::with_capacity(string.len()); + let mut chars = string.chars().peekable(); + + while let Some(c) = chars.next() { + if c == '&' && chars.peek() == Some(&'&') { + result.push('&'); + chars.next(); + } else if c != '&' { + result.push(c); + } + } + + result +} + +#[cfg(test)] +mod tests { + use super::strip_mnemonic; + + #[test] + fn strips_mnemonics_without_placeholder_collisions() { + assert_eq!(strip_mnemonic("&File && Edit [~~]"), "File & Edit [~~]"); + } } diff --git a/ports/muda/src/platform_impl/windows/dark_menu_bar.rs b/ports/muda/src/platform_impl/windows/dark_menu_bar.rs index 55968f3c6fd8..021cc88e44e6 100644 --- a/ports/muda/src/platform_impl/windows/dark_menu_bar.rs +++ b/ports/muda/src/platform_impl/windows/dark_menu_bar.rs @@ -332,7 +332,7 @@ fn is_high_contrast() -> bool { const HCF_HIGHCONTRASTON: u32 = 1; let mut hc = HIGHCONTRASTA { - cbSize: 0, + cbSize: std::mem::size_of::() as _, dwFlags: Default::default(), lpszDefaultScheme: std::ptr::null_mut(), }; diff --git a/ports/tray-icon/LICENSE.spdx b/ports/tray-icon/LICENSE.spdx index c6f204fdb001..4708994c5d25 100644 --- a/ports/tray-icon/LICENSE.spdx +++ b/ports/tray-icon/LICENSE.spdx @@ -1,11 +1,10 @@ SPDXVersion: SPDX-2.1 DataLicense: CC0-1.0 PackageName: tray-icon -DataFormat: SPDXRef-1 +SPDXID: SPDXRef-1 PackageSupplier: Organization: The Tauri Programme in the Commons Conservancy PackageHomePage: https://tauri.app -PackageLicenseDeclared: Apache-2.0 -PackageLicenseDeclared: MIT +PackageLicenseDeclared: Apache-2.0 OR MIT PackageCopyrightText: 2020-2022, The Tauri Programme in the Commons Conservancy PackageSummary: Create tray icons for desktop applications. @@ -16,4 +15,4 @@ Created: 2022-12-05T09:00:00Z PackageDownloadLocation: git://github.com/tauri-apps/tray-icon PackageDownloadLocation: git+https://github.com/tauri-apps/tray-icon.git PackageDownloadLocation: git+ssh://github.com/tauri-apps/tray-icon.git -Creator: Person: Daniel Thompson-Yvetot \ No newline at end of file +Creator: Person: Daniel Thompson-Yvetot diff --git a/ports/tray-icon/README.md b/ports/tray-icon/README.md index f249868a9fd6..23f3959f77e5 100644 --- a/ports/tray-icon/README.md +++ b/ports/tray-icon/README.md @@ -15,12 +15,12 @@ tray-icon lets you create tray icons for desktop applications. ### Cargo Features - `common-controls-v6`: Use `TaskDialogIndirect` API from `ComCtl32.dll` v6 on Windows for showing the predefined `About` menu item dialog. -- `libxdo`: Enables linking to `libxdo` which is used for the predfined `Copy`, `Cut`, `Paste` and `SelectAll` menu item, see https://github.com/tauri-apps/muda#cargo-features +- `libxdo`: Enables linking to `libxdo` which is used for the predefined `Copy`, `Cut`, `Paste` and `SelectAll` menu item, see https://github.com/tauri-apps/muda#cargo-features - `serde`: Enables de/serializing derives. ## Dependencies (Linux Only) -On Linux, `gtk`, `libxdo` is used to make the predfined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work and `libappindicator` or `libayatnat-appindicator` are used to create the tray icon, so make sure to install them on your system. +On Linux, `gtk`, `libxdo` is used to make the predefined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work and `libappindicator` or `libayatana-appindicator` are used to create the tray icon, so make sure to install them on your system. #### Arch Linux / Manjaro: diff --git a/ports/tray-icon/src/lib.rs b/ports/tray-icon/src/lib.rs index 13d80c966e36..dda9ec5b2338 100644 --- a/ports/tray-icon/src/lib.rs +++ b/ports/tray-icon/src/lib.rs @@ -15,15 +15,16 @@ //! - Windows //! - macOS //! - Linux (gtk Only) +//! - FreeBSD / DragonFly BSD / NetBSD / OpenBSD (gtk Only) //! //! # Platform-specific notes: //! -//! - On Windows and Linux, an event loop must be running on the thread, on Windows, a win32 event loop and on Linux, a gtk event loop. It doesn't need to be the main thread but you have to create the tray icon on the same thread as the event loop. +//! - On Windows, Linux, and BSD, an event loop must be running on the thread, on Windows, a win32 event loop and on Linux or BSD, a gtk event loop. It doesn't need to be the main thread but you have to create the tray icon on the same thread as the event loop. //! - On macOS, an event loop must be running on the main thread so you also need to create the tray icon on the main thread. You must make sure that the event loop is already running and not just created before creating a TrayIcon to prevent issues with fullscreen apps. In Winit for example the earliest you can create icons is on [`StartCause::Init`](https://docs.rs/winit/latest/winit/event/enum.StartCause.html#variant.Init). //! //! # Dependencies (Linux Only) //! -//! On Linux, `gtk`, `libxdo` is used to make the predfined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work and `libappindicator` or `libayatnat-appindicator` are used to create the tray icon, so make sure to install them on your system. +//! On Linux, `gtk`, `libxdo` is used to make the predefined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work and `libappindicator` or `libayatana-appindicator` are used to create the tray icon, so make sure to install them on your system. //! //! #### Arch Linux / Manjaro: //! @@ -225,12 +226,17 @@ impl Default for TrayIconAttributes { } /// [`TrayIcon`] builder struct and associated methods. -#[derive(Default)] pub struct TrayIconBuilder { id: TrayIconId, attrs: TrayIconAttributes, } +impl Default for TrayIconBuilder { + fn default() -> Self { + Self::new() + } +} + impl TrayIconBuilder { /// Creates a new [`TrayIconBuilder`] with default [`TrayIconAttributes`]. /// @@ -551,7 +557,7 @@ impl TrayIcon { /// /// ## Platform-specific: /// -/// - **Linux**: Unsupported. The event is not emmited even though the icon is shown +/// - **Linux**: Unsupported. The event is not emitted even though the icon is shown /// and will still show a context menu on right click. #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -705,6 +711,16 @@ impl TrayIconEvent { #[cfg(test)] mod tests { + use super::*; + + #[test] + fn default_builder_uses_unique_id() { + let first = TrayIconBuilder::default(); + let second = TrayIconBuilder::default(); + + assert!(!first.id.as_ref().is_empty()); + assert_ne!(first.id, second.id); + } #[cfg(feature = "serde")] #[test] diff --git a/ports/tray-icon/src/platform_impl/gtk/icon.rs b/ports/tray-icon/src/platform_impl/gtk/icon.rs index de554a05e5aa..9dade60ff10a 100644 --- a/ports/tray-icon/src/platform_impl/gtk/icon.rs +++ b/ports/tray-icon/src/platform_impl/gtk/icon.rs @@ -8,7 +8,7 @@ use std::{fs::File, io::BufWriter, path::Path}; -use crate::icon::BadIcon; +use crate::icon::{BadIcon, PIXEL_SIZE}; #[derive(Debug, Clone)] pub struct PlatformIcon { @@ -19,6 +19,23 @@ pub struct PlatformIcon { impl PlatformIcon { pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { + if !rgba.len().is_multiple_of(PIXEL_SIZE) { + return Err(BadIcon::ByteCountNotDivisibleBy4 { + byte_count: rgba.len(), + }); + } + + let pixel_count = rgba.len() / PIXEL_SIZE; + let width_x_height = width as usize * height as usize; + if pixel_count != width_x_height { + return Err(BadIcon::DimensionsVsPixelCount { + width, + height, + width_x_height, + pixel_count, + }); + } + Ok(Self { rgba, width: width as i32, @@ -40,3 +57,29 @@ impl PlatformIcon { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn from_rgba_rejects_invalid_byte_count() { + assert!(matches!( + PlatformIcon::from_rgba(vec![0, 0, 0], 1, 1), + Err(BadIcon::ByteCountNotDivisibleBy4 { byte_count: 3 }) + )); + } + + #[test] + fn from_rgba_rejects_dimension_mismatch() { + assert!(matches!( + PlatformIcon::from_rgba(vec![0, 0, 0, 0], 2, 1), + Err(BadIcon::DimensionsVsPixelCount { + width: 2, + height: 1, + width_x_height: 2, + pixel_count: 1, + }) + )); + } +} diff --git a/ports/tray-icon/src/platform_impl/linux/mod.rs b/ports/tray-icon/src/platform_impl/linux/mod.rs index 03f885798b08..11940bdbb544 100644 --- a/ports/tray-icon/src/platform_impl/linux/mod.rs +++ b/ports/tray-icon/src/platform_impl/linux/mod.rs @@ -13,11 +13,14 @@ mod tray; use std::{ sync::{ atomic::{AtomicBool, Ordering}, - Arc, + Arc, Mutex, }, thread, }; +use crossbeam_channel::{unbounded, Sender}; +use once_cell::sync::Lazy; + pub(crate) use icon::PlatformIcon; use tray::Tray; @@ -28,6 +31,29 @@ pub struct TrayIcon { shutdown: Arc, } +static MENU_UPDATE_SUBSCRIBERS: Lazy>>> = + Lazy::new(|| Mutex::new(Vec::new())); +static MENU_UPDATE_DISPATCHER: Lazy<()> = Lazy::new(|| { + thread::spawn(|| { + while muda::recv_menu_update().is_ok() { + let Ok(mut subscribers) = MENU_UPDATE_SUBSCRIBERS.lock() else { + continue; + }; + subscribers.retain(|subscriber| subscriber.send(()).is_ok()); + } + }); +}); + +fn subscribe_menu_updates() -> crossbeam_channel::Receiver<()> { + Lazy::force(&MENU_UPDATE_DISPATCHER); + + let (sender, receiver) = unbounded(); + if let Ok(mut subscribers) = MENU_UPDATE_SUBSCRIBERS.lock() { + subscribers.push(sender); + } + receiver +} + impl TrayIcon { pub fn new(id: TrayIconId, attrs: TrayIconAttributes) -> crate::Result { let icon = attrs.icon.map(|icon| icon.inner.into()); @@ -46,8 +72,9 @@ impl TrayIcon { let update_tray_handle = tray_handle.clone(); let update_shutdown = shutdown.clone(); + let update_receiver = subscribe_menu_updates(); thread::spawn(move || { - while muda::recv_menu_update().is_ok() { + while update_receiver.recv().is_ok() { if update_shutdown.load(Ordering::Relaxed) { break; } diff --git a/ports/tray-icon/src/platform_impl/windows/mod.rs b/ports/tray-icon/src/platform_impl/windows/mod.rs index a45da9e48761..56fc5a0b3e26 100644 --- a/ports/tray-icon/src/platform_impl/windows/mod.rs +++ b/ports/tray-icon/src/platform_impl/windows/mod.rs @@ -233,11 +233,7 @@ impl TrayIcon { ..std::mem::zeroed() }; if let Some(tooltip) = &tooltip { - let tip = util::encode_wide(tooltip.as_ref()); - #[allow(clippy::manual_memcpy)] - for i in 0..tip.len().min(128) { - nid.szTip[i] = tip[i]; - } + copy_tooltip_to_buffer(tooltip.as_ref(), &mut nid.szTip); } if Shell_NotifyIconW(NIM_MODIFY, &nid) == 0 { @@ -581,11 +577,7 @@ unsafe fn register_tray_icon( if let Some(tooltip) = tooltip { flags |= NIF_TIP; - let tip = util::encode_wide(tooltip); - #[allow(clippy::manual_memcpy)] - for i in 0..tip.len().min(128) { - sz_tip[i] = tip[i]; - } + copy_tooltip_to_buffer(tooltip, &mut sz_tip); } #[allow(non_snake_case)] @@ -612,6 +604,26 @@ unsafe fn register_tray_icon( Shell_NotifyIconW(NIM_ADD, &mut nid as _) == TRUE } +fn copy_tooltip_to_buffer(tooltip: &str, buffer: &mut [u16; 128]) { + let tip = util::encode_wide(tooltip); + let len = tip.len().min(buffer.len() - 1); + buffer[..len].copy_from_slice(&tip[..len]); + buffer[len] = 0; +} + +#[cfg(test)] +mod tests { + use super::copy_tooltip_to_buffer; + + #[test] + fn tooltip_buffer_is_always_null_terminated() { + let mut buffer = [1; 128]; + copy_tooltip_to_buffer(&"a".repeat(128), &mut buffer); + + assert_eq!(buffer[127], 0); + } +} + #[inline] unsafe fn remove_tray_icon(hwnd: HWND, id: u32) { let nid = NOTIFYICONDATAW { From 716ef7f78bdb85097231bf2fe60fc3d861f4c8c1 Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Wed, 8 Jul 2026 10:49:00 -0400 Subject: [PATCH 10/46] fix(tao): use packed stride for GTK icons --- ports/tao/src/platform_impl/linux/icon.rs | 28 +++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/ports/tao/src/platform_impl/linux/icon.rs b/ports/tao/src/platform_impl/linux/icon.rs index e7c7581a7611..eb40129b2e2b 100644 --- a/ports/tao/src/platform_impl/linux/icon.rs +++ b/ports/tao/src/platform_impl/linux/icon.rs @@ -40,17 +40,27 @@ impl PlatformIcon { /// `rgba.len() / 4`. Otherwise, this will return a `BadIcon` error. pub fn from_rgba(rgba: Vec, width: u32, height: u32) -> Result { let icon = RgbaIcon::from_rgba(rgba, width, height)?; - let row_stride = Pixbuf::calculate_rowstride( - Colorspace::Rgb, - true, - 8, - icon.width as i32, - icon.height as i32, - ); + let width = i32::try_from(icon.width) + .map_err(|_| BadIcon::DimensionsMultiplyOverflow { width, height })?; + let height = i32::try_from(icon.height).map_err(|_| BadIcon::DimensionsMultiplyOverflow { + width: icon.width, + height, + })?; + let row_stride = i32::try_from(icon.width.checked_mul(4).ok_or( + BadIcon::DimensionsMultiplyOverflow { + width: icon.width, + height: icon.height, + }, + )?) + .map_err(|_| BadIcon::DimensionsMultiplyOverflow { + width: icon.width, + height: icon.height, + })?; + Ok(Self { raw: icon.rgba, - width: icon.width as i32, - height: icon.height as i32, + width, + height, row_stride, }) } From 9c739a7db5d1404a6f9a144a4fdd8b4368524546 Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Wed, 8 Jul 2026 13:26:47 -0400 Subject: [PATCH 11/46] fix(tray-icon): document KSNI backend and drop stale lock --- ports/tray-icon/Cargo.lock | 5674 ------------------------------------ ports/tray-icon/README.md | 13 +- ports/tray-icon/src/lib.rs | 15 +- 3 files changed, 16 insertions(+), 5686 deletions(-) delete mode 100644 ports/tray-icon/Cargo.lock diff --git a/ports/tray-icon/Cargo.lock b/ports/tray-icon/Cargo.lock deleted file mode 100644 index 2c02774253ca..000000000000 --- a/ports/tray-icon/Cargo.lock +++ /dev/null @@ -1,5674 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[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.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d3b8f9bae46a948369bc4a03e815d4ed6d616bd00de4051133a5019dc31c5a" - -[[package]] -name = "accesskit_atspi_common" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5dd55e6e94949498698daf4d48fb5659e824d7abec0d394089656ceaf99d4f" -dependencies = [ - "accesskit", - "accesskit_consumer", - "atspi-common", - "serde", - "thiserror 1.0.69", - "zvariant", -] - -[[package]] -name = "accesskit_consumer" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459" -dependencies = [ - "accesskit", - "hashbrown 0.15.5", - "immutable-chunkmap", -] - -[[package]] -name = "accesskit_macos" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7329821f3bd1101e03a7d2e03bd339e3ac0dc64c70b4c9f9ae1949e3ba8dece1" -dependencies = [ - "accesskit", - "accesskit_consumer", - "hashbrown 0.15.5", - "objc2 0.5.2", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "accesskit_unix" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcee751cc20d88678c33edaf9c07e8b693cd02819fe89053776f5313492273f5" -dependencies = [ - "accesskit", - "accesskit_atspi_common", - "async-channel", - "async-executor", - "async-task", - "atspi", - "futures-lite", - "futures-util", - "serde", - "zbus", -] - -[[package]] -name = "accesskit_windows" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24fcd5d23d70670992b823e735e859374d694a3d12bfd8dd32bd3bd8bedb5d81" -dependencies = [ - "accesskit", - "accesskit_consumer", - "hashbrown 0.15.5", - "paste", - "static_assertions", - "windows 0.58.0", - "windows-core 0.58.0", -] - -[[package]] -name = "accesskit_winit" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6a48dad5530b6deb9fc7a52cc6c3bf72cdd9eb8157ac9d32d69f2427a5e879" -dependencies = [ - "accesskit", - "accesskit_macos", - "accesskit_unix", - "accesskit_windows", - "raw-window-handle", - "winit", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "getrandom 0.3.4", - "once_cell", - "version_check", - "zerocopy", -] - -[[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.13.0", - "cc", - "jni 0.22.4", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys 0.6.0+11769913", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "arboard" -version = "3.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" -dependencies = [ - "clipboard-win", - "image", - "log", - "objc2 0.6.4", - "objc2-app-kit 0.3.2", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.2", - "parking_lot", - "percent-encoding", - "windows-sys 0.60.2", - "x11rb", -] - -[[package]] -name = "arc-swap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" -dependencies = [ - "rustversion", -] - -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" - -[[package]] -name = "as-raw-xcb-connection" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" - -[[package]] -name = "ash" -version = "0.38.0+1.3.281" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" -dependencies = [ - "libloading 0.8.9", -] - -[[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-fs" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" -dependencies = [ - "async-lock", - "blocking", - "futures-lite", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" -dependencies = [ - "event-listener", - "event-listener-strategy", - "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 2.0.118", -] - -[[package]] -name = "async-signal" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" -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-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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "atk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" -dependencies = [ - "atk-sys", - "glib 0.18.5", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" -dependencies = [ - "glib-sys 0.18.1", - "gobject-sys 0.18.0", - "libc", - "system-deps 6.2.2", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "atspi" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be534b16650e35237bb1ed189ba2aab86ce65e88cc84c66f4935ba38575cecbf" -dependencies = [ - "atspi-common", - "atspi-connection", - "atspi-proxies", -] - -[[package]] -name = "atspi-common" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1909ed2dc01d0a17505d89311d192518507e8a056a48148e3598fef5e7bb6ba7" -dependencies = [ - "enumflags2", - "serde", - "static_assertions", - "zbus", - "zbus-lockstep", - "zbus-lockstep-macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "atspi-connection" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "430c5960624a4baaa511c9c0fcc2218e3b58f5dbcc47e6190cafee344b873333" -dependencies = [ - "atspi-common", - "atspi-proxies", - "futures-lite", - "zbus", -] - -[[package]] -name = "atspi-proxies" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e6c5de3e524cf967569722446bcd458d5032348554d9a17d7d72b041ab7496" -dependencies = [ - "atspi-common", - "serde", - "zbus", - "zvariant", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" - -[[package]] -name = "bit-set" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" -dependencies = [ - "serde_core", -] - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -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 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 = "bumpalo" -version = "3.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" - -[[package]] -name = "bytemuck" -version = "1.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - -[[package]] -name = "bytes" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" - -[[package]] -name = "cairo-rs" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" -dependencies = [ - "bitflags 2.13.0", - "cairo-sys-rs 0.18.2", - "glib 0.18.5", - "libc", - "once_cell", - "thiserror 1.0.69", -] - -[[package]] -name = "cairo-rs" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc8d9aa793480744cd9a0524fef1a2e197d9eaa0f739cde19d16aba530dcb95" -dependencies = [ - "bitflags 2.13.0", - "cairo-sys-rs 0.22.0", - "glib 0.22.8", - "libc", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "glib-sys 0.18.1", - "libc", - "system-deps 6.2.2", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8b4985713047f5faee02b8db6a6ef32bbb50269ff53c1aee716d1d195b76d54" -dependencies = [ - "glib-sys 0.22.8", - "libc", - "system-deps 7.0.8", -] - -[[package]] -name = "calloop" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" -dependencies = [ - "bitflags 2.13.0", - "log", - "polling", - "rustix 0.38.44", - "slab", - "thiserror 1.0.69", -] - -[[package]] -name = "calloop" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" -dependencies = [ - "bitflags 2.13.0", - "polling", - "rustix 1.1.4", - "slab", - "tracing", -] - -[[package]] -name = "calloop-wayland-source" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" -dependencies = [ - "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 = "cc" -version = "1.2.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" -dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon 0.12.16", -] - -[[package]] -name = "cfg-expr" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb693542bcafa528e198be0ebd9d3632ca5b7c93dbe7237460e199910835997c" -dependencies = [ - "smallvec", - "target-lexicon 0.13.5", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -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 = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags 1.3.2", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] - -[[package]] -name = "clipboard-win" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" -dependencies = [ - "error-code", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "core-graphics" -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 0.1.3", - "foreign-types", - "libc", -] - -[[package]] -name = "core-graphics" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" -dependencies = [ - "bitflags 2.13.0", - "core-foundation 0.10.1", - "core-graphics-types 0.2.0", - "foreign-types", - "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 = "core-graphics-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" -dependencies = [ - "bitflags 2.13.0", - "core-foundation 0.10.1", - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" - -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cursor-icon" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" - -[[package]] -name = "dbus" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" -dependencies = [ - "libc", - "libdbus-sys", - "windows-sys 0.61.2", -] - -[[package]] -name = "dbus-codegen" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a49da9fdfbe872d4841d56605dc42efa5e6ca3291299b87f44e1cde91a28617c" -dependencies = [ - "clap", - "dbus", - "xml-rs", -] - -[[package]] -name = "dbus-tree" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f456e698ae8e54575e19ddb1f9b7bce2298568524f215496b248eb9498b4f508" -dependencies = [ - "dbus", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.61.2", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" -dependencies = [ - "bitflags 2.13.0", - "block2 0.6.2", - "libc", - "objc2 0.6.4", -] - -[[package]] -name = "displaydoc" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[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 = "dlopen2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" -dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", -] - -[[package]] -name = "dlopen2_derive" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -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" -dependencies = [ - "serde", -] - -[[package]] -name = "ecolor" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc4feb366740ded31a004a0e4452fbf84e80ef432ecf8314c485210229672fd1" -dependencies = [ - "bytemuck", - "emath", -] - -[[package]] -name = "eframe" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0dfe0859f3fb1bc6424c57d41e10e9093fe938f426b691e42272c2f336d915c" -dependencies = [ - "ahash", - "bytemuck", - "document-features", - "egui", - "egui-wgpu", - "egui-winit", - "egui_glow", - "glow", - "glutin", - "glutin-winit", - "image", - "js-sys", - "log", - "objc2 0.5.2", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", - "parking_lot", - "percent-encoding", - "profiling", - "raw-window-handle", - "static_assertions", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "web-time", - "winapi", - "windows-sys 0.59.0", - "winit", -] - -[[package]] -name = "egui" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" -dependencies = [ - "accesskit", - "ahash", - "bitflags 2.13.0", - "emath", - "epaint", - "log", - "nohash-hasher", - "profiling", -] - -[[package]] -name = "egui-wgpu" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d319dfef570f699b6e9114e235e862a2ddcf75f0d1a061de9e1328d92146d820" -dependencies = [ - "ahash", - "bytemuck", - "document-features", - "egui", - "epaint", - "log", - "profiling", - "thiserror 1.0.69", - "type-map", - "web-time", - "wgpu", - "winit", -] - -[[package]] -name = "egui-winit" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9dfbb78fe4eb9c3a39ad528b90ee5915c252e77bbab9d4ebc576541ab67e13" -dependencies = [ - "accesskit_winit", - "ahash", - "arboard", - "bytemuck", - "egui", - "log", - "profiling", - "raw-window-handle", - "smithay-clipboard", - "web-time", - "webbrowser", - "winit", -] - -[[package]] -name = "egui_glow" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "910906e3f042ea6d2378ec12a6fd07698e14ddae68aed2d819ffe944a73aab9e" -dependencies = [ - "ahash", - "bytemuck", - "egui", - "glow", - "log", - "memoffset", - "profiling", - "wasm-bindgen", - "web-sys", - "winit", -] - -[[package]] -name = "emath" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "endi" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" - -[[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 2.0.118", -] - -[[package]] -name = "epaint" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fcc0f5a7c613afd2dee5e4b30c3e6acafb8ad6f0edb06068811f708a67c562" -dependencies = [ - "ab_glyph", - "ahash", - "bytemuck", - "ecolor", - "emath", - "epaint_default_fonts", - "log", - "nohash-hasher", - "parking_lot", - "profiling", -] - -[[package]] -name = "epaint_default_fonts" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7e7a64c02cf7a5b51e745a9e45f60660a286f151c238b9d397b3e923f5082f" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "error-code" -version = "3.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" - -[[package]] -name = "event-listener" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener", - "pin-project-lite", -] - -[[package]] -name = "fastrand" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" - -[[package]] -name = "fax" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[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 = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "flate2" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-channel" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-executor" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "futures-sink" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" - -[[package]] -name = "futures-task" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" - -[[package]] -name = "futures-util" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" -dependencies = [ - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "slab", -] - -[[package]] -name = "gdk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" -dependencies = [ - "cairo-rs 0.18.5", - "gdk-pixbuf 0.18.5", - "gdk-sys", - "gio 0.18.4", - "glib 0.18.5", - "libc", - "pango 0.18.3", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" -dependencies = [ - "gdk-pixbuf-sys 0.18.0", - "gio 0.18.4", - "glib 0.18.5", - "libc", - "once_cell", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f420376dbee041b2db374ce4573892a36222bb3f6c0c43e24f0d67eae9b646" -dependencies = [ - "gdk-pixbuf-sys 0.22.0", - "gio 0.22.8", - "glib 0.22.8", - "libc", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" -dependencies = [ - "gio-sys 0.18.1", - "glib-sys 0.18.1", - "gobject-sys 0.18.0", - "libc", - "system-deps 6.2.2", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f31b37b1fc4b48b54f6b91b7ef04c18e00b4585d98359dd7b998774bbd91fb" -dependencies = [ - "gio-sys 0.22.8", - "glib-sys 0.22.8", - "gobject-sys 0.22.6", - "libc", - "system-deps 7.0.8", -] - -[[package]] -name = "gdk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" -dependencies = [ - "cairo-sys-rs 0.18.2", - "gdk-pixbuf-sys 0.18.0", - "gio-sys 0.18.1", - "glib-sys 0.18.1", - "gobject-sys 0.18.0", - "libc", - "pango-sys 0.18.0", - "pkg-config", - "system-deps 6.2.2", -] - -[[package]] -name = "gdk4" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d81e2a6c6ecba2aab60633a98df1868b03fa0bfdce8105edc27c1bccf71f0e39" -dependencies = [ - "cairo-rs 0.22.0", - "gdk-pixbuf 0.22.0", - "gdk4-sys", - "gio 0.22.8", - "glib 0.22.8", - "libc", - "pango 0.22.8", -] - -[[package]] -name = "gdk4-sys" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d8f608d8d7d229975c4d0d026f5d3071598c4ddab3c5262b0a31840fec78d13" -dependencies = [ - "cairo-sys-rs 0.22.0", - "gdk-pixbuf-sys 0.22.0", - "gio-sys 0.22.8", - "glib-sys 0.22.8", - "gobject-sys 0.22.6", - "libc", - "pango-sys 0.22.0", - "pkg-config", - "system-deps 7.0.8", -] - -[[package]] -name = "gdk4-wayland" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d95828dadc0357dee236cc6a5712808bd894d3217159982592ce24f2b8aaf7" -dependencies = [ - "gdk4", - "gdk4-wayland-sys", - "gio 0.22.8", - "glib 0.22.8", - "libc", - "wayland-backend", - "wayland-client", - "wayland-protocols", -] - -[[package]] -name = "gdk4-wayland-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653cafb8715f2ac1c56edaf8060d9360ae3acbe3c6fb61b676a2917d42b668cf" -dependencies = [ - "glib-sys 0.22.8", - "libc", - "system-deps 7.0.8", -] - -[[package]] -name = "gdk4-x11" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d892b4cf5a07e90e1390e93cd792975746c68b59f790a2de9e96ce77211ea9a" -dependencies = [ - "gdk4", - "gdk4-x11-sys", - "gio 0.22.8", - "glib 0.22.8", - "libc", -] - -[[package]] -name = "gdk4-x11-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d41f2e28f62378b081288914325d73bddbb6ccbbadb41aa6392afc71d27002" -dependencies = [ - "gdk4-sys", - "glib-sys 0.22.8", - "libc", - "system-deps 7.0.8", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "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 = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "libc", - "r-efi 5.3.0", - "wasip2", -] - -[[package]] -name = "getrandom" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" -dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", -] - -[[package]] -name = "gio" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys 0.18.1", - "glib 0.18.5", - "libc", - "once_cell", - "pin-project-lite", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "gio" -version = "0.22.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3e1f669909c326b9413bde5a742097b8c90a7d78f45326db13668984769ded" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys 0.22.8", - "glib 0.22.8", - "libc", - "pin-project-lite", - "smallvec", -] - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys 0.18.1", - "gobject-sys 0.18.0", - "libc", - "system-deps 6.2.2", - "winapi", -] - -[[package]] -name = "gio-sys" -version = "0.22.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353fdc7da7cd16da916104b1e0e4e7de380ec9c8aaa20d4d742d66310ab4b0d5" -dependencies = [ - "glib-sys 0.22.8", - "gobject-sys 0.22.6", - "libc", - "system-deps 7.0.8", - "windows-sys 0.61.2", -] - -[[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 = "glib" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" -dependencies = [ - "bitflags 2.13.0", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys 0.18.1", - "glib-macros 0.18.5", - "glib-sys 0.18.1", - "gobject-sys 0.18.0", - "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "glib" -version = "0.22.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddbcf514bd1881fc1b960e4e52b4e82873f4da3bceddbd58d42827b508888100" -dependencies = [ - "bitflags 2.13.0", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys 0.22.8", - "glib-macros 0.22.6", - "glib-sys 0.22.8", - "gobject-sys 0.22.6", - "libc", - "memchr", - "smallvec", -] - -[[package]] -name = "glib-macros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" -dependencies = [ - "heck 0.4.1", - "proc-macro-crate 2.0.2", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "glib-macros" -version = "0.22.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "506d23499707c7142898429757e8d9a3871d965239a2cb66dfa05052be6d6f19" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps 6.2.2", -] - -[[package]] -name = "glib-sys" -version = "0.22.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030967459f9f676851872c6304adea7825c6d462ec9b72554c733cf0c5952233" -dependencies = [ - "libc", - "system-deps 7.0.8", -] - -[[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.13.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 = "gobject-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" -dependencies = [ - "glib-sys 0.18.1", - "libc", - "system-deps 6.2.2", -] - -[[package]] -name = "gobject-sys" -version = "0.22.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a861859b887a79cf461359c192c97a57d8fb0229dd291232e57aa11f6fa72c" -dependencies = [ - "glib-sys 0.22.8", - "libc", - "system-deps 7.0.8", -] - -[[package]] -name = "gpu-alloc" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45cf04b2726f02df5508c6de726acdc90cdf97ac771a9a0ffd8ba10a6e696bf9" -dependencies = [ - "bitflags 2.13.0", - "gpu-alloc-types", -] - -[[package]] -name = "gpu-alloc-types" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bbed164dd10ed526c2e4fe3e721ca4a71c61730e5aafac6844b417b3227058" -dependencies = [ - "bitflags 2.13.0", -] - -[[package]] -name = "gpu-descriptor" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" -dependencies = [ - "bitflags 2.13.0", - "gpu-descriptor-types", - "hashbrown 0.15.5", -] - -[[package]] -name = "gpu-descriptor-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" -dependencies = [ - "bitflags 2.13.0", -] - -[[package]] -name = "graphene-rs" -version = "0.22.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb856b9c558971c3f13ab692358926da710b046932a4e087aedcc35b040d7dff" -dependencies = [ - "glib 0.22.8", - "graphene-sys", -] - -[[package]] -name = "graphene-sys" -version = "0.22.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ffdfde88f3570d3705e0d8a2433e036d387a1f2930bbf47eafcb5f569fd04" -dependencies = [ - "glib-sys 0.22.8", - "libc", - "system-deps 7.0.8", -] - -[[package]] -name = "gsk4" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b867be1c5f14dcb8f552c0eff6e9a9b1da5f8b43943e8efc3a63c889d84952ff" -dependencies = [ - "cairo-rs 0.22.0", - "gdk4", - "glib 0.22.8", - "graphene-rs", - "gsk4-sys", - "libc", - "pango 0.22.8", -] - -[[package]] -name = "gsk4-sys" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7c7eb2e681ee896646cfb8872b431f24d09f53ba9283289d9b10caa6707088" -dependencies = [ - "cairo-sys-rs 0.22.0", - "gdk4-sys", - "glib-sys 0.22.8", - "gobject-sys 0.22.6", - "graphene-sys", - "libc", - "pango-sys 0.22.0", - "system-deps 7.0.8", -] - -[[package]] -name = "gtk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" -dependencies = [ - "atk", - "cairo-rs 0.18.5", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf 0.18.5", - "gio 0.18.4", - "glib 0.18.5", - "gtk-sys", - "gtk3-macros", - "libc", - "pango 0.18.3", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" -dependencies = [ - "atk-sys", - "cairo-sys-rs 0.18.2", - "gdk-pixbuf-sys 0.18.0", - "gdk-sys", - "gio-sys 0.18.1", - "glib-sys 0.18.1", - "gobject-sys 0.18.0", - "libc", - "pango-sys 0.18.0", - "system-deps 6.2.2", -] - -[[package]] -name = "gtk3-macros" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "gtk4" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98a0a0466484f64b07b5b8184d43fa46be78eb0b8e04ae4e179af31d770b76d9" -dependencies = [ - "cairo-rs 0.22.0", - "field-offset", - "futures-channel", - "gdk-pixbuf 0.22.0", - "gdk4", - "gio 0.22.8", - "glib 0.22.8", - "graphene-rs", - "gsk4", - "gtk4-macros", - "gtk4-sys", - "libc", - "pango 0.22.8", -] - -[[package]] -name = "gtk4-macros" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac7179400a36a04de039c24206bb841c5596992b907b43b23ee8d5bdc40d00e" -dependencies = [ - "proc-macro-crate 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "gtk4-sys" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f954786af0b1984425c4446b77f5ff6594346181316be3f850caab1c6f01" -dependencies = [ - "cairo-sys-rs 0.22.0", - "gdk-pixbuf-sys 0.22.0", - "gdk4-sys", - "gio-sys 0.22.8", - "glib-sys 0.22.8", - "gobject-sys 0.22.6", - "graphene-sys", - "gsk4-sys", - "libc", - "pango-sys 0.22.0", - "system-deps 7.0.8", -] - -[[package]] -name = "half" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" -dependencies = [ - "cfg-if", - "crunchy", - "zerocopy", -] - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash", -] - -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hexf-parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" - -[[package]] -name = "icu_collections" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" - -[[package]] -name = "icu_properties" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" - -[[package]] -name = "icu_provider" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "image" -version = "0.25.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" -dependencies = [ - "bytemuck", - "byteorder-lite", - "moxcms", - "num-traits", - "png", - "tiff", -] - -[[package]] -name = "immutable-chunkmap" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3e98b1520e49e252237edc238a39869da9f3241f2ec19dc788c1d24694d1e4" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "indexmap" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" -dependencies = [ - "equivalent", - "hashbrown 0.17.1", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys 0.3.1", - "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 2.0.118", -] - -[[package]] -name = "jni-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" -dependencies = [ - "jni-sys 0.4.1", -] - -[[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 2.0.118", -] - -[[package]] -name = "jobserver" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" -dependencies = [ - "getrandom 0.4.3", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" -dependencies = [ - "cfg-if", - "futures-util", - "wasm-bindgen", -] - -[[package]] -name = "keyboard-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" -dependencies = [ - "bitflags 2.13.0", - "serde", - "unicode-segmentation", -] - -[[package]] -name = "khronos-egl" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" -dependencies = [ - "libc", - "libloading 0.8.9", - "pkg-config", -] - -[[package]] -name = "khronos_api" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" - -[[package]] -name = "ksni" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4934310bdd016e55725482b8d35ac0c16fd058c1b955d8959aa2d953b918c85b" -dependencies = [ - "dbus", - "dbus-codegen", - "dbus-tree", - "thiserror 1.0.69", -] - -[[package]] -name = "libappindicator" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" -dependencies = [ - "glib 0.18.5", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" -dependencies = [ - "gtk-sys", - "libloading 0.7.4", - "once_cell", -] - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "libdbus-sys" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" -dependencies = [ - "pkg-config", -] - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link 0.2.1", -] - -[[package]] -name = "libredox" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" -dependencies = [ - "bitflags 2.13.0", - "libc", - "plain", - "redox_syscall 0.9.0", -] - -[[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.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - -[[package]] -name = "litemap" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" - -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - -[[package]] -name = "memchr" -version = "2.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" - -[[package]] -name = "memmap2" -version = "0.9.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" -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 = "metal" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" -dependencies = [ - "bitflags 2.13.0", - "block", - "core-graphics-types 0.1.3", - "foreign-types", - "log", - "objc", - "paste", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "moxcms" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" -dependencies = [ - "num-traits", - "pxfm", -] - -[[package]] -name = "muda" -version = "0.19.3" -dependencies = [ - "arc-swap", - "crossbeam-channel", - "dpi", - "gtk4", - "keyboard-types", - "objc2 0.6.4", - "objc2-app-kit 0.3.2", - "objc2-core-foundation", - "objc2-foundation 0.3.2", - "once_cell", - "png", - "serde", - "thiserror 2.0.18", - "windows-sys 0.61.2", -] - -[[package]] -name = "naga" -version = "24.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" -dependencies = [ - "arrayvec", - "bit-set", - "bitflags 2.13.0", - "cfg_aliases", - "codespan-reporting", - "hexf-parse", - "indexmap", - "log", - "rustc-hash 1.1.0", - "spirv", - "strum", - "termcolor", - "thiserror 2.0.18", - "unicode-xid", -] - -[[package]] -name = "ndk" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" -dependencies = [ - "bitflags 2.13.0", - "jni-sys 0.3.1", - "log", - "ndk-sys 0.6.0+11769913", - "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.5.0+25.2.9519653" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" -dependencies = [ - "jni-sys 0.3.1", -] - -[[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.1", -] - -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags 2.13.0", - "cfg-if", - "cfg_aliases", - "libc", - "memoffset", -] - -[[package]] -name = "nohash-hasher" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_enum" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -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 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - -[[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.13.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.13.0", - "objc2 0.6.4", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 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.13.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-core-location 0.2.2", - "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.13.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.13.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 = [ - "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.13.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.13.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", -] - -[[package]] -name = "objc2-core-image" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" -dependencies = [ - "objc2 0.6.4", - "objc2-foundation 0.3.2", -] - -[[package]] -name = "objc2-core-location" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" -dependencies = [ - "block2 0.5.1", - "objc2 0.5.2", - "objc2-contacts", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-core-location" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" -dependencies = [ - "objc2 0.6.4", - "objc2-foundation 0.3.2", -] - -[[package]] -name = "objc2-core-text" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" -dependencies = [ - "bitflags 2.13.0", - "objc2 0.6.4", - "objc2-core-foundation", - "objc2-core-graphics", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "objc2-foundation" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -dependencies = [ - "bitflags 2.13.0", - "block2 0.5.1", - "dispatch", - "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-foundation" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" -dependencies = [ - "bitflags 2.13.0", - "block2 0.6.2", - "objc2 0.6.4", - "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.13.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.13.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.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.13.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" -dependencies = [ - "bitflags 2.13.0", - "objc2 0.6.4", - "objc2-core-foundation", - "objc2-foundation 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.13.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 0.2.2", - "objc2-foundation 0.2.2", - "objc2-link-presentation", - "objc2-quartz-core 0.2.2", - "objc2-symbols", - "objc2-uniform-type-identifiers", - "objc2-user-notifications 0.2.2", -] - -[[package]] -name = "objc2-ui-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" -dependencies = [ - "bitflags 2.13.0", - "block2 0.6.2", - "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-location 0.3.2", - "objc2-core-text", - "objc2-foundation 0.3.2", - "objc2-quartz-core 0.3.2", - "objc2-user-notifications 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.13.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-core-location 0.2.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-user-notifications" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" -dependencies = [ - "objc2 0.6.4", - "objc2-foundation 0.3.2", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "orbclient" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df339f526ea9a60e371768d50efc2f2508c7203290731565d1f7a6f71d21747" -dependencies = [ - "libc", - "libredox", -] - -[[package]] -name = "ordered-float" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" -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", -] - -[[package]] -name = "pango" -version = "0.18.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" -dependencies = [ - "gio 0.18.4", - "glib 0.18.5", - "libc", - "once_cell", - "pango-sys 0.18.0", -] - -[[package]] -name = "pango" -version = "0.22.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d800d8d0de2ad5d0fb046f5344dbaba14a003cf3dd27cc21d85893d35ea316c" -dependencies = [ - "gio 0.22.8", - "glib 0.22.8", - "pango-sys 0.22.0", -] - -[[package]] -name = "pango-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" -dependencies = [ - "glib-sys 0.18.1", - "gobject-sys 0.18.0", - "libc", - "system-deps 6.2.2", -] - -[[package]] -name = "pango-sys" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd111a20ca90fedf03e09c59783c679c00900f1d8491cca5399f5e33609d5d6" -dependencies = [ - "glib-sys 0.22.8", - "gobject-sys 0.22.6", - "libc", - "system-deps 7.0.8", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.18", - "smallvec", - "windows-link 0.2.1", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pin-project" -version = "1.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[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.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" - -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - -[[package]] -name = "png" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" -dependencies = [ - "bitflags 2.13.0", - "crc32fast", - "fdeflate", - "flate2", - "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 = "potential_utf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" -dependencies = [ - "zerovec", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" -dependencies = [ - "toml_datetime 0.6.3", - "toml_edit 0.20.2", -] - -[[package]] -name = "proc-macro-crate" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" -dependencies = [ - "toml_edit 0.25.12+spec-1.1.0", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "profiling" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" - -[[package]] -name = "pxfm" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" - -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - -[[package]] -name = "quick-xml" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "quick-xml" -version = "0.39.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" -dependencies = [ - "memchr", -] - -[[package]] -name = "quote" -version = "1.0.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - -[[package]] -name = "rand" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] - -[[package]] -name = "raw-window-handle" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags 2.13.0", -] - -[[package]] -name = "redox_syscall" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5102a6aaa05aa011a238e178e6bca86d2cb56fc9f586d37cb80f5bca6e07759" -dependencies = [ - "bitflags 2.13.0", -] - -[[package]] -name = "redox_users" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" -dependencies = [ - "getrandom 0.2.17", - "libredox", - "thiserror 2.0.18", -] - -[[package]] -name = "renderdoc-sys" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc-hash" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.13.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" -dependencies = [ - "bitflags 2.13.0", - "errno", - "libc", - "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustversion" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[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", -] - -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "serde_json" -version = "1.0.150" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[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 2.0.118", -] - -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_spanned" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" -dependencies = [ - "serde_core", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "shlex" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" - -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "simd-adler32" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" - -[[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 = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - -[[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.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" - -[[package]] -name = "smithay-client-toolkit" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" -dependencies = [ - "bitflags 2.13.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.13.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 = "spirv" -version = "0.3.0+sdk-1.3.268.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" -dependencies = [ - "bitflags 2.13.0", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strict-num" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" - -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.118", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.118" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr 0.15.8", - "heck 0.5.0", - "pkg-config", - "toml 0.8.2", - "version-compare", -] - -[[package]] -name = "system-deps" -version = "7.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7" -dependencies = [ - "cfg-expr 0.20.8", - "heck 0.5.0", - "pkg-config", - "toml 1.1.2+spec-1.1.0", - "version-compare", -] - -[[package]] -name = "tao" -version = "0.35.3" -dependencies = [ - "async-channel", - "bitflags 2.13.0", - "block2 0.6.2", - "core-foundation 0.10.1", - "core-graphics 0.25.0", - "crossbeam-channel", - "dbus", - "dispatch2", - "dlopen2", - "dpi", - "gdk4-wayland", - "gdk4-x11", - "gtk4", - "jni 0.21.1", - "libc", - "log", - "ndk", - "ndk-sys 0.6.0+11769913", - "objc2 0.6.4", - "objc2-app-kit 0.3.2", - "objc2-foundation 0.3.2", - "objc2-ui-kit 0.3.2", - "once_cell", - "parking_lot", - "percent-encoding", - "raw-window-handle", - "tao-macros", - "unicode-segmentation", - "url", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - -[[package]] -name = "tao-macros" -version = "0.1.3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - -[[package]] -name = "target-lexicon" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" - -[[package]] -name = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.4.3", - "once_cell", - "rustix 1.1.4", - "windows-sys 0.61.2", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl 2.0.18", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "tiff" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" -dependencies = [ - "fax", - "flate2", - "half", - "quick-error", - "weezl", - "zune-jpeg", -] - -[[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", - "tiny-skia-path", -] - -[[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]] -name = "tinystr" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "toml" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" -dependencies = [ - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.3", - "toml_edit 0.20.2", -] - -[[package]] -name = "toml" -version = "1.1.2+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" -dependencies = [ - "indexmap", - "serde_core", - "serde_spanned 1.1.1", - "toml_datetime 1.1.1+spec-1.1.0", - "toml_parser", - "toml_writer", - "winnow 1.0.3", -] - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_datetime" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "toml_datetime 0.6.3", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" -dependencies = [ - "indexmap", - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.3", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.25.12+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" -dependencies = [ - "indexmap", - "toml_datetime 1.1.1+spec-1.1.0", - "toml_parser", - "winnow 1.0.3", -] - -[[package]] -name = "toml_parser" -version = "1.1.2+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" -dependencies = [ - "winnow 1.0.3", -] - -[[package]] -name = "toml_writer" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tray-icon" -version = "0.24.1" -dependencies = [ - "arc-swap", - "crossbeam-channel", - "dirs", - "eframe", - "gtk4", - "image", - "ksni", - "libappindicator", - "muda", - "objc2 0.6.4", - "objc2-app-kit 0.3.2", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.2", - "once_cell", - "png", - "serde", - "serde_json", - "tao", - "thiserror 2.0.18", - "windows-sys 0.61.2", - "winit", -] - -[[package]] -name = "ttf-parser" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" - -[[package]] -name = "type-map" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" -dependencies = [ - "rustc-hash 2.1.3", -] - -[[package]] -name = "typenum" -version = "1.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" - -[[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 = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unicode-segmentation" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - -[[package]] -name = "version-compare" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.4+wasi-0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.118", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" -dependencies = [ - "unicode-ident", -] - -[[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.13.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.13.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.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" -dependencies = [ - "bitflags 2.13.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.13.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.13.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.13.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.13.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.4", - "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-sys" -version = "0.3.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webbrowser" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc95580916af1e68ff6a7be07446fc5db73ebf71cf092de939bbf5f7e189f72" -dependencies = [ - "core-foundation 0.10.1", - "jni 0.22.4", - "log", - "ndk-context", - "objc2 0.6.4", - "objc2-foundation 0.3.2", - "url", - "web-sys", -] - -[[package]] -name = "weezl" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" - -[[package]] -name = "wgpu" -version = "24.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0b3436f0729f6cdf2e6e9201f3d39dc95813fad61d826c1ed07918b4539353" -dependencies = [ - "arrayvec", - "bitflags 2.13.0", - "cfg_aliases", - "document-features", - "js-sys", - "log", - "parking_lot", - "profiling", - "raw-window-handle", - "smallvec", - "static_assertions", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "wgpu-core", - "wgpu-hal", - "wgpu-types", -] - -[[package]] -name = "wgpu-core" -version = "24.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f0aa306497a238d169b9dc70659105b4a096859a34894544ca81719242e1499" -dependencies = [ - "arrayvec", - "bit-vec", - "bitflags 2.13.0", - "cfg_aliases", - "document-features", - "indexmap", - "log", - "naga", - "once_cell", - "parking_lot", - "profiling", - "raw-window-handle", - "rustc-hash 1.1.0", - "smallvec", - "thiserror 2.0.18", - "wgpu-hal", - "wgpu-types", -] - -[[package]] -name = "wgpu-hal" -version = "24.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259" -dependencies = [ - "android_system_properties", - "arrayvec", - "ash", - "bitflags 2.13.0", - "bytemuck", - "cfg_aliases", - "core-graphics-types 0.1.3", - "glow", - "glutin_wgl_sys", - "gpu-alloc", - "gpu-descriptor", - "js-sys", - "khronos-egl", - "libc", - "libloading 0.8.9", - "log", - "metal", - "naga", - "ndk-sys 0.5.0+25.2.9519653", - "objc", - "once_cell", - "ordered-float", - "parking_lot", - "profiling", - "raw-window-handle", - "renderdoc-sys", - "rustc-hash 1.1.0", - "smallvec", - "thiserror 2.0.18", - "wasm-bindgen", - "web-sys", - "wgpu-types", - "windows 0.58.0", -] - -[[package]] -name = "wgpu-types" -version = "24.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c" -dependencies = [ - "bitflags 2.13.0", - "js-sys", - "log", - "web-sys", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[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", - "windows-core 0.61.2", - "windows-future", - "windows-link 0.1.3", - "windows-numerics", -] - -[[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]] -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]] -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", -] - -[[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 2.0.118", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[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 2.0.118", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -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-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-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link 0.2.1", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "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-version" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -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.13.0", - "block2 0.5.1", - "bytemuck", - "calloop 0.13.0", - "cfg_aliases", - "concurrent-queue", - "core-foundation 0.9.4", - "core-graphics 0.23.2", - "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", - "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.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" -dependencies = [ - "memchr", -] - -[[package]] -name = "wit-bindgen" -version = "0.57.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" - -[[package]] -name = "writeable" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" - -[[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 = "xcursor" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" - -[[package]] -name = "xdg-home" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "xkbcommon-dl" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" -dependencies = [ - "bitflags 2.13.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 = "yoke" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", - "synstructure", -] - -[[package]] -name = "zbus" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" -dependencies = [ - "async-broadcast", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-process", - "async-recursion", - "async-task", - "async-trait", - "blocking", - "enumflags2", - "event-listener", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "nix", - "ordered-stream", - "rand", - "serde", - "serde_repr", - "sha1", - "static_assertions", - "tracing", - "uds_windows", - "windows-sys 0.52.0", - "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus-lockstep" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca2c5dceb099bddaade154055c926bb8ae507a18756ba1d8963fd7b51d8ed1d" -dependencies = [ - "zbus_xml", - "zvariant", -] - -[[package]] -name = "zbus-lockstep-macros" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", - "zbus-lockstep", - "zbus_xml", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" -dependencies = [ - "proc-macro-crate 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.118", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" -dependencies = [ - "serde", - "static_assertions", - "zvariant", -] - -[[package]] -name = "zbus_xml" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3f374552b954f6abb4bd6ce979e6c9b38fb9d0cd7cc68a7d796e70c9f3a233" -dependencies = [ - "quick-xml 0.30.0", - "serde", - "static_assertions", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zerocopy" -version = "0.8.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "zerofrom" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", - "synstructure", -] - -[[package]] -name = "zerotrie" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - -[[package]] -name = "zune-core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" - -[[package]] -name = "zune-jpeg" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" -dependencies = [ - "zune-core", -] - -[[package]] -name = "zvariant" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" -dependencies = [ - "endi", - "enumflags2", - "serde", - "static_assertions", - "zvariant_derive", -] - -[[package]] -name = "zvariant_derive" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" -dependencies = [ - "proc-macro-crate 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.118", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] diff --git a/ports/tray-icon/README.md b/ports/tray-icon/README.md index 23f3959f77e5..c22037612ac6 100644 --- a/ports/tray-icon/README.md +++ b/ports/tray-icon/README.md @@ -4,34 +4,35 @@ tray-icon lets you create tray icons for desktop applications. - Windows - macOS -- Linux (gtk Only) -- FreeBSD (gtk Only) +- Linux (`linux-ksni` or legacy `gtk` backend) +- FreeBSD (legacy `gtk` backend) ## Platform-specific notes: -- On Windows and Linux or FreeBSD, an event loop must be running on the thread, on Windows, a win32 event loop and on Linux or FreeBSD, a gtk event loop. It doesn't need to be the main thread but you have to create the tray icon on the same thread as the event loop. +- On Windows and Linux or FreeBSD, an event loop must be running on the thread. On Windows, this is a win32 event loop. On Linux with the legacy `gtk` backend or on FreeBSD, this is a gtk event loop. It doesn't need to be the main thread but you have to create the tray icon on the same thread as the event loop. - On macOS, an event loop must be running on the main thread so you also need to create the tray icon on the main thread. ### Cargo Features - `common-controls-v6`: Use `TaskDialogIndirect` API from `ComCtl32.dll` v6 on Windows for showing the predefined `About` menu item dialog. +- `linux-ksni`: Uses StatusNotifierItem over D-Bus through `ksni` for Linux tray icons, avoiding `libappindicator`. - `libxdo`: Enables linking to `libxdo` which is used for the predefined `Copy`, `Cut`, `Paste` and `SelectAll` menu item, see https://github.com/tauri-apps/muda#cargo-features - `serde`: Enables de/serializing derives. ## Dependencies (Linux Only) -On Linux, `gtk`, `libxdo` is used to make the predefined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work and `libappindicator` or `libayatana-appindicator` are used to create the tray icon, so make sure to install them on your system. +On Linux, the `linux-ksni` feature uses StatusNotifierItem over D-Bus through `ksni` and does not depend on `libappindicator`. The legacy `gtk` feature keeps the appindicator backend available for compatibility. `libxdo` is used by predefined `Copy`, `Cut`, `Paste`, and `SelectAll` menu items. #### Arch Linux / Manjaro: ```sh -pacman -S gtk3 xdotool libappindicator-gtk3 #or libayatana-appindicator +pacman -S gtk4 xdotool dbus ``` #### Debian / Ubuntu: ```sh -sudo apt install libgtk-3-dev libxdo-dev libappindicator3-dev #or libayatana-appindicator3-dev +sudo apt install libgtk-4-dev libxdo-dev libdbus-1-dev ``` ## Dependencies in FreeBSD diff --git a/ports/tray-icon/src/lib.rs b/ports/tray-icon/src/lib.rs index dda9ec5b2338..9873a624d8d7 100644 --- a/ports/tray-icon/src/lib.rs +++ b/ports/tray-icon/src/lib.rs @@ -14,28 +14,31 @@ //! //! - Windows //! - macOS -//! - Linux (gtk Only) -//! - FreeBSD / DragonFly BSD / NetBSD / OpenBSD (gtk Only) +//! - Linux (`linux-ksni` or legacy `gtk` backend) +//! - FreeBSD / DragonFly BSD / NetBSD / OpenBSD (legacy `gtk` backend) //! //! # Platform-specific notes: //! -//! - On Windows, Linux, and BSD, an event loop must be running on the thread, on Windows, a win32 event loop and on Linux or BSD, a gtk event loop. It doesn't need to be the main thread but you have to create the tray icon on the same thread as the event loop. +//! - On Windows, Linux, and BSD, an event loop must be running on the thread. On Windows, this is a win32 event loop. On Linux with the legacy `gtk` backend or on BSD, this is a gtk event loop. It doesn't need to be the main thread but you have to create the tray icon on the same thread as the event loop. //! - On macOS, an event loop must be running on the main thread so you also need to create the tray icon on the main thread. You must make sure that the event loop is already running and not just created before creating a TrayIcon to prevent issues with fullscreen apps. In Winit for example the earliest you can create icons is on [`StartCause::Init`](https://docs.rs/winit/latest/winit/event/enum.StartCause.html#variant.Init). //! //! # Dependencies (Linux Only) //! -//! On Linux, `gtk`, `libxdo` is used to make the predefined `Copy`, `Cut`, `Paste` and `SelectAll` menu items work and `libappindicator` or `libayatana-appindicator` are used to create the tray icon, so make sure to install them on your system. +//! On Linux, the `linux-ksni` feature uses StatusNotifierItem over D-Bus through +//! `ksni` and does not depend on `libappindicator`. The legacy `gtk` feature +//! keeps the appindicator backend available for compatibility. `libxdo` is used +//! by predefined `Copy`, `Cut`, `Paste`, and `SelectAll` menu items. //! //! #### Arch Linux / Manjaro: //! //! ```sh -//! pacman -S gtk3 xdotool libappindicator-gtk3 #or libayatana-appindicator +//! pacman -S gtk4 xdotool dbus //! ``` //! //! #### Debian / Ubuntu: //! //! ```sh -//! sudo apt install libgtk-3-dev libxdo-dev libappindicator3-dev #or libayatana-appindicator3-dev +//! sudo apt install libgtk-4-dev libxdo-dev libdbus-1-dev //! ``` //! //! # Examples From 41644c41fcc11f084319266367406b3cf2025cc1 Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Wed, 8 Jul 2026 13:58:30 -0400 Subject: [PATCH 12/46] fix(ci): restore schema patch and silence Apple clippy --- Cargo.lock | 26 ++++++++------------ crates/tauri-runtime-wry/src/window/macos.rs | 10 ++++---- crates/tauri/src/app.rs | 10 +++----- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03c523ed7352..06efa7737dbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4053,7 +4053,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.15.5", "serde", "serde_core", ] @@ -7840,9 +7840,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.22" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" dependencies = [ "dyn-clone", "indexmap 1.9.3", @@ -7879,9 +7879,8 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +version = "0.8.21" +source = "git+https://github.com/tauri-apps/schemars.git?branch=feat%2Fpreserve-description-newlines#c30f98480e6e4742aa72202d55d5264c6b2e6476" dependencies = [ "proc-macro2", "quote", @@ -9191,7 +9190,7 @@ dependencies = [ "heck", "json-patch", "quote", - "schemars 0.8.22", + "schemars 0.8.21", "semver", "serde", "serde_json", @@ -9445,7 +9444,7 @@ dependencies = [ "anyhow", "glob", "plist", - "schemars 0.8.22", + "schemars 0.8.21", "serde", "serde_json", "tauri-utils", @@ -9537,7 +9536,7 @@ dependencies = [ name = "tauri-schema-generator" version = "0.0.0" dependencies = [ - "schemars 0.8.22", + "schemars 0.8.21", "serde", "serde_json", "tauri-utils", @@ -9584,7 +9583,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "schemars 0.8.22", + "schemars 0.8.21", "semver", "serde", "serde-untagged", @@ -9632,7 +9631,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.3", + "getrandom 0.3.4", "once_cell", "rustix", "windows-sys 0.61.2", @@ -11935,8 +11934,3 @@ checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" dependencies = [ "zune-core", ] - -[[patch.unused]] -name = "schemars_derive" -version = "0.8.21" -source = "git+https://github.com/tauri-apps/schemars.git?branch=feat%2Fpreserve-description-newlines#c30f98480e6e4742aa72202d55d5264c6b2e6476" diff --git a/crates/tauri-runtime-wry/src/window/macos.rs b/crates/tauri-runtime-wry/src/window/macos.rs index 6bb16ce3e5f1..4a1d9a360599 100644 --- a/crates/tauri-runtime-wry/src/window/macos.rs +++ b/crates/tauri-runtime-wry/src/window/macos.rs @@ -24,16 +24,16 @@ impl super::WindowExt for tao::window::Window { false, ) }; - unsafe { sheet.setAlphaValue(0.5) }; - unsafe { ns_window.beginSheet_completionHandler(&sheet, None) }; - } else if let Some(attached) = unsafe { ns_window.attachedSheet() } { - unsafe { ns_window.endSheet(&attached) }; + sheet.setAlphaValue(0.5); + ns_window.beginSheet_completionHandler(&sheet, None); + } else if let Some(attached) = ns_window.attachedSheet() { + ns_window.endSheet(&attached); } } fn is_enabled(&self) -> bool { let ns_window: &NSWindow = unsafe { &*self.ns_window().cast() }; - unsafe { ns_window.attachedSheet() }.is_none() + ns_window.attachedSheet().is_none() } fn center(&self) { diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index b18af93333db..9be8b95cbadc 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -679,7 +679,7 @@ impl AppHandle { #[cfg(target_os = "ios")] pub fn supports_multiple_windows(&self) -> bool { let (tx, rx) = std::sync::mpsc::channel(); - let _ = self.run_on_main_thread(move || unsafe { + let _ = self.run_on_main_thread(move || { let mtm = objc2::MainThreadMarker::new().unwrap(); let ui_application = objc2_ui_kit::UIApplication::sharedApplication(mtm); tx.send(ui_application.supportsMultipleScenes()).unwrap(); @@ -1263,11 +1263,9 @@ impl App { /// Whether the application supports multiple windows. #[cfg(target_os = "ios")] pub fn supports_multiple_windows(&self) -> bool { - unsafe { - let mtm = objc2::MainThreadMarker::new().unwrap(); - let ui_application = objc2_ui_kit::UIApplication::sharedApplication(mtm); - ui_application.supportsMultipleScenes() - } + let mtm = objc2::MainThreadMarker::new().unwrap(); + let ui_application = objc2_ui_kit::UIApplication::sharedApplication(mtm); + ui_application.supportsMultipleScenes() } /// Sets the activation policy for the application. It is set to `NSApplicationActivationPolicyRegular` by default. From f7472de557b0868b1f6ff2fe6973568f8750eda0 Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Wed, 8 Jul 2026 14:16:40 -0400 Subject: [PATCH 13/46] chore: document GTK4 supply-chain posture --- audits/GTK4_WebKit6_supply_chain_notes.md | 147 ++++++++++++++++++++++ supply-chain/config.toml | 27 ++++ 2 files changed, 174 insertions(+) create mode 100644 audits/GTK4_WebKit6_supply_chain_notes.md diff --git a/audits/GTK4_WebKit6_supply_chain_notes.md b/audits/GTK4_WebKit6_supply_chain_notes.md new file mode 100644 index 000000000000..4a36ec20cab5 --- /dev/null +++ b/audits/GTK4_WebKit6_supply_chain_notes.md @@ -0,0 +1,147 @@ +# GTK4 / WebKitGTK 6 Supply Chain Notes + +Date: 2026-07-08 + +This note separates the Linux GTK4/WebKitGTK 6 runtime dependency changes from +standalone example dependencies and scanner noise. It is intended as a +review-facing artifact, not as a claim that the entire repository is currently +`cargo-vet` clean. + +## Runtime Graph + +Checked with: + +```powershell +cargo metadata --format-version 1 --locked --all-features --filter-platform x86_64-unknown-linux-gnu +``` + +The Linux all-features graph contains the expected GTK4/WebKitGTK 6 crates: + +| Package | Version | Repository | Notes | +|---------|---------|------------|-------| +| `gtk4` / `gdk4` / `gdk4-wayland` / `gdk4-x11` | `0.11.4` | `https://github.com/gtk-rs/gtk4-rs` | Active gtk-rs bindings for GTK4/GDK4. | +| `webkit6` | `0.6.1` | `https://gitlab.gnome.org/World/Rust/webkit6-rs` | WebKitGTK 6 binding; required for the GTK4 migration. | +| `javascriptcore6` | `0.6.0` | `https://gitlab.gnome.org/World/Rust/webkit6-rs` | Transitive WebKitGTK 6 binding. | +| `soup3` | `0.9.0` | `https://gitlab.gnome.org/World/Rust/soup3-rs` | Transitive GNOME/libsoup binding. | +| `ksni` | `0.2.2` | `https://github.com/iovxw/ksni` | Real optional Linux StatusNotifier tray backend. | +| `arc-swap` | `1.9.2` | `https://github.com/vorner/arc-swap` | Used by Linux menu/tray support. | +| `async-channel` | `2.5.0` | `https://github.com/smol-rs/async-channel` | Transitive async utility. | + +`ksni` is intentionally pulled through `tauri -> tray-icon/linux-ksni`. +Removing it means deliberately dropping or replacing that StatusNotifier tray +path, not merely trimming dead dependency weight. + +`libadwaita` is not in the default root graph. It is an optional Tao feature: + +```powershell +cargo tree --features libadwaita --target x86_64-unknown-linux-gnu -i libadwaita +``` + +## Example-Only Graphics Deps + +The Socket table lists `wgpu`, `glow`, `pollster`, and `eframe`, but they are +not in the root Linux all-features graph. + +Checked with: + +```powershell +cargo tree --all-features --target x86_64-unknown-linux-gnu -i wgpu +cargo tree --all-features --target x86_64-unknown-linux-gnu -i eframe +``` + +Both commands report no package match from the root workspace. + +Their actual locations are standalone vendored-port examples: + +| Package | Location | Use | +|---------|----------|-----| +| `wgpu` | `ports/wry/Cargo.toml` dev-dependency | `ports/wry/examples/wgpu.rs` | +| `pollster` | `ports/wry/Cargo.toml` dev-dependency | `ports/wry/examples/wgpu.rs` | +| `glow` | `ports/wry/Cargo.toml` dev-dependency | `ports/wry/examples/gtk_opengl.rs` | +| `eframe` | `ports/tray-icon/Cargo.toml` dev-dependency | `ports/tray-icon/examples/egui.rs` | + +The root workspace explicitly excludes `ports/muda`, `ports/tao`, +`ports/tray-icon`, and `ports/wry`, while patching crates.io to those local +paths. These example deps should not be treated as shipped Tauri runtime deps. + +## Socket Warning Triage + +Socket's "obfuscated code" warnings hit foundational ecosystem crates: + +| Package | Root Graph Status | Triage | +|---------|-------------------|--------| +| `hyper-util` `0.1.20` | Present | Comes through networking/client/server tooling such as `reqwest`, `axum`, and `jsonrpsee`; Hyperium-maintained. | +| `tokio` `1.52.3` | Present | Core async runtime; Tokio-maintained. | +| `libc` `0.2.186` | Present | Rust-lang maintained low-level platform crate. | +| `zerocopy` `0.8.53` | Present | Google-maintained parsing/layout crate. | +| `openssl` `0.10.81` | Present only with all-features Linux resolution | Comes through `native-tls`, then `tauri-bundler` / `ureq`; absent from the default Linux tree. | + +These warnings should be handled as scanner false-positive triage, not as a +reason to revert the GTK4/WebKitGTK 6 migration. + +## cargo-vet Status + +`cargo-vet` store version is `0.9`. On Windows with Rust `1.95`, installing +`cargo-vet 0.9.1` without its old lockfile fails in `flock.rs` because the +Windows handle type resolves to a different `c_void`. + +Working bootstrap command: + +```powershell +cargo +1.92 install cargo-vet --version 0.9.1 --locked --root .\.tmp-cargo-vet-0.9.1 +$env:PATH = "$PWD\.tmp-cargo-vet-0.9.1\bin;$env:PATH" +cargo +1.92 vet --version +``` + +This branch now adds `audit-as-crates-io` policy entries for local patched +crates that match published crate versions: + +```text +muda, tao, tao-macros, tauri-bundler, tauri-cli, tauri-driver, +tauri-macos-sign, tray-icon, wry +``` + +After formatting a disposable copy of the `supply-chain` store and running: + +```powershell +cargo-vet.exe vet check --store-path --locked --output-format=json +``` + +the policy mismatch is gone, but the full graph still fails vetting with 985 +missing criteria. The GTK/WebKit-related missing criteria are: + +```text +arc-swap 1.9.2 +async-channel 2.5.0 +gdk4 0.11.4 +gdk4-sys 0.11.4 +gdk4-wayland 0.11.4 +gdk4-wayland-sys 0.11.0 +gdk4-x11 0.11.4 +gdk4-x11-sys 0.11.0 +gtk4 0.11.4 +gtk4-macros 0.11.4 +gtk4-sys 0.11.4 +javascriptcore6 0.6.0 +javascriptcore6-sys 0.6.0 +ksni 0.2.2 +soup3 0.9.0 +soup3-sys 0.9.0 +webkit6 0.6.1 +webkit6-sys 0.6.0 +``` + +Recommendation: do not mass-exempt the full 985-package graph in this GTK +migration patch. Split cargo-vet remediation into its own supply-chain PR or +audit packet. For this migration, document the GTK/WebKit-specific delta and +avoid conflating it with stale repo-wide vet coverage. + +## Recommendation + +Keep the GTK4/WebKitGTK 6 runtime dependencies and keep `ksni` if the +StatusNotifier tray path is in scope. + +If the goal is to reduce scanner noise, remove or quarantine the standalone +vendored-port examples that pull `wgpu`, `glow`, `pollster`, and `eframe`. +That is a maintenance decision for the vendored ports, not a runtime security +fix for Tauri's Linux GTK4/WebKitGTK 6 path. diff --git a/supply-chain/config.toml b/supply-chain/config.toml index ef23ca62e600..b3617d1a853f 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -28,12 +28,24 @@ audit-as-crates-io = true [policy.tauri-build] audit-as-crates-io = true +[policy.tauri-bundler] +audit-as-crates-io = true + [policy.tauri-codegen] audit-as-crates-io = true +[policy.tauri-cli] +audit-as-crates-io = true + +[policy.tauri-driver] +audit-as-crates-io = true + [policy.tauri-macros] audit-as-crates-io = true +[policy.tauri-macos-sign] +audit-as-crates-io = true + [policy.tauri-plugin] audit-as-crates-io = true @@ -46,6 +58,21 @@ audit-as-crates-io = true [policy.tauri-utils] audit-as-crates-io = true +[policy.muda] +audit-as-crates-io = true + +[policy.tao] +audit-as-crates-io = true + +[policy.tao-macros] +audit-as-crates-io = true + +[policy.tray-icon] +audit-as-crates-io = true + +[policy.wry] +audit-as-crates-io = true + [[exemptions.addr2line]] version = "0.21.0" criteria = "safe-to-deploy" From 0e8413c0f7218a8d90a668d2a2097f41deadee28 Mon Sep 17 00:00:00 2001 From: Anthony Smith Date: Wed, 8 Jul 2026 14:38:37 -0400 Subject: [PATCH 14/46] fix: address review feedback --- .github/workflows/lint-rust.yml | 2 ++ crates/tauri/src/app.rs | 15 ++++++++++----- crates/tauri/src/webview/webview_window.rs | 2 +- ports/tray-icon/README.md | 4 ++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/lint-rust.yml b/.github/workflows/lint-rust.yml index 0ccbf0519c91..25fff9195fef 100644 --- a/.github/workflows/lint-rust.yml +++ b/.github/workflows/lint-rust.yml @@ -57,6 +57,8 @@ jobs: steps: - uses: actions/checkout@v7 + with: + persist-credentials: false - name: install rust stable and clippy uses: dtolnay/rust-toolchain@stable diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index 9be8b95cbadc..44aa7cc0230b 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -679,11 +679,16 @@ impl AppHandle { #[cfg(target_os = "ios")] pub fn supports_multiple_windows(&self) -> bool { let (tx, rx) = std::sync::mpsc::channel(); - let _ = self.run_on_main_thread(move || { - let mtm = objc2::MainThreadMarker::new().unwrap(); - let ui_application = objc2_ui_kit::UIApplication::sharedApplication(mtm); - tx.send(ui_application.supportsMultipleScenes()).unwrap(); - }); + if self + .run_on_main_thread(move || { + let mtm = objc2::MainThreadMarker::new().unwrap(); + let ui_application = objc2_ui_kit::UIApplication::sharedApplication(mtm); + tx.send(ui_application.supportsMultipleScenes()).unwrap(); + }) + .is_err() + { + return false; + } rx.recv().unwrap() } } diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs index 3d2f763bd419..63f0048462e3 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -1284,7 +1284,7 @@ impl> WebviewWindowBuilder<'_, R, M> { /// let mut builder = tauri::WebviewWindowBuilder::new(app, "label", tauri::WebviewUrl::App("index.html".into())); /// #[cfg(target_os = "ios")] /// { - /// window_builder = window_builder.with_input_accessory_view_builder(|_webview| unsafe { + /// builder = builder.with_input_accessory_view_builder(|_webview| unsafe { /// let mtm = objc2::MainThreadMarker::new_unchecked(); /// let button = objc2_ui_kit::UIButton::buttonWithType(objc2_ui_kit::UIButtonType(1), mtm); /// button.setTitle_forState( diff --git a/ports/tray-icon/README.md b/ports/tray-icon/README.md index c22037612ac6..e1ea0e06e446 100644 --- a/ports/tray-icon/README.md +++ b/ports/tray-icon/README.md @@ -23,13 +23,13 @@ tray-icon lets you create tray icons for desktop applications. On Linux, the `linux-ksni` feature uses StatusNotifierItem over D-Bus through `ksni` and does not depend on `libappindicator`. The legacy `gtk` feature keeps the appindicator backend available for compatibility. `libxdo` is used by predefined `Copy`, `Cut`, `Paste`, and `SelectAll` menu items. -#### Arch Linux / Manjaro: +### Arch Linux / Manjaro: ```sh pacman -S gtk4 xdotool dbus ``` -#### Debian / Ubuntu: +### Debian / Ubuntu: ```sh sudo apt install libgtk-4-dev libxdo-dev libdbus-1-dev From d8ee6207d09bd61a1d0733b47c710cf7531aee4f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 11 Jul 2026 11:56:42 +0800 Subject: [PATCH 15/46] chore(deps): update rust crate jsonschema to 0.47 (#15699) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 42 ++++++++++++++++++++++++++----------- crates/tauri-cli/Cargo.toml | 2 +- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f2823918ae4..61ea2016ce6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2532,9 +2532,9 @@ dependencies = [ [[package]] name = "fancy-regex" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8" +checksum = "e1e1dacd0d2082dfcf1351c4bdd566bbe89a2b263235a2b50058f1e130a47277" dependencies = [ "bit-set", "regex-automata", @@ -3361,6 +3361,15 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ "allocator-api2", "equivalent", @@ -4197,9 +4206,9 @@ dependencies = [ [[package]] name = "jsonschema" -version = "0.46.2" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50180452e7808015fe083eae3efcf1ec98b89b45dd8cc204f7b4a6b7b81ea675" +checksum = "281c43ff06dcb331e9356d30e38853d559ce3d0a3f693e0b0e102667dec14fb1" dependencies = [ "ahash 0.8.11", "bytecount", @@ -4210,18 +4219,27 @@ dependencies = [ "getrandom 0.3.4", "idna", "itoa", + "jsonschema-regex", "num-cmp", "num-traits", "percent-encoding", "referencing", "regex", - "regex-syntax", "serde", "serde_json", "unicode-general-category", "uuid-simd", ] +[[package]] +name = "jsonschema-regex" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee0b351864e7ffbc5db9273daf7fa1b4d5177b0946713d667ca571b83c0b4045" +dependencies = [ + "regex-syntax", +] + [[package]] name = "k256" version = "0.13.4" @@ -7033,14 +7051,14 @@ dependencies = [ [[package]] name = "referencing" -version = "0.46.9" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77954d81b2e1c5e8ab889f9f597a92f852ab073255de9e37ee3fb443efd57051" +checksum = "348e860aeb0b7bd035778fd11dd9cd5290d32e4aed3b8f2274a00287a9fd362b" dependencies = [ "ahash 0.8.11", "fluent-uri", "getrandom 0.3.4", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "itoa", "micromap", "parking_lot", @@ -7062,9 +7080,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db" dependencies = [ "aho-corasick", "memchr", @@ -7073,9 +7091,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rend" diff --git a/crates/tauri-cli/Cargo.toml b/crates/tauri-cli/Cargo.toml index 2d6085777f32..d1caa9581bf0 100644 --- a/crates/tauri-cli/Cargo.toml +++ b/crates/tauri-cli/Cargo.toml @@ -67,7 +67,7 @@ tauri-utils = { version = "2.9.3", path = "../tauri-utils", features = [ "html-manipulation-2", ] } toml = "1" -jsonschema = { version = "0.46", default-features = false } +jsonschema = { version = "0.47", default-features = false } handlebars = "6" include_dir = "0.7" dirs = "6" From aebf38c845b57bc5653eca677e2e2e044528ea73 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Sat, 11 Jul 2026 08:56:21 +0200 Subject: [PATCH 16/46] android: Migrate Gradle scripts to `compilerOptions` DSL (#15694) Kotlin Gradle Plugin deprecated the string-based `kotlinOptions` DSL and 2.3+ rejects it with a hard error. Use the `compilerOptions` DSL with `JvmTarget.JVM_1_8` instead, which is accepted on both 1.9.x and 2.x, so projects can move to Kotlin 2.x without editing the vendored `:tauri-android` scripts. --- .changes/android-compileroptions-dsl.md | 7 +++++++ .../templates/mobile/android/app/build.gradle.kts | 10 +++++++--- .../templates/plugin/android/build.gradle.kts | 9 +++++++-- crates/tauri/mobile/android/build.gradle.kts | 11 ++++++++--- .../tauri-plugin-sample/android/build.gradle.kts | 9 +++++++-- 5 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 .changes/android-compileroptions-dsl.md diff --git a/.changes/android-compileroptions-dsl.md b/.changes/android-compileroptions-dsl.md new file mode 100644 index 000000000000..8cffdfa87785 --- /dev/null +++ b/.changes/android-compileroptions-dsl.md @@ -0,0 +1,7 @@ +--- +"tauri": patch:enhance +"tauri-cli": patch:enhance +"@tauri-apps/cli": patch:enhance +--- + +Migrate the Android Gradle scripts from the deprecated `kotlinOptions` DSL to `compilerOptions`, which is accepted by both Kotlin Gradle Plugin 1.9.x and 2.x. This lets projects move to Kotlin 2.x without hitting the hard error that 2.3+ raises on the old DSL. diff --git a/crates/tauri-cli/templates/mobile/android/app/build.gradle.kts b/crates/tauri-cli/templates/mobile/android/app/build.gradle.kts index 0f73195fa008..129eacf61b3d 100644 --- a/crates/tauri-cli/templates/mobile/android/app/build.gradle.kts +++ b/crates/tauri-cli/templates/mobile/android/app/build.gradle.kts @@ -1,3 +1,4 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget import java.util.Properties plugins { @@ -50,14 +51,17 @@ android { ) } } - kotlinOptions { - jvmTarget = "1.8" - } buildFeatures { buildConfig = true } } +kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_1_8 + } +} + rust { rootDirRel = "{{root-dir-rel}}" } diff --git a/crates/tauri-cli/templates/plugin/android/build.gradle.kts b/crates/tauri-cli/templates/plugin/android/build.gradle.kts index f788a85fb6c7..b999d6b65e3d 100644 --- a/crates/tauri-cli/templates/plugin/android/build.gradle.kts +++ b/crates/tauri-cli/templates/plugin/android/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { id("com.android.library") id("org.jetbrains.kotlin.android") @@ -27,8 +29,11 @@ android { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } - kotlinOptions { - jvmTarget = "1.8" +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_1_8 } } diff --git a/crates/tauri/mobile/android/build.gradle.kts b/crates/tauri/mobile/android/build.gradle.kts index f997910c9b33..e633a072f429 100644 --- a/crates/tauri/mobile/android/build.gradle.kts +++ b/crates/tauri/mobile/android/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { id("com.android.library") id("org.jetbrains.kotlin.android") @@ -27,14 +29,17 @@ android { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } - kotlinOptions { - jvmTarget = "1.8" - } buildFeatures { buildConfig = true } } +kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_1_8 + } +} + dependencies { implementation("androidx.core:core-ktx:1.7.0") diff --git a/examples/api/src-tauri/tauri-plugin-sample/android/build.gradle.kts b/examples/api/src-tauri/tauri-plugin-sample/android/build.gradle.kts index 94f504ede46a..1d34a2e4b3ad 100644 --- a/examples/api/src-tauri/tauri-plugin-sample/android/build.gradle.kts +++ b/examples/api/src-tauri/tauri-plugin-sample/android/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { id("com.android.library") id("org.jetbrains.kotlin.android") @@ -27,8 +29,11 @@ android { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } - kotlinOptions { - jvmTarget = "1.8" +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_1_8 } } From f5347cd70838c027040acb4a66733a2470f20ae4 Mon Sep 17 00:00:00 2001 From: Tony <68118705+Legend-Master@users.noreply.github.com> Date: Mon, 13 Jul 2026 16:17:13 +0800 Subject: [PATCH 17/46] chore(deps): bump plist for quick-xml audit (#15709) --- .cargo/audit.toml | 4 ---- Cargo.lock | 12 ++++++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.cargo/audit.toml b/.cargo/audit.toml index 2ba828d61ecf..b8a4b1e1e507 100644 --- a/.cargo/audit.toml +++ b/.cargo/audit.toml @@ -11,8 +11,4 @@ ignore = [ "RUSTSEC-2026-0097", # glib 0.18.5 unsoundness, fixed by updating to gtk4 "RUSTSEC-2024-0429", - # quick-xml, need an update in plist - "RUSTSEC-2026-0194", - # quick-xml, need an update in plist - "RUSTSEC-2026-0195", ] diff --git a/Cargo.lock b/Cargo.lock index 61ea2016ce6a..acf6ae7dd78f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3841,7 +3841,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.15.5", "serde", "serde_core", ] @@ -6006,7 +6006,7 @@ dependencies = [ "aes-gcm", "aes-kw", "argon2", - "base64 0.22.1", + "base64 0.21.7", "bitfield", "block-padding", "blowfish", @@ -6352,9 +6352,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "plist" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" +checksum = "7da1d65da6dd5d1e44199ac0f58712d241c0f439f80adea8924d832384087f85" dependencies = [ "base64 0.22.1", "indexmap 2.11.4", @@ -6627,9 +6627,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.32.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", ] From 5ab317504aa2a77cbdaf46341456ff26f13861f6 Mon Sep 17 00:00:00 2001 From: Tony <68118705+Legend-Master@users.noreply.github.com> Date: Mon, 13 Jul 2026 19:24:32 +0800 Subject: [PATCH 18/46] refactor: migrate to svelte ts for API example (#15675) * Migrate to svelte ts for API example * Clean up * Use `$derived` `selectedWebview` * Do the change in onchange instead of state effects * Set initial x y and sizes * revert ai slop on main.ts * More cleanup * Remove ConsoleMessage * Remove View type * license header * Use `ViewProps` * Use same button spacing through out * Move theme example to top level theme switch * Fix menu views * More cleanups * Final cleanup * Move types to svelte files * fallback to empty string not false --- examples/api/index.html | 2 +- examples/api/jsconfig.json | 32 -- examples/api/src/App.svelte | 129 ++--- .../api/src/components/MenuBuilder.svelte | 78 ++- .../api/src/components/MenuItemBuilder.svelte | 79 +-- examples/api/src/{main.js => main.ts} | 2 +- examples/api/src/views/App.svelte | 31 +- examples/api/src/views/Communication.svelte | 18 +- examples/api/src/views/Menu.svelte | 73 +-- examples/api/src/views/Tray.svelte | 20 +- examples/api/src/views/WebRTC.svelte | 50 +- examples/api/src/views/Welcome.svelte | 5 +- examples/api/src/views/Window.svelte | 457 +++++++++++------- examples/api/tsconfig.json | 15 + 14 files changed, 583 insertions(+), 408 deletions(-) delete mode 100644 examples/api/jsconfig.json rename examples/api/src/{main.js => main.ts} (87%) create mode 100644 examples/api/tsconfig.json diff --git a/examples/api/index.html b/examples/api/index.html index 010944d8e277..5490c5c8e345 100644 --- a/examples/api/index.html +++ b/examples/api/index.html @@ -8,6 +8,6 @@

- + diff --git a/examples/api/jsconfig.json b/examples/api/jsconfig.json deleted file mode 100644 index 5696a2de74a0..000000000000 --- a/examples/api/jsconfig.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "compilerOptions": { - "moduleResolution": "bundler", - "target": "ESNext", - "module": "ESNext", - /** - * svelte-preprocess cannot figure out whether you have - * a value or a type, so tell TypeScript to enforce using - * `import type` instead of `import` for Types. - */ - "verbatimModuleSyntax": true, - "isolatedModules": true, - "resolveJsonModule": true, - /** - * To have warnings / errors of the Svelte compiler at the - * correct position, enable source maps by default. - */ - "sourceMap": true, - "esModuleInterop": true, - "skipLibCheck": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable this if you'd like to use dynamic types. - */ - "checkJs": true - }, - /** - * Use global.d.ts instead of compilerOptions.types - * to avoid limiting type declarations. - */ - "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"] -} diff --git a/examples/api/src/App.svelte b/examples/api/src/App.svelte index 7d14871a7944..980ca0e954fc 100644 --- a/examples/api/src/App.svelte +++ b/examples/api/src/App.svelte @@ -1,4 +1,10 @@ - + +
diff --git a/examples/api/src/components/MenuBuilder.svelte b/examples/api/src/components/MenuBuilder.svelte index 7e824bb1d712..006afecf5201 100644 --- a/examples/api/src/components/MenuBuilder.svelte +++ b/examples/api/src/components/MenuBuilder.svelte @@ -1,38 +1,84 @@ - + +
- +
{#each items as item} diff --git a/examples/api/src/components/MenuItemBuilder.svelte b/examples/api/src/components/MenuItemBuilder.svelte index 0f93436978a4..47b34b9733b7 100644 --- a/examples/api/src/components/MenuItemBuilder.svelte +++ b/examples/api/src/components/MenuItemBuilder.svelte @@ -1,22 +1,39 @@ - -
+
- Toggle dock visibility -
diff --git a/examples/api/src/views/Communication.svelte b/examples/api/src/views/Communication.svelte index 5c62d0936b5e..33aaf4a979da 100644 --- a/examples/api/src/views/Communication.svelte +++ b/examples/api/src/views/Communication.svelte @@ -1,20 +1,20 @@ - -
+
- - + +
diff --git a/examples/api/src/views/Menu.svelte b/examples/api/src/views/Menu.svelte index 0c4b719fd7ce..6613d3ab3210 100644 --- a/examples/api/src/views/Menu.svelte +++ b/examples/api/src/views/Menu.svelte @@ -1,41 +1,48 @@ -
-
+
+ + - -
diff --git a/examples/api/src/views/Tray.svelte b/examples/api/src/views/Tray.svelte index 9636f00c6806..bb30255c2428 100644 --- a/examples/api/src/views/Tray.svelte +++ b/examples/api/src/views/Tray.svelte @@ -1,18 +1,22 @@ -
Not available for Linux
-
diff --git a/examples/api/src/views/Welcome.svelte b/examples/api/src/views/Welcome.svelte index 72b1f2d49fae..cbe9d31fc7bc 100644 --- a/examples/api/src/views/Welcome.svelte +++ b/examples/api/src/views/Welcome.svelte @@ -1,4 +1,4 @@ - -
- + onMount(() => { + const sourceSortable1 = makeSourceSortable(sourceSortableEl1) + const sourceSortable2 = makeSourceSortable(sourceSortableEl2) + const targetSortable = new Sortable(targetSortableEl, { + dataIdAttr: 'data-id', + group: { + name: 'shared' + }, + async onAdd(event) { + const item = event.item + const kind = item.dataset.kind as MenuItemComponentKind + const text = item.dataset.text + const iconPath = item.dataset.iconPath + const checked = item.dataset.checked + + const newItem = { + id: currentId, + kind, + text, + iconPath, + checked: checked !== undefined ? checked === 'true' : checked + } as Item + currentId += 1 + + // HACK: We can't track the element created by Sortable, + // just make a new one and delete the one from Sortable + item.remove() + + if (event.newIndex !== undefined) { + items.splice(event.newIndex, 0, newItem) + } else { + items.push(newItem) + } + + newItem.menu = await create(newItem) -
- {#each items as item} -
-
-

{itemToString(item)}

+ await onItemAdded?.(newItem) + }, + onUpdate(event) { + const [item] = items.splice(event.oldIndex!, 1) + // Sortable's DOM manipulation doesn't work with Svelte, + // so we recreate all the nodes on order changes... + // This must be `toSpliced` to trigger the `#key` block re-render + items = items.toSpliced(event.newIndex!, 0, item!) + + onItemMoved?.(item, event.newIndex!) + }, + delayOnTouchOnly: true, + delay: 500, + animation: 200 + }) + return () => { + targetSortable.destroy() + sourceSortable1.destroy() + sourceSortable2.destroy() + } + }) + + onDestroy(() => { + for (const item of items) { + item.menu?.close() + } + items = [] + }) + + +
+
+
+

Custom

+
+ + +
- {/each} +
+
+

Predefined

+
+ {#each predefinedOptions as predefinedOption} + + {/each} +
+
+
+
+
+ {#key items} + {#each items as item, i (item.id)} + { + item.menu?.setText(item.text ?? '') + } + : undefined} + onIconPathChange={item.iconPath !== undefined + ? () => { + ;(item.menu as IconMenuItem | undefined)?.setIcon( + item.iconPath! + ) + } + : undefined} + onCheckedChange={item.checked !== undefined + ? () => { + ;(item.menu as CheckMenuItem | undefined)?.setChecked( + item.checked! + ) + } + : undefined} + onRemove={async () => { + items.splice(i, 1) + await onItemRemoved?.(item).finally(() => { + item.menu?.close() + }) + }} + /> + {:else} +
+ Drag and drop the menu items above to start building +
+ {/each} + {/key}
diff --git a/examples/api/src/components/MenuItemBuilder.svelte b/examples/api/src/components/MenuItemBuilder.svelte deleted file mode 100644 index 47b34b9733b7..000000000000 --- a/examples/api/src/components/MenuItemBuilder.svelte +++ /dev/null @@ -1,163 +0,0 @@ - - -
-
- {#each itemKinds as itemKind, i} -
- (kind = itemKind)} - type="radio" - name="kind" - value={itemKinds[i]} - /> - -
- {/each} -
- -
- -
- {#if kind == 'Normal' || kind == 'Icon' || kind == 'Check'} - - {/if} - {#if kind == 'Icon'} - - {:else if kind == 'Check'} -
- - -
- {:else if kind == 'Predefined'} -
- {#each predefinedOptions as predefinedOption, i} -
- (predefinedItem = predefinedOption)} - type="radio" - name="predefinedKind" - value={predefinedOptions[i]} - /> - -
- {/each} -
- {/if} -
- -
- -
- -
-
diff --git a/examples/api/src/components/MenuItemComponent.svelte b/examples/api/src/components/MenuItemComponent.svelte new file mode 100644 index 000000000000..5b828714a9fb --- /dev/null +++ b/examples/api/src/components/MenuItemComponent.svelte @@ -0,0 +1,79 @@ + + + + + diff --git a/examples/api/src/views/Menu.svelte b/examples/api/src/views/Menu.svelte index 6613d3ab3210..aa9cef7ed69d 100644 --- a/examples/api/src/views/Menu.svelte +++ b/examples/api/src/views/Menu.svelte @@ -1,49 +1,60 @@ -
- +
+ { + if (item.menu) { + await submenu?.append(item.menu) + } + }} + onItemRemoved={async (item) => { + if (item.menu) { + await submenu?.remove(item.menu) + } + }} + onItemMoved={(item, toIndex) => { + if (submenu) { + reorderMenuItems(submenu, item, toIndex) + } + }} + />
+
+ {#if tray} + + {:else} + + {/if} +
diff --git a/examples/api/src/views/Window.svelte b/examples/api/src/views/Window.svelte index 96f02642ac07..481c927969c2 100644 --- a/examples/api/src/views/Window.svelte +++ b/examples/api/src/views/Window.svelte @@ -400,7 +400,7 @@ }) -
+
@@ -513,7 +513,7 @@ Set focusable to {!focusable}
-
+
-
-
+
+
-
+
-
+
-
+