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/.changes/android-compileroptions-dsl.md b/.changes/android-compileroptions-dsl.md new file mode 100644 index 000000000000..3e3fcbd36e82 --- /dev/null +++ b/.changes/android-compileroptions-dsl.md @@ -0,0 +1,9 @@ +--- +"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. + +This increased the minimum supported Gradle version to 8.13. If your Gradle version is earlier, delete `src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties` and re-run `tauri android init` to update it. diff --git a/.changes/android-material3.md b/.changes/android-material3.md new file mode 100644 index 000000000000..1f013f7d3a21 --- /dev/null +++ b/.changes/android-material3.md @@ -0,0 +1,6 @@ +--- +"tauri-cli": patch:enhance +"@tauri-apps/cli": patch:enhance +--- + +Use `Theme.Material3.DayNight.NoActionBar` instead of `Theme.MaterialComponents.DayNight.NoActionBar` when running `tauri android init` diff --git a/.changes/app-bound-domains.md b/.changes/app-bound-domains.md new file mode 100644 index 000000000000..ea5a24f56939 --- /dev/null +++ b/.changes/app-bound-domains.md @@ -0,0 +1,8 @@ +--- +"tauri": minor:feat +"tauri-runtime": minor:feat +"tauri-runtime-wry": minor:feat +"tauri-utils": minor:feat +--- + +Add `WebviewBuilder::limit_navigations_to_app_bound_domains`, `WebviewWindowBuilder::limit_navigations_to_app_bound_domains`, and limitNavigationsToAppBoundDomains to tauri.config.json. diff --git a/.changes/bundler-show-sizes.md b/.changes/bundler-show-sizes.md new file mode 100644 index 000000000000..6525c8067d75 --- /dev/null +++ b/.changes/bundler-show-sizes.md @@ -0,0 +1,7 @@ +--- +"tauri-bundler": "minor:feat" +"tauri-cli": "minor:feat" +"@tauri-apps/cli": "minor:feat" +--- + +The bundler now prints the size of each generated bundle next to its path in the `Finished N bundles at:` output (directories such as macOS `.app` bundles are measured recursively). diff --git a/.changes/cleanup-js-menu-channel.md b/.changes/cleanup-js-menu-channel.md new file mode 100644 index 000000000000..980ea277c36c --- /dev/null +++ b/.changes/cleanup-js-menu-channel.md @@ -0,0 +1,5 @@ +--- +"tauri": "patch:bug" +--- + +Remove the `Channel` used to send events to the JavaScript side when the menu is dropped. diff --git a/.changes/fix-wix-resource-target-name.md b/.changes/fix-wix-resource-target-name.md new file mode 100644 index 000000000000..c773020d7bfd --- /dev/null +++ b/.changes/fix-wix-resource-target-name.md @@ -0,0 +1,8 @@ +--- +"tauri-bundler": patch:bug +"tauri-cli": patch:bug +"@tauri-apps/cli": patch:bug +--- + + +Fix the WiX bundler so it respects the resource's target file name. diff --git a/.changes/resolved-command-reference-debug-assertion.md b/.changes/resolved-command-reference-debug-assertion.md new file mode 100644 index 000000000000..a91a2b66cb2c --- /dev/null +++ b/.changes/resolved-command-reference-debug-assertion.md @@ -0,0 +1,8 @@ +--- +tauri: minor:enhance +tauri-macros: minor:enhance +tauri-utils: minor:enhance +tauri-build: minor:enhance +--- + +Fix compilation errors when `tauri-utils` is built with different debug-assertion settings for the build and runtime profiles. diff --git a/.changes/tauri-info-skip-rust-only-js.md b/.changes/tauri-info-skip-rust-only-js.md new file mode 100644 index 000000000000..ab905fe4012b --- /dev/null +++ b/.changes/tauri-info-skip-rust-only-js.md @@ -0,0 +1,6 @@ +--- +"tauri-cli": "patch:bug" +"@tauri-apps/cli": "patch:bug" +--- + +Prevent `tauri info` from reporting Rust-only plugins as having a missing npm package. diff --git a/.changes/wry-callback-sync.md b/.changes/wry-callback-sync.md new file mode 100644 index 000000000000..c6d581d47edc --- /dev/null +++ b/.changes/wry-callback-sync.md @@ -0,0 +1,6 @@ +--- +"tauri": minor:breaking +"tauri-runtime": minor:breaking +--- + +Require webview navigation, IPC, page-load, and document-title callbacks to be `Sync` in addition to `Send`, matching the thread-safety contract of the vendored Wry runtime. diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 9be465957136..fbb9bfb7c528 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -48,7 +48,7 @@ jobs: - uses: actions/checkout@v7 with: persist-credentials: false - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version: 'lts/*' - run: corepack enable diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 62fc97221fb9..10e990109a61 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -50,12 +50,13 @@ 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 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 \ - webkit2gtk-4.1 libayatana-appindicator3-dev \ + libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev \ xvfb \ at-spi2-core @@ -86,11 +87,13 @@ 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 if: github.repository == 'tauri-apps/tauri' && github.ref == 'refs/heads/dev' - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: token: ${{ secrets.ORG_TAURI_BOT_PAT }} path: gh-pages diff --git a/.github/workflows/check-change-tags.yml b/.github/workflows/check-change-tags.yml index d10c5a09912b..f13e29e8beef 100644 --- a/.github/workflows/check-change-tags.yml +++ b/.github/workflows/check-change-tags.yml @@ -17,7 +17,9 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - name: check change files end with .md run: | diff --git a/.github/workflows/check-generated-files.yml b/.github/workflows/check-generated-files.yml index fb1e59866d2f..d6fb0226f2e5 100644 --- a/.github/workflows/check-generated-files.yml +++ b/.github/workflows/check-generated-files.yml @@ -26,7 +26,9 @@ jobs: api: ${{ steps.filter.outputs.api }} schema: ${{ steps.filter.outputs.schema }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - uses: dorny/paths-filter@v3 id: filter with: @@ -45,9 +47,13 @@ jobs: needs: changes if: needs.changes.outputs.api == 'true' steps: - - uses: actions/checkout@v4 - - run: npm i -g --force corepack - - uses: actions/setup-node@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false + - run: | + npm i -g --force corepack@0.34.0 + corepack enable pnpm + - uses: actions/setup-node@v7 with: node-version: 'lts/*' cache: 'pnpm' @@ -65,15 +71,18 @@ jobs: needs: changes if: needs.changes.outputs.schema == 'true' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - name: install stable uses: dtolnay/rust-toolchain@stable - 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-3-dev + sudo apt-get install -y libgtk-4-dev - uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/check-license-header.yml b/.github/workflows/check-license-header.yml index 9b850deccb17..f035328208d6 100644 --- a/.github/workflows/check-license-header.yml +++ b/.github/workflows/check-license-header.yml @@ -15,7 +15,9 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - uses: dorny/paths-filter@v3 id: filter with: diff --git a/.github/workflows/covector-status.yml b/.github/workflows/covector-status.yml index 9b13dc2215d8..d98311a526eb 100644 --- a/.github/workflows/covector-status.yml +++ b/.github/workflows/covector-status.yml @@ -10,9 +10,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 + persist-credentials: false - name: covector status uses: jbolda/covector/packages/action@covector-v0 id: covector diff --git a/.github/workflows/covector-version-or-publish.yml b/.github/workflows/covector-version-or-publish.yml index 170bc3ef31b0..3c76c8ef0661 100644 --- a/.github/workflows/covector-version-or-publish.yml +++ b/.github/workflows/covector-version-or-publish.yml @@ -19,14 +19,16 @@ jobs: platform: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 + persist-credentials: false - - run: npm i -g --force corepack - - uses: actions/setup-node@v4 + - run: | + npm i -g --force corepack@0.34.0 + corepack enable pnpm + - uses: actions/setup-node@v7 with: - node-version: 20 cache: 'pnpm' - name: install stable @@ -35,8 +37,9 @@ 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 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 @@ -70,11 +73,14 @@ jobs: - run-integration-tests steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 - - run: npm i -g --force corepack - - uses: actions/setup-node@v6 + persist-credentials: false + - run: | + npm i -g --force corepack@0.34.0 + corepack enable pnpm + - uses: actions/setup-node@v7 with: node-version: 24 @@ -87,8 +93,9 @@ 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 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 @@ -108,7 +115,7 @@ jobs: - name: Create Pull Request With Versions Bumped if: steps.covector.outputs.commandRan == 'version' - uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # 7.0.6 + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: token: ${{ secrets.GITHUB_TOKEN }} branch: release/version-updates diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ca9b2623640f..8baa7d1a14d9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -17,15 +17,18 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: install stable uses: dtolnay/rust-toolchain@stable - 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-3-dev + sudo apt-get install -y libgtk-4-dev - name: install cross run: cargo install cross --git https://github.com/cross-rs/cross @@ -59,7 +62,9 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: install stable uses: dtolnay/rust-toolchain@stable @@ -68,7 +73,7 @@ jobs: - run: npm i -g --force corepack - name: Setup node - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: 'lts/*' @@ -85,20 +90,20 @@ jobs: path: 'examples/api' - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v4 - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and export to Docker - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v7 with: context: .docker/cross file: .docker/cross/${{ matrix.target.filename }}.Dockerfile @@ -107,8 +112,9 @@ 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 webkit2gtk-4.1 libayatana-appindicator3-dev + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev libdbus-1-dev - name: Test run: | @@ -122,7 +128,7 @@ jobs: ./cargo-tauri build --runner cross --bundles deb --target ${{ matrix.target.name }} --verbose - name: Build and push - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v7 with: context: .docker/cross file: .docker/cross/${{ matrix.target.filename }}.Dockerfile diff --git a/.github/workflows/fmt.yml b/.github/workflows/fmt.yml index db0a735cec63..12cc93a37710 100644 --- a/.github/workflows/fmt.yml +++ b/.github/workflows/fmt.yml @@ -12,7 +12,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - name: install Rust stable and rustfmt uses: dtolnay/rust-toolchain@stable @@ -25,9 +27,13 @@ jobs: prettier: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - run: npm i -g --force corepack - - uses: actions/setup-node@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false + - run: | + npm i -g --force corepack@0.34.0 + corepack enable pnpm + - uses: actions/setup-node@v7 with: node-version: 'lts/*' cache: 'pnpm' @@ -38,7 +44,9 @@ jobs: name: taplo (.toml files) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - name: install Rust stable uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml index f997bb72cedf..9df617a6bfac 100644 --- a/.github/workflows/lint-js.yml +++ b/.github/workflows/lint-js.yml @@ -18,9 +18,13 @@ jobs: eslint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - run: npm i -g --force corepack - - uses: actions/setup-node@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false + - run: | + npm i -g --force corepack@0.34.0 + corepack enable pnpm + - uses: actions/setup-node@v7 with: node-version: 'lts/*' cache: 'pnpm' @@ -30,9 +34,13 @@ jobs: typescript: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - run: npm i -g --force corepack - - uses: actions/setup-node@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false + - run: | + npm i -g --force corepack@0.34.0 + corepack enable pnpm + - uses: actions/setup-node@v7 with: node-version: 'lts/*' cache: 'pnpm' diff --git a/.github/workflows/lint-rust.yml b/.github/workflows/lint-rust.yml index fb0d8ed45603..1cfa73c79760 100644 --- a/.github/workflows/lint-rust.yml +++ b/.github/workflows/lint-rust.yml @@ -68,7 +68,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 - name: Install cross if: ${{ matrix.platform.cargo == 'cross' }} diff --git a/.github/workflows/publish-cli-js.yml b/.github/workflows/publish-cli-js.yml index d5960789d2a2..429d47002985 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,18 +70,22 @@ 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 + name: stable - ${{ matrix.settings.target }} - node@22 runs-on: ${{ matrix.settings.host }} steps: - uses: actions/checkout@v7 - - run: npm i -g --force corepack + with: + persist-credentials: false + - run: | + npm i -g --force corepack@0.34.0 + corepack enable pnpm - name: Setup node - uses: actions/setup-node@v6 - if: ${{ !matrix.settings.docker }} + uses: actions/setup-node@v7 with: - node-version: 20 + node-version: 22 cache: 'pnpm' - name: Install Rust @@ -148,9 +153,11 @@ jobs: runs-on: ${{ matrix.settings.host }} steps: - uses: actions/checkout@v7 + with: + persist-credentials: false - run: npm i -g --force corepack - name: Setup node - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version: ${{ matrix.node }} cache: pnpm @@ -186,9 +193,11 @@ jobs: runs-on: ${{ contains(matrix.target, 'aarch64') && 'ubuntu-24.04-arm' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v7 + with: + persist-credentials: false - run: npm i -g --force corepack - name: Setup node - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version: ${{ matrix.node }} cache: pnpm @@ -208,8 +217,9 @@ 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 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') }} @@ -266,9 +276,11 @@ jobs: - test-linux-binding steps: - uses: actions/checkout@v7 + with: + persist-credentials: false - run: npm i -g --force corepack - name: Setup node - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version: 24 cache: 'pnpm' diff --git a/.github/workflows/publish-cli-rs.yml b/.github/workflows/publish-cli-rs.yml index e40a2ddd42d4..f98701c7cedc 100644 --- a/.github/workflows/publish-cli-rs.yml +++ b/.github/workflows/publish-cli-rs.yml @@ -45,7 +45,9 @@ jobs: cross: true steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - name: 'Setup Rust' if: ${{ !matrix.config.cross }} @@ -61,8 +63,9 @@ 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-3-dev + sudo apt-get install -y libgtk-4-dev - name: Install cross if: ${{ matrix.config.cross }} @@ -99,7 +102,9 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 + with: + persist-credentials: false - name: Download built CLIs uses: actions/download-artifact@v4.1.7 diff --git a/.github/workflows/test-android.yml b/.github/workflows/test-android.yml index 5790e5dafcf9..ceb5d8103d90 100644 --- a/.github/workflows/test-android.yml +++ b/.github/workflows/test-android.yml @@ -31,25 +31,30 @@ jobs: platform: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - - 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-3-dev webkit2gtk-4.1 + sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev - - run: npm i -g --force corepack + - run: | + npm i -g --force corepack@0.34.0 + corepack enable pnpm - name: setup node - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: lts/* cache: 'pnpm' - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v5 with: distribution: temurin java-version: 17 @@ -65,8 +70,15 @@ jobs: # TODO check after https://github.com/nttld/setup-ndk/issues/518 is fixed - name: Restore Android Symlinks if: matrix.platform == 'ubuntu-latest' || matrix.platform == 'macos-latest' + env: + NDK_PATH: ${{ steps.setup-ndk.outputs.ndk-path }} 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="${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")" diff --git a/.github/workflows/test-cli-js.yml b/.github/workflows/test-cli-js.yml index 212a915551f2..ea16ba0db7c2 100644 --- a/.github/workflows/test-cli-js.yml +++ b/.github/workflows/test-cli-js.yml @@ -33,14 +33,18 @@ jobs: platform: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - name: install Rust stable uses: dtolnay/rust-toolchain@stable - - run: npm i -g --force corepack + - run: | + npm i -g --force corepack@0.34.0 + corepack enable pnpm - name: setup node - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: 'lts/*' cache: 'pnpm' @@ -48,8 +52,9 @@ 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 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..e9d623a802b9 100644 --- a/.github/workflows/test-cli-rs.yml +++ b/.github/workflows/test-cli-rs.yml @@ -14,6 +14,8 @@ on: - 'crates/tauri-utils/**' - 'crates/tauri-bundler/**' - 'crates/tauri-cli/**' + - 'ports/**' + - 'vendor/wayland-scanner/**' - 'Cargo.toml' - 'Cargo.lock' @@ -43,10 +45,12 @@ jobs: - { target: x86_64-apple-darwin, os: macos-latest } steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - name: 'Setup Rust' - uses: dtolnay/rust-toolchain@1.90 + uses: dtolnay/rust-toolchain@1.92 with: targets: ${{ matrix.platform.target }} @@ -55,7 +59,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..4e9b87d8cd9f 100644 --- a/.github/workflows/test-core.yml +++ b/.github/workflows/test-core.yml @@ -12,6 +12,8 @@ on: paths: - '.github/workflows/test-core.yml' - 'crates/**' + - 'ports/**' + - 'vendor/wayland-scanner/**' - 'Cargo.toml' - 'Cargo.lock' - '!crates/tauri/scripts/**' @@ -39,35 +41,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' } @@ -76,7 +78,9 @@ jobs: - { args: --all-features, key: all } steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - name: install Rust uses: dtolnay/rust-toolchain@master @@ -89,7 +93,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..0b9df44d10d1 100644 --- a/.github/workflows/udeps.yml +++ b/.github/workflows/udeps.yml @@ -27,11 +27,19 @@ jobs: macros: ${{ steps.filter.outputs.macros }} runtime: ${{ steps.filter.outputs.runtime }} wry: ${{ steps.filter.outputs.wry }} + muda: ${{ steps.filter.outputs.muda }} + tao: ${{ steps.filter.outputs.tao }} + tray_icon: ${{ steps.filter.outputs.tray_icon }} + port_wry: ${{ steps.filter.outputs.port_wry }} + wayland_scanner: ${{ steps.filter.outputs.wayland_scanner }} utils: ${{ steps.filter.outputs.utils }} bundler: ${{ steps.filter.outputs.bundler }} cli: ${{ steps.filter.outputs.cli }} + macossign: ${{ steps.filter.outputs.macossign }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - uses: dorny/paths-filter@v3 id: filter with: @@ -49,6 +57,18 @@ jobs: - 'crates/tauri-runtime/**' wry: - 'crates/tauri-runtime-wry/**' + - 'ports/**' + - 'vendor/wayland-scanner/**' + muda: + - 'ports/muda/**' + tao: + - 'ports/tao/**' + tray_icon: + - 'ports/tray-icon/**' + port_wry: + - 'ports/wry/**' + wayland_scanner: + - 'vendor/wayland-scanner/**' utils: - 'crates/tauri-utils/**' bundler: @@ -68,13 +88,20 @@ jobs: needs.changes.outputs.macros == 'true' || needs.changes.outputs.runtime == 'true' || needs.changes.outputs.wry == 'true' || + needs.changes.outputs.muda == 'true' || + needs.changes.outputs.tao == 'true' || + needs.changes.outputs.tray_icon == 'true' || + needs.changes.outputs.port_wry == 'true' || + needs.changes.outputs.wayland_scanner == 'true' || needs.changes.outputs.utils == 'true' || needs.changes.outputs.bundler == 'true' || needs.changes.outputs.cli == 'true' || needs.changes.outputs.macossign == 'true' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - name: Install Rust nightly uses: dtolnay/rust-toolchain@nightly @@ -98,6 +125,11 @@ jobs: MACROS: ${{ needs.changes.outputs.macros == 'true' }} RUNTIME: ${{ needs.changes.outputs.runtime == 'true' }} WRY: ${{ needs.changes.outputs.wry == 'true' }} + MUDA: ${{ needs.changes.outputs.muda == 'true' }} + TAO: ${{ needs.changes.outputs.tao == 'true' }} + TRAY_ICON: ${{ needs.changes.outputs.tray_icon == 'true' }} + PORT_WRY: ${{ needs.changes.outputs.port_wry == 'true' }} + WAYLAND_SCANNER: ${{ needs.changes.outputs.wayland_scanner == 'true' }} UTILS: ${{ needs.changes.outputs.utils == 'true' }} BUNDLER: ${{ needs.changes.outputs.bundler == 'true' }} CLI: ${{ needs.changes.outputs.cli == 'true' }} @@ -110,11 +142,17 @@ jobs: if [ "${MACROS}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-macros\""; fi if [ "${RUNTIME}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-runtime\""; fi if [ "${WRY}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-runtime-wry\""; fi + if [ "${MUDA}" == "true" ]; then crates[${#crates[@]}]="\"./ports/muda\""; fi + if [ "${TAO}" == "true" ]; then crates[${#crates[@]}]="\"./ports/tao\""; fi + if [ "${TRAY_ICON}" == "true" ]; then crates[${#crates[@]}]="\"./ports/tray-icon\""; fi + if [ "${PORT_WRY}" == "true" ]; then crates[${#crates[@]}]="\"./ports/wry\""; fi + if [ "${WAYLAND_SCANNER}" == "true" ]; then crates[${#crates[@]}]="\"./vendor/wayland-scanner\""; fi if [ "${UTILS}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-utils\""; fi if [ "${BUNDLER}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-bundler\""; fi if [ "${CLI}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-cli\""; fi if [ "${MACOSSIGN}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-macos-sign\""; fi - echo "matrix=[$crates]" >> "$GITHUB_OUTPUT" + printf -v matrix '%s,' "${crates[@]}" + echo "matrix=[${matrix%,}]" >> "$GITHUB_OUTPUT" outputs: matrix: ${{ steps.create-matrix.outputs.matrix }} @@ -125,15 +163,18 @@ jobs: matrix: path: ${{ fromJson(needs.setup.outputs.matrix) }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + persist-credentials: false - name: Install Rust nightly uses: dtolnay/rust-toolchain@nightly - 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-3-dev + sudo apt-get install -y libgtk-4-dev - uses: Swatinem/rust-cache@v2 @@ -147,8 +188,9 @@ 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 webkit2gtk-4.1 libayatana-appindicator3-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/.prettierignore b/.prettierignore index 3494710b79e3..c4e373a9a6e2 100644 --- a/.prettierignore +++ b/.prettierignore @@ -9,6 +9,7 @@ node_modules/ target/ dist/ +/vendor/ # lock files pnpm-lock.yaml diff --git a/.scripts/ci/check-license-header.js b/.scripts/ci/check-license-header.js index 4dd48fa46150..fb07f23a3278 100644 --- a/.scripts/ci/check-license-header.js +++ b/.scripts/ci/check-license-header.js @@ -22,14 +22,16 @@ const ignore = [ 'templates', 'node_modules', 'gen', + 'vendor', 'dist', 'bundle.global.js' ] async function checkFile(file) { + const pathParts = path.normalize(file).split(path.sep) if ( extensions.some((e) => file.endsWith(e)) - && !ignore.some((i) => file.includes(`/${i}/`) || path.basename(file) === i) + && !ignore.some((i) => pathParts.includes(i)) ) { const fileStream = fs.createReadStream(file) const rl = readline.createInterface({ diff --git a/Cargo.lock b/Cargo.lock index 71196189ceeb..4a63c03852bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -187,6 +187,15 @@ 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" @@ -282,7 +291,7 @@ dependencies = [ "bitflags 2.13.0", "bytes", "chrono", - "clap", + "clap 4.5.26", "cryptographic-message-syntax", "der", "dialoguer 0.11.0", @@ -406,6 +415,15 @@ 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" @@ -489,6 +507,18 @@ dependencies = [ "syn 2.0.117", ] +[[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-trait" version = "0.1.88" @@ -500,29 +530,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "atk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" -dependencies = [ - "atk-sys", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - [[package]] name = "atomic" version = "0.6.0" @@ -538,6 +545,17 @@ 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" @@ -901,7 +919,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" dependencies = [ "once_cell", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.5.0", "proc-macro2", "quote", "syn 2.0.117", @@ -928,6 +946,15 @@ dependencies = [ "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" @@ -1031,6 +1058,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" +[[package]] +name = "bytesize" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7c8918969267b2932ffd5655509bbbea0833823058c378876953217f5fc50e" + [[package]] name = "bzip2" version = "0.4.4" @@ -1054,23 +1087,21 @@ dependencies = [ [[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", @@ -1111,7 +1142,7 @@ dependencies = [ "english-numbers", "freedesktop_entry_parser", "handlebars", - "heck 0.5.0", + "heck", "home", "ignore", "java-properties", @@ -1125,7 +1156,7 @@ dependencies = [ "regex", "serde", "serde_json", - "textwrap", + "textwrap 0.16.2", "thiserror 2.0.12", "toml 1.0.6+spec-1.1.0", "ureq", @@ -1235,9 +1266,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", @@ -1291,6 +1322,21 @@ dependencies = [ "inout", ] +[[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 0.8.0", + "textwrap 0.11.0", + "unicode-width 0.1.14", + "vec_map", +] + [[package]] name = "clap" version = "4.5.26" @@ -1310,7 +1356,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.1", ] [[package]] @@ -1319,7 +1365,7 @@ version = "4.5.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0" dependencies = [ - "clap", + "clap 4.5.26", ] [[package]] @@ -1328,7 +1374,7 @@ version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.117", @@ -1370,7 +1416,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] @@ -1412,6 +1458,15 @@ 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" @@ -1421,7 +1476,7 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width", + "unicode-width 0.2.0", "windows-sys 0.59.0", ] @@ -1433,7 +1488,7 @@ checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" dependencies = [ "encode_unicode", "libc", - "unicode-width", + "unicode-width 0.2.0", "windows-sys 0.61.2", ] @@ -1729,7 +1784,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 +1801,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", @@ -1763,6 +1831,16 @@ dependencies = [ "syn 2.0.117", ] +[[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.117", +] + [[package]] name = "ct-codecs" version = "1.1.7" @@ -1828,8 +1906,18 @@ version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.10", + "darling_macro 0.20.10", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] @@ -1842,7 +1930,20 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.11.1", + "syn 2.0.117", +] + +[[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.117", ] @@ -1852,7 +1953,18 @@ version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core", + "darling_core 0.20.10", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", "quote", "syn 2.0.117", ] @@ -1889,6 +2001,26 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "dbus-codegen" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a49da9fdfbe872d4841d56605dc42efa5e6ca3291299b87f44e1cde91a28617c" +dependencies = [ + "clap 2.34.0", + "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 = "der" version = "0.7.9" @@ -1935,7 +2067,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ - "darling", + "darling 0.20.10", "proc-macro2", "quote", "syn 2.0.117", @@ -2145,6 +2277,15 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "dlib" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" +dependencies = [ + "libloading 0.7.4", +] + [[package]] name = "dlopen2" version = "0.8.0" @@ -2183,6 +2324,27 @@ dependencies = [ "tendril 0.5.0", ] +[[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.0", +] + +[[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" @@ -2515,6 +2677,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 +2715,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", @@ -2913,39 +3096,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 +3122,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 +3154,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 = "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 = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +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]] @@ -3103,9 +3296,9 @@ 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 +3307,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,20 +3342,16 @@ 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", @@ -3172,9 +3359,9 @@ dependencies = [ [[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", @@ -3201,9 +3388,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 +3408,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,57 +3441,88 @@ 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 = "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 = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +checksum = "5ac7179400a36a04de039c24206bb841c5596992b907b43b23ee8d5bdc40d00e" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", + "proc-macro-crate 3.5.0", "proc-macro2", "quote", "syn 2.0.117", ] +[[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" @@ -3363,15 +3602,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", - "equivalent", - "foldhash 0.2.0", ] [[package]] -name = "heck" -version = "0.4.1" +name = "hashbrown" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "heck" @@ -3379,6 +3621,15 @@ 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 = "hex" version = "0.4.3" @@ -3434,6 +3685,16 @@ 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" @@ -3987,21 +4248,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", @@ -4197,9 +4458,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 +4471,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" @@ -4296,6 +4566,18 @@ dependencies = [ "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" @@ -4335,30 +4617,6 @@ 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" -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.178" @@ -4408,36 +4666,17 @@ dependencies = [ name = "libm" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" - -[[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", -] +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] -name = "libxdo-sys" -version = "0.11.0" +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db23b9e7e2b7831bbd8aac0bbeeeb7b68cbebc162b227e7052e8e55829a09212" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ + "bitflags 2.13.0", "libc", - "x11", + "redox_syscall", ] [[package]] @@ -4580,6 +4819,17 @@ dependencies = [ "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.0", + "web_atoms", +] + [[package]] name = "match_token" version = "0.1.0" @@ -4743,19 +4993,17 @@ 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-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", "once_cell", "png 0.18.1", "serde", @@ -5137,7 +5385,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", "syn 2.0.117", @@ -5180,55 +5428,57 @@ 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", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[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-foundation 0.3.2", ] [[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-foundation 0.3.2", ] [[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", + "dispatch2", "objc2 0.6.4", ] [[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", + "dispatch2", "objc2 0.6.4", "objc2-core-foundation", "objc2-io-surface", @@ -5236,22 +5486,34 @@ dependencies = [ [[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-foundation 0.3.2", ] [[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 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 = "d31f4c5b5192304996badc466aeadffe1411d73a9bbd3b18b6b2ee9d048b07bd" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ + "bitflags 2.13.0", "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2-core-foundation", + "objc2-core-graphics", ] [[package]] @@ -5283,9 +5545,9 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.13.0", "block2 0.6.2", @@ -5295,9 +5557,9 @@ dependencies = [ [[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", @@ -5331,21 +5593,21 @@ dependencies = [ [[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-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[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", @@ -5356,33 +5618,34 @@ dependencies = [ "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 0.3.2", + "objc2-quartz-core 0.3.2", "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-foundation 0.3.2", ] [[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", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", ] [[package]] @@ -5557,10 +5820,10 @@ dependencies = [ "cfg-if", "owo-colors", "oxc-miette-derive", - "textwrap", + "textwrap 0.16.2", "thiserror 2.0.12", "unicode-segmentation", - "unicode-width", + "unicode-width 0.2.0", ] [[package]] @@ -5793,22 +6056,20 @@ dependencies = [ [[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", @@ -5816,6 +6077,12 @@ 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" @@ -6321,9 +6588,9 @@ dependencies = [ [[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" @@ -6333,9 +6600,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", @@ -6440,16 +6707,6 @@ 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" @@ -6461,35 +6718,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" -dependencies = [ - "toml_edit 0.22.24", -] - -[[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" +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.4+spec-1.1.0", ] [[package]] @@ -6608,9 +6841,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", ] @@ -7032,14 +7265,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", @@ -7061,9 +7294,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", @@ -7072,9 +7305,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" @@ -7629,6 +7862,30 @@ 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" @@ -7640,6 +7897,12 @@ dependencies = [ "syn 2.0.117", ] +[[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" @@ -7770,6 +8033,25 @@ dependencies = [ "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.0.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 = "semver" version = "1.0.28" @@ -7947,17 +8229,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", @@ -7965,11 +8249,11 @@ 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", @@ -8315,7 +8599,7 @@ 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", @@ -8392,9 +8676,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", @@ -8405,9 +8689,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", @@ -8550,6 +8834,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" @@ -8571,7 +8861,7 @@ 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", @@ -8745,23 +9035,22 @@ 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.0.6+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", @@ -8771,9 +9060,9 @@ dependencies = [ "dispatch2", "dlopen2", "dpi", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", + "gdk4-wayland", + "gdk4-x11", + "gtk4", "jni", "libc", "log", @@ -8781,13 +9070,13 @@ dependencies = [ "ndk-sys", "objc2 0.6.4", "objc2-app-kit", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", "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", @@ -8796,6 +9085,15 @@ dependencies = [ "x11-dl", ] +[[package]] +name = "tao-macros" +version = "0.1.3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "tao-macros" version = "0.1.3" @@ -8826,9 +9124,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" @@ -8844,8 +9142,8 @@ dependencies = [ "embed_plist", "getrandom 0.3.4", "glob", - "gtk", - "heck 0.5.0", + "gtk4", + "heck", "http", "http-range", "image", @@ -8856,7 +9154,7 @@ dependencies = [ "muda", "objc2 0.6.4", "objc2-app-kit", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", "objc2-ui-kit", "objc2-web-kit", "percent-encoding", @@ -8885,7 +9183,7 @@ dependencies = [ "tray-icon", "url", "uuid", - "webkit2gtk", + "webkit6", "webview2-com", "window-vibrancy", "windows 0.61.1", @@ -8899,10 +9197,10 @@ dependencies = [ "cargo_toml", "dirs 6.0.0", "glob", - "heck 0.5.0", + "heck", "json-patch", "quote", - "schemars", + "schemars 0.8.21", "semver", "serde", "serde_json", @@ -8919,12 +9217,13 @@ dependencies = [ "anyhow", "ar", "bitness", + "bytesize 2.4.2", "dirs 6.0.0", "dunce", "flate2", "glob", "handlebars", - "heck 0.5.0", + "heck", "hex", "image", "log", @@ -8939,7 +9238,7 @@ dependencies = [ "serde_json", "sha1 0.11.0", "sha2 0.11.0", - "strsim", + "strsim 0.11.1", "tar", "tauri-icns", "tauri-macos-sign", @@ -8965,7 +9264,7 @@ dependencies = [ "axum", "base64 0.22.1", "cargo-mobile2", - "clap", + "clap 4.5.26", "clap_complete", "colored 3.1.1", "common-path", @@ -8979,7 +9278,7 @@ dependencies = [ "env_logger 0.11.6", "glob", "handlebars", - "heck 0.5.0", + "heck", "ignore", "image", "include_dir", @@ -9141,7 +9440,7 @@ dependencies = [ name = "tauri-macros" version = "2.6.3" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.117", @@ -9156,7 +9455,7 @@ dependencies = [ "anyhow", "glob", "plist", - "schemars", + "schemars 0.8.21", "serde", "serde_json", "tauri-utils", @@ -9174,7 +9473,7 @@ dependencies = [ "fern", "log", "objc2 0.6.4", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", "serde", "serde_json", "serde_repr", @@ -9202,7 +9501,7 @@ version = "2.11.3" dependencies = [ "cookie", "dpi", - "gtk", + "gtk4", "http", "jni", "objc2 0.6.4", @@ -9214,7 +9513,7 @@ dependencies = [ "tauri-utils", "thiserror 2.0.12", "url", - "webkit2gtk", + "webkit6", "webview2-com", "windows 0.61.1", ] @@ -9223,7 +9522,7 @@ dependencies = [ name = "tauri-runtime-wry" version = "2.11.4" dependencies = [ - "gtk", + "gtk4", "http", "jni", "log", @@ -9238,7 +9537,7 @@ dependencies = [ "tauri-utils", "tracing", "url", - "webkit2gtk", + "webkit6", "webview2-com", "windows 0.61.1", "wry", @@ -9248,7 +9547,7 @@ dependencies = [ name = "tauri-schema-generator" version = "0.0.0" dependencies = [ - "schemars", + "schemars 0.8.21", "serde", "serde_json", "tauri-utils", @@ -9278,7 +9577,7 @@ dependencies = [ "brotli", "cargo_metadata", "ctor", - "dom_query", + "dom_query 0.27.0", "dunce", "getrandom 0.3.4", "glob", @@ -9295,7 +9594,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "schemars", + "schemars 0.8.21", "semver", "serde", "serde-untagged", @@ -9381,6 +9680,15 @@ dependencies = [ "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" @@ -9390,7 +9698,7 @@ dependencies = [ "smawk", "terminal_size", "unicode-linebreak", - "unicode-width", + "unicode-width 0.2.0", ] [[package]] @@ -9662,17 +9970,6 @@ 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" @@ -9807,19 +10104,18 @@ dependencies = [ [[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-app-kit", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", "once_cell", "png 0.18.1", "serde", @@ -10028,6 +10324,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + [[package]] name = "unicode-width" version = "0.2.0" @@ -10247,6 +10549,12 @@ 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" @@ -10421,6 +10729,64 @@ 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 1.0.7", + "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.0.7", + "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" +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", + "pkg-config", +] + [[package]] name = "web-sys" version = "0.3.102" @@ -10454,45 +10820,34 @@ 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", ] @@ -10615,7 +10970,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] @@ -10633,7 +10988,7 @@ dependencies = [ "objc2 0.6.4", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", "raw-window-handle", "windows-sys 0.59.0", "windows-version", @@ -11207,29 +11562,25 @@ 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", "cookie", "crossbeam-channel", "dirs 6.0.0", - "dom_query", + "dom_query 0.28.0", "dpi", "dunce", - "gdkx11", - "gtk", + "gtk4", "http", - "javascriptcore-rs", "jni", "libc", "ndk", "objc2 0.6.4", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.2", "objc2-ui-kit", "objc2-web-kit", "once_cell", @@ -11237,17 +11588,16 @@ dependencies = [ "raw-window-handle", "sha2 0.10.8", "soup3", - "tao-macros", + "tao", + "tao-macros 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 2.0.12", "tracing", "url", - "webkit2gtk", - "webkit2gtk-sys", + "webkit6", "webview2-com", "windows 0.61.1", "windows-core 0.61.0", "windows-version", - "x11-dl", ] [[package]] @@ -11259,16 +11609,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" @@ -11538,7 +11878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce824a6bfffe8942820fa36d24973b7c83a40896749a42e33de0abdd11750ee5" dependencies = [ "byteorder", - "bytesize", + "bytesize 1.3.0", "thiserror 1.0.69", ] diff --git a/Cargo.toml b/Cargo.toml index 3bf88a350845..bcf63f174663 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] @@ -43,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] @@ -68,7 +69,12 @@ 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" } +wayland-scanner = { path = "./vendor/wayland-scanner" } +wry = { path = "./ports/wry" } diff --git a/audits/GTK4_WebKit6_supply_chain_notes.md b/audits/GTK4_WebKit6_supply_chain_notes.md new file mode 100644 index 000000000000..95df5c249b71 --- /dev/null +++ b/audits/GTK4_WebKit6_supply_chain_notes.md @@ -0,0 +1,164 @@ +# GTK4 / WebKitGTK 6 Supply Chain Notes + +Date: 2026-07-19 + +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. | + +`wayland-scanner 0.31.10` is vendored from its crates.io release under +`vendor/wayland-scanner`. It carries Smithay's one-line `xml10_content` parser +adapter from `ec2d9328` and the upstream `quick-xml 0.41` bump from `d07c4f91`, +resolving `RUSTSEC-2026-0194` and `RUSTSEC-2026-0195`. The other Wayland crates +remain on their compatible crates.io releases. Using Smithay's full unreleased +snapshot would also pull intentional code-generation and public-API changes, +breaking released consumers such as `wayland-cursor` and Smithay Client Toolkit. +Remove the vendor patch after Smithay publishes a compatible scanner release +containing the security bump. + +`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 standalone Muda, Tao, Tray Icon, and Wry repositories carry the same +API-compatible scanner vendor patch and tracked lockfile metadata. Tray Icon's +`eframe` example disables the default AccessKit feature, removing the obsolete +`zbus_xml -> quick-xml 0.30` path, and Tao's lockfile updates +`crossbeam-epoch` to `0.9.20`. Wry no longer ignores the two `quick-xml` +advisories in its audit configuration. + +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/crates/tauri-bundler/Cargo.toml b/crates/tauri-bundler/Cargo.toml index 4d3255875587..ae51b02d9c81 100644 --- a/crates/tauri-bundler/Cargo.toml +++ b/crates/tauri-bundler/Cargo.toml @@ -27,6 +27,7 @@ serde = { version = "1", features = ["derive"] } strsim = "0.11" tar = "0.4" walkdir = "2" +bytesize = "2" handlebars = "6" tempfile = "3" log = { version = "0.4.21", features = ["kv"] } diff --git a/crates/tauri-bundler/README.md b/crates/tauri-bundler/README.md index afd6a5b90bed..60fb8438b52d 100644 --- a/crates/tauri-bundler/README.md +++ b/crates/tauri-bundler/README.md @@ -4,7 +4,7 @@ Wrap Rust executables in OS-specific app bundles. ## About -This is a fork of the awesome [cargo-bundle](https://github.com/burtonageo/cargo-bundle), turned into a library used by the [Tauri CLI](../cli). +This is a fork of the awesome [cargo-bundle](https://github.com/burtonageo/cargo-bundle), turned into a library used by the [Tauri CLI](../tauri-cli). ### Stability diff --git a/crates/tauri-bundler/src/bundle.rs b/crates/tauri-bundler/src/bundle.rs index 34d79f5f5bdb..60685a421ef5 100644 --- a/crates/tauri-bundler/src/bundle.rs +++ b/crates/tauri-bundler/src/bundle.rs @@ -16,6 +16,7 @@ mod windows; use crate::error::ErrorExt; use anyhow::Context; +use bytesize::ByteSize; use std::{ fmt::Write, io::{Seek, SeekFrom}, @@ -290,7 +291,10 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { "" }; let path_display = display_path(path); - writeln!(printable_paths, " {path_display}{note}").unwrap(); + let size = bundle_size(path) + .map(|bytes| format!(" ({:.2})", ByteSize::b(bytes).display())) + .unwrap_or_default(); + writeln!(printable_paths, " {path_display}{note}{size}").unwrap(); } } @@ -299,6 +303,23 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { Ok(bundles) } +/// Total size in bytes of a bundle path, recursing into directories (e.g. macOS `.app`). +fn bundle_size(path: &std::path::Path) -> crate::Result { + let metadata = std::fs::symlink_metadata(path)?; + if metadata.is_dir() { + let mut total = 0; + for entry in walkdir::WalkDir::new(path) { + let entry = entry?; + if entry.file_type().is_file() || entry.path_is_symlink() { + total += entry.metadata()?.len(); + } + } + Ok(total) + } else { + Ok(metadata.len()) + } +} + fn sign_binaries_if_needed(settings: &Settings, target_os: &TargetPlatform) -> crate::Result<()> { if matches!(target_os, TargetPlatform::Windows) { if settings.windows().can_sign() { @@ -356,3 +377,19 @@ pub fn check_icons(settings: &Settings) -> crate::Result { Ok(true) } } + +#[cfg(test)] +mod tests { + use super::bundle_size; + + #[test] + fn bundle_size_excludes_directory_metadata() { + let temp = tempfile::tempdir().unwrap(); + let nested = temp.path().join("nested"); + std::fs::create_dir(&nested).unwrap(); + std::fs::write(temp.path().join("one"), [0; 3]).unwrap(); + std::fs::write(nested.join("two"), [0; 5]).unwrap(); + + assert_eq!(bundle_size(temp.path()).unwrap(), 8); + } +} 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..a5e0f59a0653 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, @@ -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() { diff --git a/crates/tauri-bundler/src/bundle/windows/msi/mod.rs b/crates/tauri-bundler/src/bundle/windows/msi/mod.rs index c7d15fb501d3..59be1efc5ace 100644 --- a/crates/tauri-bundler/src/bundle/windows/msi/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/msi/mod.rs @@ -97,9 +97,6 @@ const UUID_NAMESPACE: [u8; 16] = [ 0xfd, 0x85, 0x95, 0xa8, 0x17, 0xa3, 0x47, 0x4e, 0xa6, 0x16, 0x76, 0x14, 0x8d, 0xfa, 0x0c, 0x7b, ]; -/// Mapper between a resource directory name and its ResourceDirectory descriptor. -type ResourceMap = BTreeMap; - #[derive(Debug, Deserialize)] struct LanguageMetadata { #[serde(rename = "asciiCode")] @@ -123,28 +120,36 @@ struct Binary { /// A Resource file to bundle with WIX. /// This data structure is needed because WIX requires each path to have its own `id` and `guid`. -#[derive(Serialize, Clone)] struct ResourceFile { /// the GUID to use on the WIX XML. guid: String, /// the id to use on the WIX XML. id: String, - /// the file path. - path: PathBuf, + /// the source file path. + source_path: PathBuf, + /// file name override, defaulting to the file name of [`Self::source_path`]. + target_name_override: Option, +} + +impl ResourceFile { + fn new(source_path: PathBuf, target_name_override: Option) -> Self { + Self { + id: format!("I{}", Uuid::new_v4().as_simple()), + guid: Uuid::new_v4().to_string(), + source_path, + target_name_override, + } + } } /// A resource directory to bundle with WIX. /// This data structure is needed because WIX requires each path to have its own `id` and `guid`. -#[derive(Serialize)] +#[derive(Default)] struct ResourceDirectory { - /// the directory path. - path: String, - /// the directory name of the described resource. - name: String, /// the files of the described resource directory. files: Vec, /// the directories that are children of the described resource directory. - directories: Vec, + directories: BTreeMap, } impl ResourceDirectory { @@ -154,38 +159,45 @@ impl ResourceDirectory { } /// Generates the wix XML string to bundle this directory resources recursively - fn get_wix_data(self) -> crate::Result<(String, Vec)> { + fn render_wix(self, directory_name: Option) -> crate::Result<(String, Vec)> { let mut files = String::from(""); let mut file_ids = Vec::new(); for file in self.files { - file_ids.push(file.id.clone()); + let ResourceFile { + id, + guid, + source_path, + target_name_override, + } = file; + let name_attribute = target_name_override + .map(|name| format!(r#"Name="{}" "#, html_escape(&name))) + .unwrap_or_default(); + let source_path = html_escape(&source_path.to_string_lossy()); files.push_str( - format!( - r#""#, - id = file.id, - guid = file.guid, - path = html_escape(&file.path.display().to_string()) - ).as_str() + &format!( + r#""#, + ) ); + file_ids.push(id); } let mut directories = String::from(""); - for directory in self.directories { - let (wix_string, ids) = directory.get_wix_data()?; + for (directory_name, directory) in self.directories { + let (wix_string, ids) = directory.render_wix(Some(directory_name))?; for id in ids { file_ids.push(id) } directories.push_str(wix_string.as_str()); } - let wix_string = if self.name.is_empty() { - format!("{files}{directories}") - } else { + let wix_string = if let Some(directory_name) = directory_name { format!( r#"{files}{directories}"#, id = Uuid::new_v4().as_simple(), - name = html_escape(&self.name), + name = html_escape(&directory_name), files = files, directories = directories, ) + } else { + format!("{files}{directories}") }; Ok((wix_string, file_ids)) @@ -633,15 +645,7 @@ pub fn build_wix_app_installer( data.insert("binaries", binaries_json); let resources = generate_resource_data(settings)?; - let mut resources_wix_string = String::from(""); - let mut files_ids = Vec::new(); - for (_, dir) in resources { - let (wix_string, ids) = dir.get_wix_data()?; - resources_wix_string.push_str(wix_string.as_str()); - for id in ids { - files_ids.push(id); - } - } + let (resources_wix_string, files_ids) = resources.render_wix(None)?; data.insert("resources", to_json(resources_wix_string)); data.insert("resource_file_ids", to_json(files_ids)); @@ -987,11 +991,11 @@ fn get_merge_modules(settings: &Settings) -> crate::Result> { } /// Generates the data required for the resource bundling on wix -fn generate_resource_data(settings: &Settings) -> crate::Result { - let mut resources = ResourceMap::new(); +fn generate_resource_data(settings: &Settings) -> crate::Result { let cwd = std::env::current_dir()?; - let mut added_resources = Vec::new(); + let mut root_resource_directory = ResourceDirectory::default(); + let mut added_resources = HashSet::new(); for resource in settings.resource_files().iter() { let resource = resource?; @@ -1004,19 +1008,24 @@ fn generate_resource_data(settings: &Settings) -> crate::Result { if added_resources.contains(&resource_path) { continue; } - added_resources.push(resource_path.clone()); + added_resources.insert(resource_path.clone()); if settings.windows().can_sign() && should_sign(&resource_path)? { try_sign(&resource_path, settings)?; } - let resource_entry = ResourceFile { - id: format!("I{}", Uuid::new_v4().as_simple()), - guid: Uuid::new_v4().to_string(), - path: resource_path.clone(), - }; + let resource_entry = ResourceFile::new( + resource_path, + Some( + resource + .target() + .file_name() + .expect("failed to read resource file name") + .to_string_lossy() + .into_owned(), + ), + ); - // split the resource path directories let target_path = resource.target(); let components_count = target_path.components().count(); let directories = target_path @@ -1024,55 +1033,19 @@ fn generate_resource_data(settings: &Settings) -> crate::Result { .take(components_count - 1) // the last component is the file .collect::>(); - // transform the directory structure to a chained vec structure - let first_directory = directories - .first() - .map(|d| d.as_os_str().to_string_lossy().into_owned()) - .unwrap_or_else(String::new); - - if !resources.contains_key(&first_directory) { - resources.insert( - first_directory.clone(), - ResourceDirectory { - path: first_directory.clone(), - name: first_directory.clone(), - directories: vec![], - files: vec![], - }, - ); - } + let mut directory_entry = &mut root_resource_directory; - let mut directory_entry = resources - .get_mut(&first_directory) - .expect("Unable to handle resources"); - - let mut path = String::new(); - // the first component is already parsed on `first_directory` so we skip(1) - for directory in directories.into_iter().skip(1) { + for directory in directories { let directory_name = directory .as_os_str() .to_os_string() .into_string() .expect("failed to read resource folder name"); - path.push_str(directory_name.as_str()); - path.push(std::path::MAIN_SEPARATOR); - let index = directory_entry + directory_entry = directory_entry .directories - .iter() - .position(|f| f.path == path); - match index { - Some(i) => directory_entry = directory_entry.directories.get_mut(i).unwrap(), - None => { - directory_entry.directories.push(ResourceDirectory { - path: path.clone(), - name: directory_name, - directories: vec![], - files: vec![], - }); - directory_entry = directory_entry.directories.iter_mut().last().unwrap(); - } - } + .entry(directory_name) + .or_default(); } directory_entry.add_file(resource_entry); } @@ -1085,12 +1058,8 @@ fn generate_resource_data(settings: &Settings) -> crate::Result { if added_resources.contains(&resource_path.to_path_buf()) { continue; } - added_resources.push(resource_path.to_path_buf()); - dlls.push(ResourceFile { - id: format!("I{}", Uuid::new_v4().as_simple()), - guid: Uuid::new_v4().to_string(), - path: resource_path.to_path_buf(), - }); + added_resources.insert(resource_path.to_path_buf()); + dlls.push(ResourceFile::new(resource_path.to_path_buf(), None)); } } @@ -1113,27 +1082,13 @@ fn generate_resource_data(settings: &Settings) -> crate::Result { try_sign(resource_path, settings)?; } - dlls.push(ResourceFile { - id: format!("I{}", Uuid::new_v4().as_simple()), - guid: Uuid::new_v4().to_string(), - path: resource_path.to_path_buf(), - }); + dlls.push(ResourceFile::new(resource_path.to_path_buf(), None)); } } - if !dlls.is_empty() { - resources - .entry("".to_string()) - .and_modify(|r| r.files.append(&mut dlls)) - .or_insert(ResourceDirectory { - path: "".to_string(), - name: "".to_string(), - directories: vec![], - files: dlls, - }); - } + root_resource_directory.files.extend(dlls); - Ok(resources) + Ok(root_resource_directory) } #[cfg(test)] @@ -1176,4 +1131,20 @@ mod tests { assert_eq!(wix_identifier(""), "_"); assert_eq!(wix_identifier("app_1.2"), "app_1.2"); } + + #[test] + fn includes_mapped_resource_file_name_in_wix_data() { + let resource = ResourceFile::new("MyFile".into(), Some("myFileRenamed".into())); + let resource_id = resource.id.clone(); + let directory = ResourceDirectory { + files: vec![resource], + directories: BTreeMap::new(), + }; + + let (wix_data, file_ids) = directory.render_wix(None).unwrap(); + + assert_eq!(file_ids, vec![resource_id]); + assert!(wix_data.contains(r#"Name="myFileRenamed""#)); + assert!(wix_data.contains(r#"Source="MyFile""#)); + } } 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" diff --git a/crates/tauri-cli/config.schema.json b/crates/tauri-cli/config.schema.json index 83e3f88a3d0e..74560b92b988 100644 --- a/crates/tauri-cli/config.schema.json +++ b/crates/tauri-cli/config.schema.json @@ -257,7 +257,7 @@ ] }, "dragDropEnabled": { - "description": "Whether the drag and drop is enabled or not on the webview. By default it is enabled.\n\n Disabling it is required to use HTML5 drag and drop on the frontend on Windows.", + "description": "Whether the drag and drop handlers used internally to generate [`DragDropEvent`]s are enabled on the webview. By default it is enabled.\n\n Disabling it is required to use HTML5 drag and drop on the frontend on Windows since we replace the drag drop handler of WebView2.\n\n Note: this setting maps to [`WebviewBuilder::disable_drag_drop_handler`], not [`WindowBuilder::drag_and_drop`].\n\n [`DragDropEvent`]: https://docs.rs/tauri/latest/tauri/enum.DragDropEvent.html\n [`WebviewBuilder::disable_drag_drop_handler`]: https://docs.rs/tauri/latest/tauri/webview/struct.WebviewBuilder.html#method.disable_drag_drop_handler\n [`WindowBuilder::drag_and_drop`]: https://docs.rs/tauri/latest/x86_64-pc-windows-msvc/tauri/window/struct.WindowBuilder.html#method.drag_and_drop", "default": true, "type": "boolean" }, @@ -614,6 +614,11 @@ } ] }, + "limitNavigationsToAppBoundDomains": { + "description": "Whether to limit navigations to App-Bound Domains. This is necessary to\n enable Service Workers on iOS according to\n [StackOverflow](https://stackoverflow.com/questions/49673399/service-workers-unavailable-in-wkwebview-in-ios-11-3/64155509#64155509).\n\n Default is false.\n\n Note: If you set this to `true` make sure to add localhost and any [`registrable\n domains`](https://developer.mozilla.org/en-US/docs/Glossary/Registrable_domain)\n used in this webview to src-tauri/Info.ios.plist:\n\n ```xml\n \n \n WKAppBoundDomains\n \n localhost\n aregistrabledomain.example\n \n \n \n ```\n\n You must add `localhost` if any webview with this set to true opens a\n local webpage, makes any localhost calls, or uses the isolation pattern\n because Tauri uses the `localhost` domain for hosting the application\n webpage, the IPC protocol, and the isolation pattern's iframe.\n\n Requests served through custom uri schemes are allowed so long as they use\n a registrable domain specified in the `WKAppBoundDomains` array for all the\n requests from the app, including requests for the `localhost` domain.\n\n In theory, you can whitelist an entire uri scheme by including the\n protocol name followed by a colon. For example, to allow all requests\n using a custom \"stream\" uri scheme (see [this tauri\n example](https://github.com/tauri-apps/tauri/blob/dev/examples/streaming/main.rs)),\n you could add `stream:` to the AppBoundDomains array. That said, I'm not\n sure whether Apple would let your app through app review if you do\n whitelist an entire protocol because this feature is not mentioned in\n [their blog post on App-Bound\n Domains](https://webkit.org/blog/10882/app-bound-domains/).\n\n See https://webkit.org/blog/10882/app-bound-domains/ and\n https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/limitsnavigationstoappbounddomains\n for the official documentation on App-Bound Domains.\n\n ## Platform-specific\n\n - **iOS**: Supported since version 14.0+.\n - **Linux / Windows / Android / MacOS:** Unsupported.", + "default": false, + "type": "boolean" + }, "activityName": { "description": "The name of the Android activity to create for this window.", "type": [ 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/info/plugins.rs b/crates/tauri-cli/src/info/plugins.rs index d0ede6b259b3..3764af8bd77b 100644 --- a/crates/tauri-cli/src/info/plugins.rs +++ b/crates/tauri-cli/src/info/plugins.rs @@ -47,17 +47,17 @@ pub fn installed_tauri_packages( tauri_dir: &Path, package_manager: PackageManager, ) -> InstalledPackages { - let know_plugins = helpers::plugins::known_plugins(); + let known_plugins = helpers::plugins::known_plugins(); let crate_names: Vec = iter::once("tauri".to_owned()) .chain( - know_plugins + known_plugins .keys() .map(|plugin_name| format!("tauri-plugin-{plugin_name}")), ) .collect(); let npm_names: Vec = iter::once("@tauri-apps/api".to_owned()) .chain( - know_plugins + known_plugins .keys() .map(|plugin_name| format!("@tauri-apps/plugin-{plugin_name}")), ) @@ -114,8 +114,8 @@ pub fn items( if let Some(tauri_dir) = tauri_dir { let (manifest, lock) = cargo_manifest_and_lock(tauri_dir); - for p in helpers::plugins::known_plugins().keys() { - let dep = format!("tauri-plugin-{p}"); + for (name, metadata) in helpers::plugins::known_plugins() { + let dep = format!("tauri-plugin-{name}"); let crate_version = crate_version(tauri_dir, manifest.as_ref(), lock.as_ref(), &dep); if !crate_version.has_version() { continue; @@ -123,11 +123,15 @@ pub fn items( let item = packages_rust::rust_section_item(&dep, crate_version); items.push(item); + if metadata.rust_only { + continue; + } + let Some(frontend_dir) = frontend_dir else { continue; }; - let package = format!("@tauri-apps/plugin-{p}"); + let package = format!("@tauri-apps/plugin-{name}"); let item = packages_nodejs::nodejs_section_item(package, None, frontend_dir.clone(), package_manager); 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/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-cli/src/mobile/android/mod.rs b/crates/tauri-cli/src/mobile/android/mod.rs index c0add29e61bc..9cbcd8ec0b5f 100644 --- a/crates/tauri-cli/src/mobile/android/mod.rs +++ b/crates/tauri-cli/src/mobile/android/mod.rs @@ -917,11 +917,7 @@ fn restart_emulator(env: &Env, serial_no: &str, emulator: &emulator::Emulator) - log::info!("Waiting for emulator to exit..."); loop { let devices = adb::device_list(env).unwrap_or_default(); - if devices - .into_iter() - .find(|d| d.serial_no() == serial_no) - .is_none() - { + if !devices.into_iter().any(|d| d.serial_no() == serial_no) { break; } sleep(Duration::from_secs(1)); 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}} 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..944e218eefe4 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,12 +51,19 @@ android { ) } } - kotlinOptions { - jvmTarget = "1.8" - } buildFeatures { buildConfig = true } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_1_8 + } } rust { @@ -77,4 +85,4 @@ dependencies { androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") } -apply(from = "tauri.build.gradle.kts") \ No newline at end of file +apply(from = "tauri.build.gradle.kts") diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/values-night/themes.xml b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values-night/themes.xml index d4abdc82e8c9..75861db36a76 100644 --- a/crates/tauri-cli/templates/mobile/android/app/src/main/res/values-night/themes.xml +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values-night/themes.xml @@ -1,6 +1,6 @@ - diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/themes.xml b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/themes.xml index d4abdc82e8c9..75861db36a76 100644 --- a/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/themes.xml +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/themes.xml @@ -1,6 +1,6 @@ - diff --git a/crates/tauri-cli/templates/plugin/.github/workflows/audit.yml b/crates/tauri-cli/templates/plugin/.github/workflows/audit.yml index 4121fa6470da..3bc3a459280e 100644 --- a/crates/tauri-cli/templates/plugin/.github/workflows/audit.yml +++ b/crates/tauri-cli/templates/plugin/.github/workflows/audit.yml @@ -27,8 +27,8 @@ jobs: audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: rustsec/audit-check@v1 + - uses: actions/checkout@v7 + - uses: rustsec/audit-check@v2 with: token: ${{ secrets.GITHUB_TOKEN }} {{{{/raw}}}} diff --git a/crates/tauri-cli/templates/plugin/.github/workflows/clippy.yml b/crates/tauri-cli/templates/plugin/.github/workflows/clippy.yml index 23556aeb345a..a716b14cde3f 100644 --- a/crates/tauri-cli/templates/plugin/.github/workflows/clippy.yml +++ b/crates/tauri-cli/templates/plugin/.github/workflows/clippy.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt @@ -41,15 +41,15 @@ jobs: runs-on: ${{ matrix.platform }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@stable with: components: clippy - - name: install webkit2gtk + - name: install WebKitGTK and GTK if: matrix.platform == 'ubuntu-latest' run: | sudo apt-get update - sudo apt-get install -y webkit2gtk-4.1 + sudo apt-get install -y libwebkitgtk-6.0-dev libgtk-4-dev - uses: Swatinem/rust-cache@v2 - run: cargo clippy --all-targets --all-features -- -D warnings {{{{/raw}}}} diff --git a/crates/tauri-cli/templates/plugin/.github/workflows/test.yml b/crates/tauri-cli/templates/plugin/.github/workflows/test.yml index c528a4506fde..c44ef69cd2a5 100644 --- a/crates/tauri-cli/templates/plugin/.github/workflows/test.yml +++ b/crates/tauri-cli/templates/plugin/.github/workflows/test.yml @@ -23,13 +23,13 @@ jobs: runs-on: ${{ matrix.platform }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@stable - - name: install webkit2gtk + - name: install WebKitGTK and GTK if: matrix.platform == 'ubuntu-latest' run: | sudo apt-get update - sudo apt-get install -y webkit2gtk-4.1 + sudo apt-get install -y libwebkitgtk-6.0-dev libgtk-4-dev - uses: Swatinem/rust-cache@v2 - run: cargo test --all-targets --all-features -- -D warnings {{{{/raw}}}} 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-macros/src/lib.rs b/crates/tauri-macros/src/lib.rs index cf02da7f49c0..034f991447ab 100644 --- a/crates/tauri-macros/src/lib.rs +++ b/crates/tauri-macros/src/lib.rs @@ -131,27 +131,27 @@ pub fn default_runtime(attributes: TokenStream, input: TokenStream) -> TokenStre /// let kind = ItemKind::Check; /// let resources_table = app.resources_table(); /// match kind { -/// ItemKind::Submenu => { -/// let i = resources_table.get::>(rid)?; -/// i.set_text(text) -/// } -/// ItemKind::MenuItem => { -/// let i = resources_table.get::>(rid)?; -/// i.set_text(text) -/// } -/// ItemKind::Predefined => { -/// let i = resources_table.get::>(rid)?; -/// i.set_text(text) -/// } -/// ItemKind::Check => { -/// let i = resources_table.get::>(rid)?; -/// i.set_text(text) -/// } -/// ItemKind::Icon => { -/// let i = resources_table.get::>(rid)?; -/// i.set_text(text) -/// } -/// _ => unreachable!(), +/// ItemKind::Submenu => { +/// let i = resources_table.get::>(rid)?; +/// i.set_text(text) +/// } +/// ItemKind::MenuItem => { +/// let i = resources_table.get::>(rid)?; +/// i.set_text(text) +/// } +/// ItemKind::Predefined => { +/// let i = resources_table.get::>(rid)?; +/// i.set_text(text) +/// } +/// ItemKind::Check => { +/// let i = resources_table.get::>(rid)?; +/// i.set_text(text) +/// } +/// ItemKind::Icon => { +/// let i = resources_table.get::>(rid)?; +/// i.set_text(text) +/// } +/// _ => unreachable!(), /// } /// ``` #[proc_macro] 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 8a3da8d31fdc..9ad759075f4f 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")] @@ -138,7 +146,7 @@ use std::{ }; pub type WebviewId = u32; -type IpcHandler = dyn Fn(Request) + 'static; +type IpcHandler = dyn Fn(Request) + Send + Sync + 'static; #[cfg(not(debug_assertions))] mod dialog; @@ -940,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 /// @@ -952,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 @@ -1089,7 +1103,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 } @@ -3330,7 +3344,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 +4580,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", @@ -5051,6 +5067,10 @@ You may have it installed on another user account, but it is not available for t #[cfg(target_os = "ios")] { + webview_builder = webview_builder.with_limit_navigations_to_app_bound_domains( + webview_attributes.limit_navigations_to_app_bound_domains, + ); + if let Some(input_accessory_view_builder) = webview_attributes.input_accessory_view_builder { webview_builder = webview_builder .with_input_accessory_view_builder(move |webview| input_accessory_view_builder.0(webview)); @@ -5145,7 +5165,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", @@ -5153,7 +5173,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-runtime-wry/src/monitor/linux.rs b/crates/tauri-runtime-wry/src/monitor/linux.rs index 62f87eb05c03..e8645d9bf719 100644 --- a/crates/tauri-runtime-wry/src/monitor/linux.rs +++ b/crates/tauri-runtime-wry/src/monitor/linux.rs @@ -2,13 +2,15 @@ // 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(); + // 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 { 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 69a7863a4fd3..73f4c702c3a8 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-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-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..36206e1d6541 100644 --- a/crates/tauri-runtime/src/webview.rs +++ b/crates/tauri-runtime/src/webview.rs @@ -31,13 +31,13 @@ type UriSchemeProtocolHandler = dyn Fn(&str, http::Request>, Box>, &mut http::Response>) + Send + Sync; -type NavigationHandler = dyn Fn(&Url) -> bool + Send; +type NavigationHandler = dyn Fn(&Url) -> bool + Send + Sync; type NewWindowHandler = dyn Fn(Url, NewWindowFeatures) -> NewWindowResponse + Send; -type OnPageLoadHandler = dyn Fn(Url, PageLoadEvent) + Send; +type OnPageLoadHandler = dyn Fn(Url, PageLoadEvent) + Send + Sync; -type DocumentTitleChangedHandler = dyn Fn(String) + Send + 'static; +type DocumentTitleChangedHandler = dyn Fn(String) + Send + Sync + 'static; type DownloadHandler = dyn Fn(DownloadEvent) -> bool + Send + Sync; @@ -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`]. @@ -402,6 +402,8 @@ pub struct WebviewAttributes { /// This relies on [`objc2_ui_kit`] which does not provide a stable API yet, so it can receive breaking changes in minor releases. #[cfg(target_os = "ios")] pub input_accessory_view_builder: Option, + #[cfg(target_os = "ios")] + pub limit_navigations_to_app_bound_domains: bool, /// Set the environment for the webview. /// Useful if you need to share the same environment, for instance when using the [`PendingWebview::new_window_handler`]. @@ -417,7 +419,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>, @@ -460,6 +462,7 @@ impl From<&WindowConfig> for WebviewAttributes { ConfigScrollBarStyle::FluentOverlay => ScrollBarStyle::FluentOverlay, _ => ScrollBarStyle::Default, }) + .limit_navigations_to_app_bound_domains(config.limit_navigations_to_app_bound_domains) .general_autofill_enabled(config.general_autofill_enabled); #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))] @@ -538,6 +541,8 @@ impl WebviewAttributes { general_autofill_enabled: true, #[cfg(target_os = "ios")] input_accessory_view_builder: None, + #[cfg(target_os = "ios")] + limit_navigations_to_app_bound_domains: false, #[cfg(windows)] environment: None, #[cfg(any( @@ -619,7 +624,9 @@ impl WebviewAttributes { self } - /// Disables the drag and drop handler. This is required to use HTML5 drag and drop APIs on the frontend on Windows. + /// Disables the drag and drop handler used internally to generate [`DragDropEvent`](crate::window::DragDropEvent)s. + /// + /// This is required to use HTML5 drag and drop APIs on the frontend on Windows since we replace the drag drop handler of WebView2. #[must_use] pub fn disable_drag_drop_handler(mut self) -> Self { self.drag_drop_handler_enabled = false; @@ -789,6 +796,65 @@ impl WebviewAttributes { self } + /// Whether to limit navigations to App-Bound Domains. This is necessary to + /// enable Service Workers on iOS according to + /// [StackOverflow](https://stackoverflow.com/questions/49673399/service-workers-unavailable-in-wkwebview-in-ios-11-3/64155509#64155509). + /// + /// Default is false. + /// + /// Note: If you pass in `true` make sure to add localhost and any [`registrable + /// domains`](https://developer.mozilla.org/en-US/docs/Glossary/Registrable_domain) + /// used in this webview to tauri-src/Info.ios.plist: + /// + /// ```xml + /// + /// + /// WKAppBoundDomains + /// + /// localhost + /// aregistrabledomain.example + /// + /// + /// + /// ``` + /// + /// You must add `localhost` if any webview with this set to true opens a + /// local webpage, makes any localhost calls, or uses the isolation pattern + /// because Tauri uses the `localhost` domain for hosting the application + /// webpage, the IPC protocol, and the isolation pattern's iframe. + /// + /// Requests served through custom uri schemes are allowed so long as they use + /// a registrable domain specified in the `WKAppBoundDomains` array for all the + /// requests from the app, including requests for the `localhost` domain. + /// + /// In theory, you can whitelist an entire uri scheme by including the + /// protocol name followed by a colon. For example, to allow all requests + /// using a custom "stream" uri scheme (see [this tauri + /// example](https://github.com/tauri-apps/tauri/blob/dev/examples/streaming/main.rs)), + /// you could add `stream:` to the AppBoundDomains array. That said, I'm not + /// sure whether Apple would let your app through app review if you do + /// whitelist an entire protocol because this feature is not mentioned in + /// [their blog post on App-Bound + /// Domains](https://webkit.org/blog/10882/app-bound-domains/). + /// + /// See https://webkit.org/blog/10882/app-bound-domains/ and + /// https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/limitsnavigationstoappbounddomains + /// for the official documentation on App-Bound Domains. + /// + /// ## Platform-specific + /// + /// - **iOS**: Supported since version 14.0+. + /// - **Linux / Windows / Android / MacOS:** Unsupported. + #[must_use] + #[allow(unused_variables, unused_mut)] + pub fn limit_navigations_to_app_bound_domains(mut self, limit_navigations: bool) -> Self { + #[cfg(target_os = "ios")] + { + self.limit_navigations_to_app_bound_domains = limit_navigations; + } + self + } + /// Change the default background throttling behavior. /// /// By default, browsers use a suspend policy that will throttle timers and even unload @@ -853,7 +919,8 @@ impl WebviewAttributes { } /// IPC handler. -pub type WebviewIpcHandler = Box, Request) + Send>; +pub type WebviewIpcHandler = + Box, Request) + Send + Sync>; /// An initialization script #[derive(Debug, Clone)] diff --git a/crates/tauri-runtime/src/window.rs b/crates/tauri-runtime/src/window.rs index 936280ca18c3..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 @@ -447,7 +453,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 +461,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-schema-generator/schemas/config.schema.json b/crates/tauri-schema-generator/schemas/config.schema.json index 83e3f88a3d0e..74560b92b988 100644 --- a/crates/tauri-schema-generator/schemas/config.schema.json +++ b/crates/tauri-schema-generator/schemas/config.schema.json @@ -257,7 +257,7 @@ ] }, "dragDropEnabled": { - "description": "Whether the drag and drop is enabled or not on the webview. By default it is enabled.\n\n Disabling it is required to use HTML5 drag and drop on the frontend on Windows.", + "description": "Whether the drag and drop handlers used internally to generate [`DragDropEvent`]s are enabled on the webview. By default it is enabled.\n\n Disabling it is required to use HTML5 drag and drop on the frontend on Windows since we replace the drag drop handler of WebView2.\n\n Note: this setting maps to [`WebviewBuilder::disable_drag_drop_handler`], not [`WindowBuilder::drag_and_drop`].\n\n [`DragDropEvent`]: https://docs.rs/tauri/latest/tauri/enum.DragDropEvent.html\n [`WebviewBuilder::disable_drag_drop_handler`]: https://docs.rs/tauri/latest/tauri/webview/struct.WebviewBuilder.html#method.disable_drag_drop_handler\n [`WindowBuilder::drag_and_drop`]: https://docs.rs/tauri/latest/x86_64-pc-windows-msvc/tauri/window/struct.WindowBuilder.html#method.drag_and_drop", "default": true, "type": "boolean" }, @@ -614,6 +614,11 @@ } ] }, + "limitNavigationsToAppBoundDomains": { + "description": "Whether to limit navigations to App-Bound Domains. This is necessary to\n enable Service Workers on iOS according to\n [StackOverflow](https://stackoverflow.com/questions/49673399/service-workers-unavailable-in-wkwebview-in-ios-11-3/64155509#64155509).\n\n Default is false.\n\n Note: If you set this to `true` make sure to add localhost and any [`registrable\n domains`](https://developer.mozilla.org/en-US/docs/Glossary/Registrable_domain)\n used in this webview to src-tauri/Info.ios.plist:\n\n ```xml\n \n \n WKAppBoundDomains\n \n localhost\n aregistrabledomain.example\n \n \n \n ```\n\n You must add `localhost` if any webview with this set to true opens a\n local webpage, makes any localhost calls, or uses the isolation pattern\n because Tauri uses the `localhost` domain for hosting the application\n webpage, the IPC protocol, and the isolation pattern's iframe.\n\n Requests served through custom uri schemes are allowed so long as they use\n a registrable domain specified in the `WKAppBoundDomains` array for all the\n requests from the app, including requests for the `localhost` domain.\n\n In theory, you can whitelist an entire uri scheme by including the\n protocol name followed by a colon. For example, to allow all requests\n using a custom \"stream\" uri scheme (see [this tauri\n example](https://github.com/tauri-apps/tauri/blob/dev/examples/streaming/main.rs)),\n you could add `stream:` to the AppBoundDomains array. That said, I'm not\n sure whether Apple would let your app through app review if you do\n whitelist an entire protocol because this feature is not mentioned in\n [their blog post on App-Bound\n Domains](https://webkit.org/blog/10882/app-bound-domains/).\n\n See https://webkit.org/blog/10882/app-bound-domains/ and\n https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/limitsnavigationstoappbounddomains\n for the official documentation on App-Bound Domains.\n\n ## Platform-specific\n\n - **iOS**: Supported since version 14.0+.\n - **Linux / Windows / Android / MacOS:** Unsupported.", + "default": false, + "type": "boolean" + }, "activityName": { "description": "The name of the Android activity to create for this window.", "type": [ diff --git a/crates/tauri-utils/src/acl/resolved.rs b/crates/tauri-utils/src/acl/resolved.rs index 8aa4322f5640..101725e95874 100644 --- a/crates/tauri-utils/src/acl/resolved.rs +++ b/crates/tauri-utils/src/acl/resolved.rs @@ -19,16 +19,37 @@ use super::{ /// A key for a scope, used to link a [`ResolvedCommand#structfield.scope`] to the store [`Resolved#structfield.scopes`]. pub type ScopeKey = u64; +// All the fields are marked with `#[cfg(debug_assertions)]` but not the struct itself is because +// we want to avoid compilation errors on different `debug_assertions` settings, +// see https://github.com/tauri-apps/tauri/issues/13865 /// Metadata for what referenced a [`ResolvedCommand`]. -#[cfg(debug_assertions)] #[derive(Default, Clone, PartialEq, Eq)] pub struct ResolvedCommandReference { /// Identifier of the capability. + #[cfg(debug_assertions)] pub capability: String, /// Identifier of the permission. + #[cfg(debug_assertions)] pub permission: String, } +impl ResolvedCommandReference { + /// Internal helper for tauri-macros to avoid compilation errors on different `debug_assertions` settings, + /// see https://github.com/tauri-apps/tauri/issues/13865 + #[doc(hidden)] + pub fn new( + #[cfg_attr(not(debug_assertions), allow(unused))] capability: String, + #[cfg_attr(not(debug_assertions), allow(unused))] permission: String, + ) -> Self { + Self { + #[cfg(debug_assertions)] + capability, + #[cfg(debug_assertions)] + permission, + } + } +} + /// A resolved command permission. #[derive(Default, Clone, PartialEq, Eq)] pub struct ResolvedCommand { @@ -45,6 +66,28 @@ pub struct ResolvedCommand { pub scope_id: Option, } +impl ResolvedCommand { + /// Internal helper for tauri-macros to avoid compilation errors on different `debug_assertions` settings, + /// see https://github.com/tauri-apps/tauri/issues/13865 + #[doc(hidden)] + pub fn new( + context: ExecutionContext, + #[cfg_attr(not(debug_assertions), allow(unused))] referenced_by: ResolvedCommandReference, + windows: Vec, + webviews: Vec, + scope_id: Option, + ) -> Self { + Self { + context, + #[cfg(debug_assertions)] + referenced_by, + windows, + webviews, + scope_id, + } + } +} + impl fmt::Debug for ResolvedCommand { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ResolvedCommand") @@ -452,12 +495,9 @@ mod build { fn to_tokens(&self, tokens: &mut TokenStream) { let capability = str_lit(&self.capability); let permission = str_lit(&self.permission); - literal_struct!( - tokens, - ::tauri::utils::acl::resolved::ResolvedCommandReference, - capability, - permission - ) + tokens.append_all(quote! { + ::tauri::utils::acl::resolved::ResolvedCommandReference::new(#capability, #permission) + }); } } @@ -465,6 +505,9 @@ mod build { fn to_tokens(&self, tokens: &mut TokenStream) { #[cfg(debug_assertions)] let referenced_by = &self.referenced_by; + #[cfg(not(debug_assertions))] + let referenced_by = + quote!(::tauri::utils::acl::resolved::ResolvedCommandReference::default()); let context = &self.context; @@ -478,27 +521,15 @@ mod build { }); let scope_id = opt_lit(self.scope_id.as_ref()); - #[cfg(debug_assertions)] - { - literal_struct!( - tokens, - ::tauri::utils::acl::resolved::ResolvedCommand, - context, - referenced_by, - windows, - webviews, - scope_id + tokens.append_all(quote! { + ::tauri::utils::acl::resolved::ResolvedCommand::new( + #context, + #referenced_by, + #windows, + #webviews, + #scope_id ) - } - #[cfg(not(debug_assertions))] - literal_struct!( - tokens, - ::tauri::utils::acl::resolved::ResolvedCommand, - context, - windows, - webviews, - scope_id - ) + }) } } diff --git a/crates/tauri-utils/src/config.rs b/crates/tauri-utils/src/config.rs index d464af84e874..da0c5369760c 100644 --- a/crates/tauri-utils/src/config.rs +++ b/crates/tauri-utils/src/config.rs @@ -1953,9 +1953,15 @@ pub struct WindowConfig { /// The user agent for the webview #[serde(alias = "user-agent")] pub user_agent: Option, - /// Whether the drag and drop is enabled or not on the webview. By default it is enabled. + /// Whether the drag and drop handlers used internally to generate [`DragDropEvent`]s are enabled on the webview. By default it is enabled. /// - /// Disabling it is required to use HTML5 drag and drop on the frontend on Windows. + /// Disabling it is required to use HTML5 drag and drop on the frontend on Windows since we replace the drag drop handler of WebView2. + /// + /// Note: this setting maps to [`WebviewBuilder::disable_drag_drop_handler`], not [`WindowBuilder::drag_and_drop`]. + /// + /// [`DragDropEvent`]: https://docs.rs/tauri/latest/tauri/enum.DragDropEvent.html + /// [`WebviewBuilder::disable_drag_drop_handler`]: https://docs.rs/tauri/latest/tauri/webview/struct.WebviewBuilder.html#method.disable_drag_drop_handler + /// [`WindowBuilder::drag_and_drop`]: https://docs.rs/tauri/latest/x86_64-pc-windows-msvc/tauri/window/struct.WindowBuilder.html#method.drag_and_drop #[serde(default = "default_true", alias = "drag-drop-enabled")] pub drag_drop_enabled: bool, /// Whether or not the window starts centered or not. @@ -2276,6 +2282,58 @@ pub struct WindowConfig { /// - **Linux / Android / iOS / macOS**: Unsupported. Only supports `Default` and performs no operation. #[serde(default, alias = "scroll-bar-style")] pub scroll_bar_style: ScrollBarStyle, + + /// Whether to limit navigations to App-Bound Domains. This is necessary to + /// enable Service Workers on iOS according to + /// [StackOverflow](https://stackoverflow.com/questions/49673399/service-workers-unavailable-in-wkwebview-in-ios-11-3/64155509#64155509). + /// + /// Default is false. + /// + /// Note: If you set this to `true` make sure to add localhost and any [`registrable + /// domains`](https://developer.mozilla.org/en-US/docs/Glossary/Registrable_domain) + /// used in this webview to src-tauri/Info.ios.plist: + /// + /// ```xml + /// + /// + /// WKAppBoundDomains + /// + /// localhost + /// aregistrabledomain.example + /// + /// + /// + /// ``` + /// + /// You must add `localhost` if any webview with this set to true opens a + /// local webpage, makes any localhost calls, or uses the isolation pattern + /// because Tauri uses the `localhost` domain for hosting the application + /// webpage, the IPC protocol, and the isolation pattern's iframe. + /// + /// Requests served through custom uri schemes are allowed so long as they use + /// a registrable domain specified in the `WKAppBoundDomains` array for all the + /// requests from the app, including requests for the `localhost` domain. + /// + /// In theory, you can whitelist an entire uri scheme by including the + /// protocol name followed by a colon. For example, to allow all requests + /// using a custom "stream" uri scheme (see [this tauri + /// example](https://github.com/tauri-apps/tauri/blob/dev/examples/streaming/main.rs)), + /// you could add `stream:` to the AppBoundDomains array. That said, I'm not + /// sure whether Apple would let your app through app review if you do + /// whitelist an entire protocol because this feature is not mentioned in + /// [their blog post on App-Bound + /// Domains](https://webkit.org/blog/10882/app-bound-domains/). + /// + /// See https://webkit.org/blog/10882/app-bound-domains/ and + /// https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/limitsnavigationstoappbounddomains + /// for the official documentation on App-Bound Domains. + /// + /// ## Platform-specific + /// + /// - **iOS**: Supported since version 14.0+. + /// - **Linux / Windows / Android / MacOS:** Unsupported. + #[serde(default, alias = "limit-navigations-to-app-bound-domains")] + pub limit_navigations_to_app_bound_domains: bool, /// The name of the Android activity to create for this window. #[serde(default, alias = "activity-name")] pub activity_name: Option, @@ -2373,6 +2431,7 @@ impl Default for WindowConfig { data_directory: None, data_store_identifier: None, scroll_bar_style: ScrollBarStyle::Default, + limit_navigations_to_app_bound_domains: false, activity_name: None, created_by_activity_name: None, requested_by_scene_identifier: None, @@ -3950,6 +4009,7 @@ mod build { let data_directory = opt_lit(self.data_directory.as_ref().map(path_buf_lit).as_ref()); let data_store_identifier = opt_vec_lit(self.data_store_identifier, identity); let scroll_bar_style = &self.scroll_bar_style; + let limit_navigations_to_app_bound_domains = self.limit_navigations_to_app_bound_domains; let activity_name = opt_lit(self.activity_name.as_ref()); let created_by_activity_name = opt_lit(self.created_by_activity_name.as_ref()); let requested_by_scene_identifier = opt_lit(self.requested_by_scene_identifier.as_ref()); @@ -4016,6 +4076,7 @@ mod build { data_directory, data_store_identifier, scroll_bar_style, + limit_navigations_to_app_bound_domains, activity_name, created_by_activity_name, requested_by_scene_identifier, diff --git a/crates/tauri/Cargo.toml b/crates/tauri/Cargo.toml index 3f1dd5f82e2d..8b9d862db938 100644 --- a/crates/tauri/Cargo.toml +++ b/crates/tauri/Cargo.toml @@ -93,13 +93,15 @@ 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 +208,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/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/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index 27f2131dba59..1b47f1b380de 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -536,7 +536,7 @@ impl AppHandle { pub fn plugin_boxed(&self, mut plugin: Box>) -> crate::Result<()> { let mut store = self.manager().plugins.lock().unwrap(); store.initialize(&mut plugin, self, &self.config().plugins)?; - store.register(plugin); + store.register_initialized(plugin); Ok(()) } @@ -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 || unsafe { - 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() } } @@ -1263,11 +1268,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. @@ -2090,7 +2093,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 /// @@ -2380,6 +2383,8 @@ tauri::Builder::default() ran_setup: false, }; + app.register_core_plugins()?; + #[cfg(desktop)] if let Some(menu) = self.menu { let menu = menu(&app.handle)?; @@ -2395,8 +2400,6 @@ tauri::Builder::default() app.manager.menu.menu_lock().replace(menu); } - app.register_core_plugins()?; - let env = Env::default(); app.manage(env); 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/ipc/protocol.rs b/crates/tauri/src/ipc/protocol.rs index 455b1d01a42c..66f9abe1a804 100644 --- a/crates/tauri/src/ipc/protocol.rs +++ b/crates/tauri/src/ipc/protocol.rs @@ -328,12 +328,10 @@ fn handle_ipc_message(request: Request, manager: &AppManager js: crate::Result, error: CallbackFn, ) { - let eval_js = match js { - Ok(js) => js, - Err(e) => crate::ipc::format_callback::format(error, &e.to_string()) - .expect("unable to serialize response error string to json"), - }; - + let eval_js = js.unwrap_or_else(|e| { + crate::ipc::format_callback::format(error, &e.to_string()) + .expect("unable to serialize response error string to json") + }); let _ = webview.eval(eval_js); } diff --git a/crates/tauri/src/manager/menu.rs b/crates/tauri/src/manager/menu.rs index 2695dd115a3a..182a8d0aef67 100644 --- a/crates/tauri/src/manager/menu.rs +++ b/crates/tauri/src/manager/menu.rs @@ -56,20 +56,18 @@ impl MenuManager { window_menu: Option<&crate::window::WindowMenu>, #[allow(unused)] theme: Option, ) -> Option)> { - { - if let Some(menu) = window_menu { - self - .menus_stash_lock() - .insert(menu.menu.id().clone(), menu.menu.clone()); - } - } + let window_menu = window_menu?; + + self + .menus_stash_lock() + .insert(window_menu.menu.id().clone(), window_menu.menu.clone()); #[cfg(target_os = "macos")] return None; #[cfg_attr(target_os = "macos", allow(unused_variables, unreachable_code))] - if let Some(menu) = &window_menu { - let menu = menu.menu.clone(); + { + let menu = window_menu.menu.clone(); Some(move |raw: tauri_runtime::window::RawWindow<'_>| { #[cfg(target_os = "windows")] { @@ -89,8 +87,6 @@ impl MenuManager { .inner() .init_for_gtk_window(raw.gtk_window, raw.default_vbox); }) - } else { - None } } diff --git a/crates/tauri/src/manager/mod.rs b/crates/tauri/src/manager/mod.rs index ccc5ffbaf896..9a61be604713 100644 --- a/crates/tauri/src/manager/mod.rs +++ b/crates/tauri/src/manager/mod.rs @@ -472,12 +472,15 @@ impl AppManager { (self.webview.invoke_handler)(invoke) } - pub fn extend_api(&self, plugin: &str, invoke: Invoke) -> bool { + /// Runs the plugin [`crate::plugin::Plugin::extend_api`] hook if it exists. Returns whether the invoke message was handled or not. + /// + /// The message is not handled when the plugin exists **and** the command does not. + pub fn run_plugin_invoke_handler(&self, plugin: &str, invoke: Invoke) -> bool { self .plugins .lock() .expect("poisoned plugin store") - .extend_api(plugin, invoke) + .run_invoke_handler(plugin, invoke) } pub fn initialize_plugins(&self, app: &AppHandle) -> crate::Result<()> { diff --git a/crates/tauri/src/manager/tray.rs b/crates/tauri/src/manager/tray.rs index a3da8715a8a0..7ad709f5adcd 100644 --- a/crates/tauri/src/manager/tray.rs +++ b/crates/tauri/src/manager/tray.rs @@ -16,6 +16,8 @@ use crate::{ }; pub struct TrayManager { + /// icon passed in from [`tauri_utils::config::TrayIconConfig::icon_path`], + /// used when creating tray icons from the configs. pub(crate) icon: Option>, /// Tray icons pub(crate) icons: Mutex>, diff --git a/crates/tauri/src/menu/mod.rs b/crates/tauri/src/menu/mod.rs index fa4abff2a575..51d377fbf35c 100644 --- a/crates/tauri/src/menu/mod.rs +++ b/crates/tauri/src/menu/mod.rs @@ -13,15 +13,24 @@ mod normal; pub(crate) mod plugin; mod predefined; mod submenu; -use std::{mem::ManuallyDrop, sync::Arc}; +use std::{ + mem::ManuallyDrop, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, +}; pub use builders::*; pub use menu::{HELP_SUBMENU_ID, WINDOW_SUBMENU_ID}; use serde::{Deserialize, Serialize}; +use crate::menu::plugin::remove_menu_channel; use crate::{image::Image, AppHandle, Runtime}; pub use muda::MenuId; +static MENU_CHANNEL_OWNER: AtomicU64 = AtomicU64::new(1); + macro_rules! run_item_main_thread { ($self:ident, $ex:expr) => {{ use std::sync::mpsc::channel; @@ -73,6 +82,7 @@ macro_rules! gen_wrappers { // This [`ManuallyDrop`] is used to [`ManuallyDrop::take`] in [`Self::drop`] to drop it on main thread inner: ManuallyDrop<::muda::$type>, app_handle: $crate::AppHandle, + channel_owner: u64, } impl $inner { @@ -80,6 +90,7 @@ macro_rules! gen_wrappers { Self { inner: ManuallyDrop::new(menu), app_handle, + channel_owner: MENU_CHANNEL_OWNER.fetch_add(1, Ordering::Relaxed), } } } @@ -94,6 +105,7 @@ macro_rules! gen_wrappers { impl Drop for $inner { fn drop(&mut self) { + remove_menu_channel(&self.app_handle, self.inner.id(), self.channel_owner); // SAFETY: we will not access `self.inner` after this let inner = unsafe { ManuallyDrop::take(&mut self.inner) }; // SAFETY: inner was created on main thread and is being dropped on main thread @@ -119,6 +131,12 @@ macro_rules! gen_wrappers { } } + impl $type { + pub(crate) fn channel_owner(&self) -> u64 { + self.0.channel_owner + } + } + $( impl $crate::menu::sealed::IsMenuItemBase for $type { fn inner_muda(&self) -> &dyn muda::IsMenuItem { diff --git a/crates/tauri/src/menu/plugin.rs b/crates/tauri/src/menu/plugin.rs index 7f6741d00315..7fa3a3f277be 100644 --- a/crates/tauri/src/menu/plugin.rs +++ b/crates/tauri/src/menu/plugin.rs @@ -161,12 +161,13 @@ impl CheckMenuItemPayload { if let Some(handler) = self.handler { let handler = handler.channel_on(webview.clone()); + let owner = item.channel_owner(); webview .state::() .0 .lock() .unwrap() - .insert(item.id().clone(), handler); + .insert(item.id().clone(), (owner, handler)); } Ok(item) @@ -217,12 +218,13 @@ impl IconMenuItemPayload { if let Some(handler) = self.handler { let handler = handler.channel_on(webview.clone()); + let owner = item.channel_owner(); webview .state::() .0 .lock() .unwrap() - .insert(item.id().clone(), handler); + .insert(item.id().clone(), (owner, handler)); } Ok(item) @@ -256,12 +258,13 @@ impl MenuItemPayload { if let Some(handler) = self.handler { let handler = handler.channel_on(webview.clone()); + let owner = item.channel_owner(); webview .state::() .0 .lock() .unwrap() - .insert(item.id().clone(), handler); + .insert(item.id().clone(), (owner, handler)); } Ok(item) @@ -359,7 +362,6 @@ struct NewOptions { #[command(root = "crate")] fn new( - app: Webview, webview: Webview, kind: ItemKind, options: Option, @@ -367,11 +369,11 @@ fn new( handler: Channel, ) -> crate::Result<(ResourceId, MenuId)> { let options = options.unwrap_or_default(); - let mut resources_table = app.resources_table(); + let mut resources_table = webview.resources_table(); - let (rid, id) = match kind { + let (rid, id, owner) = match kind { ItemKind::Menu => { - let mut builder = MenuBuilder::new(&app); + let mut builder = MenuBuilder::new(&webview); if let Some(id) = options.id { builder = builder.id(id); } @@ -382,9 +384,10 @@ fn new( } let menu = builder.build()?; let id = menu.id().clone(); + let owner = menu.channel_owner(); let rid = resources_table.add(menu); - (rid, id) + (rid, id, owner) } ItemKind::Submenu => { @@ -397,9 +400,10 @@ fn new( } .create_item(&webview, &resources_table)?; let id = submenu.id().clone(); + let owner = submenu.channel_owner(); let rid = resources_table.add(submenu); - (rid, id) + (rid, id, owner) } ItemKind::MenuItem => { @@ -413,8 +417,9 @@ fn new( } .create_item(&webview)?; let id = item.id().clone(); + let owner = item.channel_owner(); let rid = resources_table.add(item); - (rid, id) + (rid, id, owner) } ItemKind::Predefined => { @@ -424,8 +429,9 @@ fn new( } .create_item(&webview, &resources_table)?; let id = item.id().clone(); + let owner = item.channel_owner(); let rid = resources_table.add(item); - (rid, id) + (rid, id, owner) } ItemKind::Check => { @@ -440,8 +446,9 @@ fn new( } .create_item(&webview)?; let id = item.id().clone(); + let owner = item.channel_owner(); let rid = resources_table.add(item); - (rid, id) + (rid, id, owner) } ItemKind::Icon => { @@ -456,12 +463,17 @@ fn new( } .create_item(&webview, &resources_table)?; let id = item.id().clone(); + let owner = item.channel_owner(); let rid = resources_table.add(item); - (rid, id) + (rid, id, owner) } }; - channels.0.lock().unwrap().insert(id.clone(), handler); + channels + .0 + .lock() + .unwrap() + .insert(id.clone(), (owner, handler)); Ok((rid, id)) } @@ -886,7 +898,27 @@ fn set_icon( ) } -struct MenuChannels(Mutex>>); +struct MenuChannels(Mutex)>>); + +fn remove_menu_channel_if_owner( + channels: &mut HashMap)>, + id: &MenuId, + owner: u64, +) { + if channels + .get(id) + .is_some_and(|(registered_owner, _)| *registered_owner == owner) + { + channels.remove(id); + } +} + +// Called in `Menu`'s `Drop` to clean up the event handlers +pub(crate) fn remove_menu_channel(app: &AppHandle, id: &MenuId, owner: u64) { + let menu_channels = app.state::(); + let mut channels = menu_channels.0.lock().unwrap(); + remove_menu_channel_if_owner(&mut channels, id, owner); +} pub(crate) fn init() -> TauriPlugin { Builder::new("menu") @@ -896,7 +928,15 @@ pub(crate) fn init() -> TauriPlugin { }) .on_event(|app, e| { if let RunEvent::MenuEvent(e) = e { - if let Some(channel) = app.state::().0.lock().unwrap().get(&e.id) { + // Cloning the channel out in case the menu gets dropped during the channel send through `channel_interceptor` + let channel = app + .state::() + .0 + .lock() + .unwrap() + .get(&e.id) + .map(|(_, channel)| channel.clone()); + if let Some(channel) = channel { let _ = channel.send(e.id.clone()); } } @@ -928,3 +968,20 @@ pub(crate) fn init() -> TauriPlugin { ]) .build() } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn stale_owner_cannot_remove_replacement_channel() { + let id = MenuId::new("shared"); + let channel = Channel::::new(|_| Ok(())); + let channel_id = channel.id(); + let mut channels = HashMap::from([(id.clone(), (2, channel))]); + + remove_menu_channel_if_owner(&mut channels, &id, 1); + + assert_eq!(channels.get(&id).unwrap().1.id(), channel_id); + } +} diff --git a/crates/tauri/src/plugin.rs b/crates/tauri/src/plugin.rs index 3a22de7bc700..153a6ab03900 100644 --- a/crates/tauri/src/plugin.rs +++ b/crates/tauri/src/plugin.rs @@ -24,7 +24,7 @@ use url::Url; use std::{ borrow::Cow, - collections::HashMap, + collections::{HashMap, HashSet}, fmt::{self, Debug}, sync::Arc, }; @@ -104,6 +104,7 @@ pub trait Plugin: Send { #[allow(unused_variables)] fn on_event(&mut self, app: &AppHandle, event: &RunEvent) {} + // TODO: Change this to `run_invoke_handler` in v3 /// Extend commands to [`crate::Builder::invoke_handler`]. #[allow(unused_variables)] fn extend_api(&mut self, invoke: Invoke) -> bool { @@ -596,7 +597,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 /// @@ -856,6 +857,7 @@ impl Plugin for TauriPlugin { #[default_runtime(crate::Wry, wry)] pub(crate) struct PluginStore { store: Vec>>, + initialized: HashSet<&'static str>, } impl fmt::Debug for PluginStore { @@ -869,7 +871,10 @@ impl fmt::Debug for PluginStore { impl Default for PluginStore { fn default() -> Self { - Self { store: Vec::new() } + Self { + store: Vec::new(), + initialized: HashSet::new(), + } } } @@ -878,18 +883,32 @@ impl PluginStore { /// /// Returns `true` if a plugin with the same name is already in the store. pub fn register(&mut self, plugin: Box>) -> bool { + let name = plugin.name(); let len = self.store.len(); - self.store.retain(|p| p.name() != plugin.name()); + self.store.retain(|p| p.name() != name); let result = len != self.store.len(); + self.initialized.remove(name); self.store.push(plugin); result } + /// Adds an already initialized plugin to the store. + pub(crate) fn register_initialized(&mut self, plugin: Box>) -> bool { + let name = plugin.name(); + let replaced = self.register(plugin); + self.initialized.insert(name); + replaced + } + /// Removes the plugin with the given name from the store. pub fn unregister(&mut self, plugin: &str) -> bool { let len = self.store.len(); self.store.retain(|p| p.name() != plugin); - len != self.store.len() + let removed = len != self.store.len(); + if removed { + self.initialized.remove(plugin); + } + removed } /// Initializes the given plugin. @@ -908,10 +927,15 @@ impl PluginStore { app: &AppHandle, config: &PluginConfig, ) -> crate::Result<()> { - self - .store - .iter_mut() - .try_for_each(|plugin| initialize(plugin, app, config)) + for plugin in &mut self.store { + let name = plugin.name(); + if self.initialized.contains(name) { + continue; + } + initialize(plugin, app, config)?; + self.initialized.insert(name); + } + Ok(()) } /// Generates an initialization script from all plugins in the store. @@ -979,10 +1003,10 @@ impl PluginStore { .for_each(|plugin| plugin.on_event(app, event)) } - /// Runs the plugin `extend_api` hook if it exists. Returns whether the invoke message was handled or not. + /// Runs the plugin [`Plugin::extend_api`] hook if it exists. Returns whether the invoke message was handled or not. /// /// The message is not handled when the plugin exists **and** the command does not. - pub(crate) fn extend_api(&mut self, plugin: &str, invoke: Invoke) -> bool { + pub(crate) fn run_invoke_handler(&mut self, plugin: &str, invoke: Invoke) -> bool { for p in self.store.iter_mut() { if p.name() == plugin { #[cfg(feature = "tracing")] @@ -1009,6 +1033,51 @@ fn initialize( .map_err(|e| Error::PluginInitialization(plugin.name().to_string(), e.to_string())) } +#[cfg(test)] +mod tests { + use super::*; + use std::sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, + }; + + struct CountingPlugin(Arc); + + impl Plugin for CountingPlugin { + fn name(&self) -> &'static str { + "counting" + } + + fn initialize( + &mut self, + _app: &AppHandle, + _config: JsonValue, + ) -> Result<(), Box> { + self.0.fetch_add(1, Ordering::SeqCst); + Ok(()) + } + } + + #[test] + fn initialize_all_skips_plugins_already_initialized_at_registration() { + let app = crate::test::mock_app(); + let count = Arc::new(AtomicUsize::new(0)); + let mut plugin: Box> = + Box::new(CountingPlugin(count.clone())); + let mut store = PluginStore::default(); + + store + .initialize(&mut plugin, app.handle(), &app.config().plugins) + .unwrap(); + store.register_initialized(plugin); + store + .initialize_all(app.handle(), &app.config().plugins) + .unwrap(); + + assert_eq!(count.load(Ordering::SeqCst), 1); + } +} + /// Permission state. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[cfg_attr(feature = "specta", derive(specta::Type))] diff --git a/crates/tauri/src/test/mock_runtime.rs b/crates/tauri/src/test/mock_runtime.rs index a1f4c88745c9..29505fd573b6 100644 --- a/crates/tauri/src/test/mock_runtime.rs +++ b/crates/tauri/src/test/mock_runtime.rs @@ -503,7 +503,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..9b4d9175eca6 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -57,12 +57,12 @@ use std::{ pub(crate) type WebResourceRequestHandler = dyn Fn(http::Request>, &mut http::Response>) + Send + Sync; -pub(crate) type NavigationHandler = dyn Fn(&Url) -> bool + Send; +pub(crate) type NavigationHandler = dyn Fn(&Url) -> bool + Send + Sync; pub(crate) type NewWindowHandler = dyn Fn(Url, NewWindowFeatures) -> NewWindowResponse + Send; pub(crate) type UriSchemeProtocolHandler = Box>, UriSchemeResponder) + Send + Sync>; pub(crate) type OnPageLoad = dyn Fn(Webview, PageLoadPayload<'_>) + Send + Sync + 'static; -pub(crate) type OnDocumentTitleChanged = dyn Fn(Webview, String) + Send + 'static; +pub(crate) type OnDocumentTitleChanged = dyn Fn(Webview, String) + Send + Sync + 'static; pub(crate) type DownloadHandler = dyn Fn(Webview, DownloadEvent<'_>) -> bool + Send + Sync; #[derive(Clone, Serialize)] @@ -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() } @@ -525,7 +525,7 @@ tauri::Builder::default() ``` "#### )] - pub fn on_navigation bool + Send + 'static>(mut self, f: F) -> Self { + pub fn on_navigation bool + Send + Sync + 'static>(mut self, f: F) -> Self { self.navigation_handler.replace(Box::new(f)); self } @@ -591,7 +591,7 @@ tauri::Builder::default() } /// Defines a closure to be executed when document title change. - pub fn on_document_title_changed, String) + Send + 'static>( + pub fn on_document_title_changed, String) + Send + Sync + 'static>( mut self, f: F, ) -> Self { @@ -968,7 +968,9 @@ fn main() { self } - /// Disables the drag and drop handler. This is required to use HTML5 drag and drop APIs on the frontend on Windows. + /// Disables the drag and drop handler used internally to generate [`DragDropEvent`](crate::DragDropEvent)s. + /// + /// This is required to use HTML5 drag and drop APIs on the frontend on Windows since we replace the drag drop handler of WebView2. #[must_use] pub fn disable_drag_drop_handler(mut self) -> Self { self.webview_attributes.drag_drop_handler_enabled = false; @@ -1219,6 +1221,62 @@ fn main() { .allow_link_preview(allow_link_preview); self } + /// Whether to limit navigations to App-Bound Domains. This is necessary to + /// enable Service Workers on iOS according to + /// [StackOverflow](https://stackoverflow.com/questions/49673399/service-workers-unavailable-in-wkwebview-in-ios-11-3/64155509#64155509). + /// + /// Default is false. + /// + /// Note: If you pass in `true` make sure to add localhost and any [`registrable + /// domains`](https://developer.mozilla.org/en-US/docs/Glossary/Registrable_domain) + /// used in this webview to tauri-src/Info.ios.plist: + /// + /// ```xml + /// + /// + /// WKAppBoundDomains + /// + /// localhost + /// aregistrabledomain.example + /// + /// + /// + /// ``` + /// + /// You must add `localhost` if any webview with this set to true opens a + /// local webpage, makes any localhost calls, or uses the isolation pattern + /// because Tauri uses the `localhost` domain for hosting the application + /// webpage, the IPC protocol, and the isolation pattern's iframe. + /// + /// Requests served through custom uri schemes are allowed so long as they use + /// a registrable domain specified in the `WKAppBoundDomains` array for all the + /// requests from the app, including requests for the `localhost` domain. + /// + /// In theory, you can whitelist an entire uri scheme by including the + /// protocol name followed by a colon. For example, to allow all requests + /// using a custom "stream" uri scheme (see [this tauri + /// example](https://github.com/tauri-apps/tauri/blob/dev/examples/streaming/main.rs)), + /// you could add `stream:` to the AppBoundDomains array. That said, I'm not + /// sure whether Apple would let your app through app review if you do + /// whitelist an entire protocol because this feature is not mentioned in + /// [their blog post on App-Bound + /// Domains](https://webkit.org/blog/10882/app-bound-domains/). + /// + /// See https://webkit.org/blog/10882/app-bound-domains/ and + /// https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/limitsnavigationstoappbounddomains + /// for the official documentation on App-Bound Domains. + /// + /// ## Platform-specific + /// + /// - **iOS**: Supported since version 14.0+. + /// - **Linux / Windows / Android / MacOS:** Unsupported. + #[must_use] + pub fn limit_navigations_to_app_bound_domains(mut self, limit_navigations: bool) -> Self { + self.webview_attributes = self + .webview_attributes + .limit_navigations_to_app_bound_domains(limit_navigations); + self + } /// Allows overriding the keyboard accessory view on iOS. /// Returning `None` effectively removes the view. @@ -1273,7 +1331,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 +1667,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 +1684,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.); } @@ -1860,7 +1918,7 @@ tauri::Builder::default() let message = invoke.message.clone(); #[allow(unused_mut)] - let mut handled = manager.extend_api(plugin, invoke); + let mut handled = manager.run_plugin_invoke_handler(plugin, invoke); #[cfg(mobile)] { diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs index 1f101de350ec..d841d954d887 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -263,7 +263,7 @@ impl<'a, R: Runtime, M: Manager> WebviewWindowBuilder<'a, R, M> { /// Ok(()) /// }); /// ``` - pub fn on_navigation bool + Send + 'static>(mut self, f: F) -> Self { + pub fn on_navigation bool + Send + Sync + 'static>(mut self, f: F) -> Self { self.webview_builder = self.webview_builder.on_navigation(f); self } @@ -323,7 +323,7 @@ impl<'a, R: Runtime, M: Manager> WebviewWindowBuilder<'a, R, M> { /// Defines a closure to be executed when the document title changes. /// /// Note that it may run before or after the navigation event. - pub fn on_document_title_changed, String) + Send + 'static>( + pub fn on_document_title_changed, String) + Send + Sync + 'static>( mut self, f: F, ) -> Self { @@ -717,12 +717,14 @@ 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 } - /// Enables or disables drag and drop support. + /// Enables or disables drag and drop support of this window. + /// + /// Note: this is a different config from [`Self::disable_drag_drop_handler`] #[cfg(windows)] #[must_use] pub fn drag_and_drop(mut self, enabled: bool) -> Self { @@ -1036,7 +1038,9 @@ impl> WebviewWindowBuilder<'_, R, M> { self } - /// Disables the drag and drop handler. This is required to use HTML5 drag and drop APIs on the frontend on Windows. + /// Disables the webview drag and drop handler used internally to generate [`DragDropEvent`](crate::DragDropEvent)s. + /// + /// This is required to use HTML5 drag and drop APIs on the frontend on Windows since we replace the drag drop handler of WebView2. #[must_use] pub fn disable_drag_drop_handler(mut self) -> Self { self.webview_builder = self.webview_builder.disable_drag_drop_handler(); @@ -1318,6 +1322,62 @@ impl> WebviewWindowBuilder<'_, R, M> { self } + /// Whether to limit navigations to App-Bound Domains. This is necessary to + /// enable Service Workers on iOS according to + /// [StackOverflow](https://stackoverflow.com/questions/49673399/service-workers-unavailable-in-wkwebview-in-ios-11-3/64155509#64155509). + /// + /// Default is false. + /// + /// Note: If you pass in `true` make sure to add localhost and any [`registrable + /// domains`](https://developer.mozilla.org/en-US/docs/Glossary/Registrable_domain) + /// used in this webview to tauri-src/Info.ios.plist: + /// + /// ```xml + /// + /// + /// WKAppBoundDomains + /// + /// localhost + /// aregistrabledomain.example + /// + /// + /// + /// ``` + /// + /// You must add `localhost` if any webview with this set to true opens a + /// local webpage, makes any localhost calls, or uses the isolation pattern + /// because Tauri uses the `localhost` domain for hosting the application + /// webpage, the IPC protocol, and the isolation pattern's iframe. + /// + /// Requests served through custom uri schemes are allowed so long as they use + /// a registrable domain specified in the `WKAppBoundDomains` array for all the + /// requests from the app, including requests for the `localhost` domain. + /// + /// In theory, you can whitelist an entire uri scheme by including the + /// protocol name followed by a colon. For example, to allow all requests + /// using a custom "stream" uri scheme (see [this tauri + /// example](https://github.com/tauri-apps/tauri/blob/dev/examples/streaming/main.rs)), + /// you could add `stream:` to the AppBoundDomains array. That said, I'm not + /// sure whether Apple would let your app through app review if you do + /// whitelist an entire protocol because this feature is not mentioned in + /// [their blog post on App-Bound + /// Domains](https://webkit.org/blog/10882/app-bound-domains/). + /// + /// See https://webkit.org/blog/10882/app-bound-domains/ and + /// https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/limitsnavigationstoappbounddomains + /// for the official documentation on App-Bound Domains. + /// + /// ## Platform-specific + /// + /// - **iOS**: Supported since version 14.0+. + /// - **Linux / Windows / Android / MacOS:** Unsupported. + pub fn limit_navigations_to_app_bound_domains(mut self, limit_navigations: bool) -> Self { + self.webview_builder = self + .webview_builder + .limit_navigations_to_app_bound_domains(limit_navigations); + self + } + /// Set the environment for the webview. /// Useful if you need to share the same environment, for instance when using the [`Self::on_new_window`]. #[cfg(all(feature = "wry", windows))] @@ -1341,7 +1401,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 } @@ -2325,7 +2385,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 @@ -2340,9 +2400,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..5717ac1f4ab7 100644 --- a/crates/tauri/src/window/mod.rs +++ b/crates/tauri/src/window/mod.rs @@ -355,7 +355,7 @@ tauri::Builder::default() /// Creates a new window with an optional webview. fn build_internal( - // mutable on Android + // mutable on mobile #[allow(unused_mut)] mut self, webview: Option>, ) -> crate::Result> { @@ -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/examples/api/index.html b/examples/api/index.html index 010944d8e277..98132dfd03c5 100644 --- a/examples/api/index.html +++ b/examples/api/index.html @@ -1,13 +1,14 @@ - + + API Example App
- + 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/package.json b/examples/api/package.json index c0f15c0f1bac..0ba26f005ea4 100644 --- a/examples/api/package.json +++ b/examples/api/package.json @@ -15,10 +15,12 @@ "devDependencies": { "@iconify-json/codicon": "^1.2.49", "@iconify-json/ph": "^1.2.2", - "@sveltejs/vite-plugin-svelte": "^7.0.0", - "@unocss/extractor-svelte": "^66.6.6", - "svelte": "^5.55.7", - "unocss": "^66.6.6", - "vite": "^8.0.16" + "@sveltejs/vite-plugin-svelte": "^7.2.0", + "@types/sortablejs": "^1.15.9", + "@unocss/extractor-svelte": "^66.7.5", + "sortablejs": "^1.15.7", + "svelte": "^5.56.4", + "unocss": "^66.7.5", + "vite": "^8.1.4" } } diff --git a/examples/api/src-tauri/src/lib.rs b/examples/api/src-tauri/src/lib.rs index b569f25cb550..876978fdaecd 100644 --- a/examples/api/src-tauri/src/lib.rs +++ b/examples/api/src-tauri/src/lib.rs @@ -67,6 +67,7 @@ pub fn run_app) + Send + 'static>( #[allow(unused_mut)] let mut window_builder = WebviewWindowBuilder::new(app, "main", WebviewUrl::default()) + .disable_drag_drop_handler() .on_document_title_changed(|_window, title| { println!("document title changed: {title}"); }); diff --git a/examples/api/src-tauri/src/tray.rs b/examples/api/src-tauri/src/tray.rs index 8e0d4e9541ae..ada914a2e092 100644 --- a/examples/api/src-tauri/src/tray.rs +++ b/examples/api/src-tauri/src/tray.rs @@ -42,7 +42,7 @@ pub fn create_tray(app: &tauri::AppHandle) -> tauri::Result<()> { let is_menu1 = AtomicBool::new(true); - let _ = TrayIconBuilder::with_id("tray-1") + let _tray = TrayIconBuilder::with_id("tray-1") .tooltip("Tauri") .icon(app.default_window_icon().unwrap().clone()) .menu(&menu1) @@ -121,7 +121,7 @@ pub fn create_tray(app: &tauri::AppHandle) -> tauri::Result<()> { } } }) - .build(app); + .build(app)?; Ok(()) } 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 } } diff --git a/examples/api/src/App.svelte b/examples/api/src/App.svelte index 7d14871a7944..db719567d00f 100644 --- a/examples/api/src/App.svelte +++ b/examples/api/src/App.svelte @@ -1,4 +1,10 @@ - + +
diff --git a/examples/api/src/app.css b/examples/api/src/app.css index f2d03802efa6..ea8af2b85202 100644 --- a/examples/api/src/app.css +++ b/examples/api/src/app.css @@ -2,6 +2,13 @@ line-height: 1.5; } +:root.dark { + color-scheme: dark; +} +:root.light { + color-scheme: light; +} + input, select { min-width: 0; @@ -42,9 +49,33 @@ code.code-block { width: 18.75rem; } -@media screen and (max-width: 640px) { +@media screen and (width < 640px) { #sidebar { --translate-x: -18.75rem; + transform: translateX(var(--translate-x)); } } + +#sidebar, +main { + padding-top: calc(env(safe-area-inset-top) + 1rem); +} + +#sidebar { + padding-left: calc(env(safe-area-inset-left) + 0.5rem); +} + +main { + padding-right: env(safe-area-inset-right); +} + +#sidebarToggle { + margin-top: calc(env(safe-area-inset-top) + 0.5rem); + margin-left: calc(env(safe-area-inset-left) + 0.5rem); +} + +#sidebar, +#console { + padding-bottom: calc(env(safe-area-inset-bottom) + 1.5rem); +} diff --git a/examples/api/src/components/MenuBuilder.svelte b/examples/api/src/components/MenuBuilder.svelte index 7e824bb1d712..e0a614328e41 100644 --- a/examples/api/src/components/MenuBuilder.svelte +++ b/examples/api/src/components/MenuBuilder.svelte @@ -1,45 +1,293 @@ - + + -
- + 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) + } -
- {#each items as item} -
-
-

{itemToString(item)}

+ newItem.menu = await create(newItem) + + 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

+
+ + + +
+
+
+

Predefined

+
+ {#each predefinedOptions as predefinedOption} + + {/each}
- {/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 0f93436978a4..000000000000 --- a/examples/api/src/components/MenuItemBuilder.svelte +++ /dev/null @@ -1,150 +0,0 @@ - - -
-
- {#each itemKinds as itemKind, 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} -
- - -
- {/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/main.js b/examples/api/src/main.ts similarity index 87% rename from examples/api/src/main.js rename to examples/api/src/main.ts index 03e3ef7dd7c4..14633e36eb85 100644 --- a/examples/api/src/main.js +++ b/examples/api/src/main.ts @@ -8,7 +8,7 @@ import App from './App.svelte' import { mount } from 'svelte' const app = mount(App, { - target: document.querySelector('#app') + target: document.querySelector('#app')! }) export default app diff --git a/examples/api/src/views/App.svelte b/examples/api/src/views/App.svelte index 25604c72a73e..13fe5662b534 100644 --- a/examples/api/src/views/App.svelte +++ b/examples/api/src/views/App.svelte @@ -1,9 +1,8 @@ - -
+
- 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..aa9cef7ed69d 100644 --- a/examples/api/src/views/Menu.svelte +++ b/examples/api/src/views/Menu.svelte @@ -1,86 +1,126 @@ - -
- -
+
+ { + 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) + } + }} + /> +
+ + - -
diff --git a/examples/api/src/views/Tray.svelte b/examples/api/src/views/Tray.svelte index 9636f00c6806..4c658f8ca88b 100644 --- a/examples/api/src/views/Tray.svelte +++ b/examples/api/src/views/Tray.svelte @@ -1,79 +1,135 @@ - -
-
- +
+ { + if (item.menu) { + await menu?.append(item.menu) + } + }} + onItemRemoved={async (item) => { + if (item.menu) { + await menu?.remove(item.menu) + } + }} + onItemMoved={(item, toIndex) => { + if (menu) { + reorderMenuItems(menu, item, toIndex) + } + }} + /> - +
+
+ - -
+ -
- + - -
+ -
- -
+ +
-
- +
+ {#if tray} + + {:else} + + {/if} +
diff --git a/examples/api/src/views/WebRTC.svelte b/examples/api/src/views/WebRTC.svelte index 8dfaa5f16da9..f1be6b1898c7 100644 --- a/examples/api/src/views/WebRTC.svelte +++ b/examples/api/src/views/WebRTC.svelte @@ -1,26 +1,43 @@ -
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 @@ - -
+
{#if Object.keys(webviewMap).length >= 1}

Selected Window

- {#each Object.keys(webviewMap) as label} @@ -427,7 +438,7 @@
- {#if webviewMap[selectedWebview]} + {#if selectedWebview}

Change Window Icon

@@ -464,7 +475,7 @@ @@ -496,39 +507,74 @@ class="btn" onclick={() => { focusable = !focusable - webviewMap[selectedWebview].setFocusable(!focusable) + selectedWebview.setFocusable(!focusable) }} > Set focusable to {!focusable}
-
+
-
-
+
+
-
+
-
+
-
+
@@ -684,9 +764,14 @@

Cursor

-
+
@@ -702,6 +788,7 @@ type="checkbox" class="checkbox" bind:checked={cursorIgnoreEvents} + onchange={updateCursorIgnoreEvents} /> Ignore events @@ -709,7 +796,11 @@
@@ -793,7 +894,7 @@