diff --git a/.github/workflows/build-cross-image.yml b/.github/workflows/build-cross-image.yml index edc80b1e0..83b40f2be 100644 --- a/.github/workflows/build-cross-image.yml +++ b/.github/workflows/build-cross-image.yml @@ -10,7 +10,7 @@ on: sdk_version: description: 'macOS SDK version' required: true - default: '26.1' + default: '14.5' zig_version: description: 'Zig version' required: true @@ -18,7 +18,17 @@ on: image_version: description: 'Image version tag' required: true - default: '1.0.0' + default: 'latest' + skip_tests: + description: 'Skip cross-compilation tests' + required: false + default: 'false' + type: boolean + push: + branches: + - v3-alpha + paths: + - 'v3/internal/commands/build_assets/docker/Dockerfile.cross' env: REGISTRY: ghcr.io @@ -30,12 +40,17 @@ jobs: permissions: contents: read packages: write + outputs: + image_tag: ${{ steps.vars.outputs.image_version }} steps: - name: Checkout uses: actions/checkout@v4 with: - ref: ${{ inputs.branch }} + ref: ${{ inputs.branch || github.ref }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -47,6 +62,13 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Set build variables + id: vars + run: | + echo "sdk_version=${{ inputs.sdk_version || '14.5' }}" >> $GITHUB_OUTPUT + echo "zig_version=${{ inputs.zig_version || '0.14.0' }}" >> $GITHUB_OUTPUT + echo "image_version=${{ inputs.image_version || 'latest' }}" >> $GITHUB_OUTPUT + - name: Extract metadata id: meta uses: docker/metadata-action@v5 @@ -54,20 +76,348 @@ jobs: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=raw,value=latest - type=raw,value=${{ inputs.image_version }} - type=raw,value=sdk-${{ inputs.sdk_version }} + type=raw,value=${{ steps.vars.outputs.image_version }} + type=raw,value=sdk-${{ steps.vars.outputs.sdk_version }} - name: Build and push uses: docker/build-push-action@v5 with: - context: v3/internal/setupwizard/docker - file: v3/internal/setupwizard/docker/Dockerfile.cross + context: v3/internal/commands/build_assets/docker + file: v3/internal/commands/build_assets/docker/Dockerfile.cross + platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + labels: | + ${{ steps.meta.outputs.labels }} + io.wails.zig.version=${{ steps.vars.outputs.zig_version }} + io.wails.sdk.version=${{ steps.vars.outputs.sdk_version }} build-args: | - ZIG_VERSION=${{ inputs.zig_version }} - MACOS_SDK_VERSION=${{ inputs.sdk_version }} - IMAGE_VERSION=${{ inputs.image_version }} + ZIG_VERSION=${{ steps.vars.outputs.zig_version }} + MACOS_SDK_VERSION=${{ steps.vars.outputs.sdk_version }} cache-from: type=gha cache-to: type=gha,mode=max + + # Test cross-compilation for all platforms + test-cross-compile: + needs: build + if: ${{ inputs.skip_tests != 'true' }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + # Darwin targets (Zig + macOS SDK) - no platform emulation needed + - os: darwin + arch: arm64 + platform: "" + expected_file: "Mach-O 64-bit.*arm64" + - os: darwin + arch: amd64 + platform: "" + expected_file: "Mach-O 64-bit.*x86_64" + # Linux targets (GCC) - need platform to match architecture + - os: linux + arch: amd64 + platform: "linux/amd64" + expected_file: "ELF 64-bit LSB.*x86-64" + - os: linux + arch: arm64 + platform: "linux/arm64" + expected_file: "ELF 64-bit LSB.*ARM aarch64" + # Windows targets (Zig + mingw) - no platform emulation needed + - os: windows + arch: amd64 + platform: "" + expected_file: "PE32\\+ executable.*x86-64" + - os: windows + arch: arm64 + platform: "" + expected_file: "PE32\\+ executable.*Aarch64" + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ inputs.branch || github.ref }} + + - name: Set up QEMU + if: matrix.platform != '' + uses: docker/setup-qemu-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create test CGO project + run: | + mkdir -p test-project + cd test-project + + # Create a minimal CGO test program + cat > main.go << 'EOF' + package main + + /* + #include + + int add(int a, int b) { + return a + b; + } + */ + import "C" + import "fmt" + + func main() { + result := C.add(1, 2) + fmt.Printf("CGO test: 1 + 2 = %d\n", result) + } + EOF + + cat > go.mod << 'EOF' + module test-cgo + + go 1.21 + EOF + + - name: Build ${{ matrix.os }}/${{ matrix.arch }} (CGO) + run: | + cd test-project + PLATFORM_FLAG="" + if [ -n "${{ matrix.platform }}" ]; then + PLATFORM_FLAG="--platform ${{ matrix.platform }}" + fi + + docker run --rm $PLATFORM_FLAG \ + -v "$(pwd):/app" \ + -e APP_NAME="test-cgo" \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag || 'latest' }} \ + ${{ matrix.os }} ${{ matrix.arch }} + + - name: Verify binary format + run: | + cd test-project/bin + ls -la + + # Find the built binary + if [ "${{ matrix.os }}" = "windows" ]; then + BINARY=$(ls test-cgo-${{ matrix.os }}-${{ matrix.arch }}.exe 2>/dev/null || ls *.exe | head -1) + else + BINARY=$(ls test-cgo-${{ matrix.os }}-${{ matrix.arch }} 2>/dev/null || ls test-cgo* | grep -v '.exe' | head -1) + fi + + echo "Binary: $BINARY" + FILE_OUTPUT=$(file "$BINARY") + echo "File output: $FILE_OUTPUT" + + # Verify the binary format matches expected + if echo "$FILE_OUTPUT" | grep -qE "${{ matrix.expected_file }}"; then + echo "✅ Binary format verified: ${{ matrix.os }}/${{ matrix.arch }}" + else + echo "❌ Binary format mismatch!" + echo "Expected pattern: ${{ matrix.expected_file }}" + echo "Got: $FILE_OUTPUT" + exit 1 + fi + + - name: Check library dependencies (Linux only) + if: matrix.os == 'linux' + run: | + cd test-project/bin + BINARY=$(ls test-cgo-${{ matrix.os }}-${{ matrix.arch }} 2>/dev/null || ls test-cgo* | grep -v '.exe' | head -1) + + echo "## Library Dependencies for $BINARY" + echo "" + + # Use readelf to show dynamic dependencies + echo "### NEEDED libraries:" + readelf -d "$BINARY" | grep NEEDED || echo "No dynamic dependencies (statically linked)" + + # Verify expected libraries are linked + echo "" + echo "### Verifying required libraries..." + NEEDED=$(readelf -d "$BINARY" | grep NEEDED) + + MISSING="" + for lib in libwebkit2gtk-4.1.so libgtk-3.so libglib-2.0.so libc.so; do + if echo "$NEEDED" | grep -q "$lib"; then + echo "✅ $lib" + else + echo "❌ $lib MISSING" + MISSING="$MISSING $lib" + fi + done + + if [ -n "$MISSING" ]; then + echo "" + echo "ERROR: Missing required libraries:$MISSING" + exit 1 + fi + + # Test non-CGO builds (pure Go cross-compilation) + test-non-cgo: + needs: build + if: ${{ inputs.skip_tests != 'true' }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - os: darwin + arch: arm64 + expected_file: "Mach-O 64-bit.*arm64" + - os: darwin + arch: amd64 + expected_file: "Mach-O 64-bit.*x86_64" + - os: linux + arch: amd64 + expected_file: "ELF 64-bit LSB" + - os: linux + arch: arm64 + expected_file: "ELF 64-bit LSB.*ARM aarch64" + - os: windows + arch: amd64 + expected_file: "PE32\\+ executable.*x86-64" + - os: windows + arch: arm64 + expected_file: "PE32\\+ executable.*Aarch64" + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ inputs.branch || github.ref }} + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create test non-CGO project + run: | + mkdir -p test-project + cd test-project + + # Create a pure Go test program (no CGO) + cat > main.go << 'EOF' + package main + + import "fmt" + + func main() { + fmt.Println("Pure Go cross-compilation test") + } + EOF + + cat > go.mod << 'EOF' + module test-pure-go + + go 1.21 + EOF + + - name: Build ${{ matrix.os }}/${{ matrix.arch }} (non-CGO) + run: | + cd test-project + + # For non-CGO, we can use any platform since Go handles cross-compilation + # We set CGO_ENABLED=0 to ensure pure Go build + docker run --rm \ + -v "$(pwd):/app" \ + -e APP_NAME="test-pure-go" \ + -e CGO_ENABLED=0 \ + --entrypoint /bin/sh \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag || 'latest' }} \ + -c "GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} go build -o bin/test-pure-go-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.os == 'windows' && '.exe' || '' }} ." + + - name: Verify binary format + run: | + cd test-project/bin + ls -la + + # Find the built binary + if [ "${{ matrix.os }}" = "windows" ]; then + BINARY="test-pure-go-${{ matrix.os }}-${{ matrix.arch }}.exe" + else + BINARY="test-pure-go-${{ matrix.os }}-${{ matrix.arch }}" + fi + + echo "Binary: $BINARY" + FILE_OUTPUT=$(file "$BINARY") + echo "File output: $FILE_OUTPUT" + + # Verify the binary format matches expected + if echo "$FILE_OUTPUT" | grep -qE "${{ matrix.expected_file }}"; then + echo "✅ Binary format verified: ${{ matrix.os }}/${{ matrix.arch }} (non-CGO)" + else + echo "❌ Binary format mismatch!" + echo "Expected pattern: ${{ matrix.expected_file }}" + echo "Got: $FILE_OUTPUT" + exit 1 + fi + + - name: Check library dependencies (Linux only) + if: matrix.os == 'linux' + run: | + cd test-project/bin + BINARY="test-pure-go-${{ matrix.os }}-${{ matrix.arch }}" + + echo "## Library Dependencies for $BINARY (non-CGO)" + echo "" + + # Non-CGO builds should have minimal dependencies (just libc or statically linked) + echo "### NEEDED libraries:" + readelf -d "$BINARY" | grep NEEDED || echo "No dynamic dependencies (statically linked)" + + # Verify NO GTK/WebKit libraries (since CGO is disabled) + NEEDED=$(readelf -d "$BINARY" | grep NEEDED || true) + if echo "$NEEDED" | grep -q "libwebkit\|libgtk"; then + echo "❌ ERROR: Non-CGO binary should not link to GTK/WebKit!" + exit 1 + else + echo "✅ Confirmed: No GTK/WebKit dependencies (expected for non-CGO)" + fi + + # Summary job + test-summary: + needs: [build, test-cross-compile, test-non-cgo] + if: always() && inputs.skip_tests != 'true' + runs-on: ubuntu-latest + steps: + - name: Check test results + run: | + echo "## Cross-Compilation Test Results" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${{ needs.test-cross-compile.result }}" = "success" ]; then + echo "✅ **CGO Tests**: All passed" >> $GITHUB_STEP_SUMMARY + else + echo "❌ **CGO Tests**: Failed" >> $GITHUB_STEP_SUMMARY + fi + + if [ "${{ needs.test-non-cgo.result }}" = "success" ]; then + echo "✅ **Non-CGO Tests**: All passed" >> $GITHUB_STEP_SUMMARY + else + echo "❌ **Non-CGO Tests**: Failed" >> $GITHUB_STEP_SUMMARY + fi + + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Tested Platforms" >> $GITHUB_STEP_SUMMARY + echo "| Platform | Architecture | CGO | Non-CGO |" >> $GITHUB_STEP_SUMMARY + echo "|----------|-------------|-----|---------|" >> $GITHUB_STEP_SUMMARY + echo "| Darwin | arm64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY + echo "| Darwin | amd64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY + echo "| Linux | arm64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY + echo "| Linux | amd64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY + echo "| Windows | arm64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY + echo "| Windows | amd64 | ✅ | ✅ |" >> $GITHUB_STEP_SUMMARY + + # Fail if any test failed + if [ "${{ needs.test-cross-compile.result }}" != "success" ] || [ "${{ needs.test-non-cgo.result }}" != "success" ]; then + echo "" + echo "❌ Some tests failed. Check the individual job logs for details." + exit 1 + fi diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml new file mode 100644 index 000000000..b5e8cfd4d --- /dev/null +++ b/.github/workflows/claude-code-review.yml @@ -0,0 +1,44 @@ +name: Claude Code Review + +on: + pull_request: + types: [opened, synchronize, ready_for_review, reopened] + # Optional: Only run on specific file changes + # paths: + # - "src/**/*.ts" + # - "src/**/*.tsx" + # - "src/**/*.js" + # - "src/**/*.jsx" + +jobs: + claude-review: + # Optional: Filter by PR author + # if: | + # github.event.pull_request.user.login == 'external-contributor' || + # github.event.pull_request.user.login == 'new-developer' || + # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' + + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + issues: read + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code Review + id: claude-review + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' + plugins: 'code-review@claude-code-plugins' + prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}' + # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md + # or https://code.claude.com/docs/en/cli-reference for available options + diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 000000000..d300267f1 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,50 @@ +name: Claude Code + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened, assigned] + pull_request_review: + types: [submitted] + +jobs: + claude: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + issues: read + id-token: write + actions: read # Required for Claude to read CI results on PRs + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + # This is an optional setting that allows Claude to read CI results on PRs + additional_permissions: | + actions: read + + # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it. + # prompt: 'Update the pull request description to include a summary of changes.' + + # Optional: Add claude_args to customize behavior and configuration + # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md + # or https://code.claude.com/docs/en/cli-reference for available options + # claude_args: '--allowed-tools Bash(gh pr:*)' + diff --git a/v2/examples/panic-recovery-test/README.md b/v2/examples/panic-recovery-test/README.md new file mode 100644 index 000000000..c0a6a7e5a --- /dev/null +++ b/v2/examples/panic-recovery-test/README.md @@ -0,0 +1,76 @@ +# Panic Recovery Test + +This example demonstrates the Linux signal handler issue (#3965) and verifies the fix using `runtime.ResetSignalHandlers()`. + +## The Problem + +On Linux, WebKit installs signal handlers without the `SA_ONSTACK` flag, which prevents Go from recovering panics caused by nil pointer dereferences (SIGSEGV). Without the fix, the application crashes with: + +``` +signal 11 received but handler not on signal stack +fatal error: non-Go code set up signal handler without SA_ONSTACK flag +``` + +## The Solution + +Call `runtime.ResetSignalHandlers()` immediately before code that might panic: + +```go +import "github.com/wailsapp/wails/v2/pkg/runtime" + +go func() { + defer func() { + if err := recover(); err != nil { + log.Printf("Recovered: %v", err) + } + }() + runtime.ResetSignalHandlers() + // Code that might panic... +}() +``` + +## How to Reproduce + +### Prerequisites + +- Linux with WebKit2GTK 4.1 installed +- Go 1.21+ +- Wails CLI + +### Steps + +1. Build the example: + ```bash + cd v2/examples/panic-recovery-test + wails build -tags webkit2_41 + ``` + +2. Run the application: + ```bash + ./build/bin/panic-recovery-test + ``` + +3. Wait ~10 seconds (the app auto-calls `Greet` after 5s, then waits another 5s before the nil pointer dereference) + +### Expected Result (with fix) + +The panic is recovered and you see: +``` +------------------------------"invalid memory address or nil pointer dereference" +``` + +The application continues running. + +### Without the fix + +Comment out the `runtime.ResetSignalHandlers()` call in `app.go` and rebuild. The application will crash with a fatal signal 11 error. + +## Files + +- `app.go` - Contains the `Greet` function that demonstrates panic recovery +- `frontend/src/main.js` - Auto-calls `Greet` after 5 seconds to trigger the test + +## Related + +- Issue: https://github.com/wailsapp/wails/issues/3965 +- Original fix PR: https://github.com/wailsapp/wails/pull/2152 diff --git a/v2/examples/panic-recovery-test/app.go b/v2/examples/panic-recovery-test/app.go new file mode 100644 index 000000000..ceb46e8d5 --- /dev/null +++ b/v2/examples/panic-recovery-test/app.go @@ -0,0 +1,44 @@ +package main + +import ( + "context" + "fmt" + "time" + + "github.com/wailsapp/wails/v2/pkg/runtime" +) + +// App struct +type App struct { + ctx context.Context +} + +// NewApp creates a new App application struct +func NewApp() *App { + return &App{} +} + +// startup is called when the app starts. The context is saved +// so we can call the runtime methods +func (a *App) startup(ctx context.Context) { + a.ctx = ctx +} + +// Greet returns a greeting for the given name +func (a *App) Greet(name string) string { + go func() { + defer func() { + if err := recover(); err != nil { + fmt.Printf("------------------------------%#v\n", err) + } + }() + time.Sleep(5 * time.Second) + // Fix signal handlers right before potential panic using the Wails runtime + runtime.ResetSignalHandlers() + // Nil pointer dereference - causes SIGSEGV + var t *time.Time + fmt.Println(t.Unix()) + }() + + return fmt.Sprintf("Hello %s, It's show time!", name) +} diff --git a/v2/examples/panic-recovery-test/frontend/index.html b/v2/examples/panic-recovery-test/frontend/index.html new file mode 100644 index 000000000..d7aa4e942 --- /dev/null +++ b/v2/examples/panic-recovery-test/frontend/index.html @@ -0,0 +1,12 @@ + + + + + + panic-test + + +
+ + + diff --git a/v2/examples/panic-recovery-test/frontend/package.json b/v2/examples/panic-recovery-test/frontend/package.json new file mode 100644 index 000000000..a1b6f8e1a --- /dev/null +++ b/v2/examples/panic-recovery-test/frontend/package.json @@ -0,0 +1,13 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "vite": "^3.0.7" + } +} \ No newline at end of file diff --git a/v2/examples/panic-recovery-test/frontend/src/app.css b/v2/examples/panic-recovery-test/frontend/src/app.css new file mode 100644 index 000000000..59d06f692 --- /dev/null +++ b/v2/examples/panic-recovery-test/frontend/src/app.css @@ -0,0 +1,54 @@ +#logo { + display: block; + width: 50%; + height: 50%; + margin: auto; + padding: 10% 0 0; + background-position: center; + background-repeat: no-repeat; + background-size: 100% 100%; + background-origin: content-box; +} + +.result { + height: 20px; + line-height: 20px; + margin: 1.5rem auto; +} + +.input-box .btn { + width: 60px; + height: 30px; + line-height: 30px; + border-radius: 3px; + border: none; + margin: 0 0 0 20px; + padding: 0 8px; + cursor: pointer; +} + +.input-box .btn:hover { + background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); + color: #333333; +} + +.input-box .input { + border: none; + border-radius: 3px; + outline: none; + height: 30px; + line-height: 30px; + padding: 0 10px; + background-color: rgba(240, 240, 240, 1); + -webkit-font-smoothing: antialiased; +} + +.input-box .input:hover { + border: none; + background-color: rgba(255, 255, 255, 1); +} + +.input-box .input:focus { + border: none; + background-color: rgba(255, 255, 255, 1); +} \ No newline at end of file diff --git a/v2/examples/panic-recovery-test/frontend/src/assets/fonts/OFL.txt b/v2/examples/panic-recovery-test/frontend/src/assets/fonts/OFL.txt new file mode 100644 index 000000000..9cac04ce8 --- /dev/null +++ b/v2/examples/panic-recovery-test/frontend/src/assets/fonts/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/v2/examples/panic-recovery-test/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/v2/examples/panic-recovery-test/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 new file mode 100644 index 000000000..2f9cc5964 Binary files /dev/null and b/v2/examples/panic-recovery-test/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 differ diff --git a/v2/examples/panic-recovery-test/frontend/src/assets/images/logo-universal.png b/v2/examples/panic-recovery-test/frontend/src/assets/images/logo-universal.png new file mode 100644 index 000000000..d63303bfa Binary files /dev/null and b/v2/examples/panic-recovery-test/frontend/src/assets/images/logo-universal.png differ diff --git a/v2/examples/panic-recovery-test/frontend/src/main.js b/v2/examples/panic-recovery-test/frontend/src/main.js new file mode 100644 index 000000000..ea5e74fc6 --- /dev/null +++ b/v2/examples/panic-recovery-test/frontend/src/main.js @@ -0,0 +1,55 @@ +import './style.css'; +import './app.css'; + +import logo from './assets/images/logo-universal.png'; +import {Greet} from '../wailsjs/go/main/App'; + +document.querySelector('#app').innerHTML = ` + +
Please enter your name below 👇
+
+ + +
+ +`; +document.getElementById('logo').src = logo; + +let nameElement = document.getElementById("name"); +nameElement.focus(); +let resultElement = document.getElementById("result"); + +// Setup the greet function +window.greet = function () { + // Get name + let name = nameElement.value; + + // Check if the input is empty + if (name === "") return; + + // Call App.Greet(name) + try { + Greet(name) + .then((result) => { + // Update result with data back from App.Greet() + resultElement.innerText = result; + }) + .catch((err) => { + console.error(err); + }); + } catch (err) { + console.error(err); + } +}; + +// Auto-call Greet after 5 seconds to trigger the panic test +setTimeout(() => { + console.log("Auto-calling Greet to trigger panic test..."); + Greet("PanicTest") + .then((result) => { + resultElement.innerText = result + " (auto-called - panic will occur in 5s)"; + }) + .catch((err) => { + console.error("Error:", err); + }); +}, 5000); diff --git a/v2/examples/panic-recovery-test/frontend/src/style.css b/v2/examples/panic-recovery-test/frontend/src/style.css new file mode 100644 index 000000000..3940d6c63 --- /dev/null +++ b/v2/examples/panic-recovery-test/frontend/src/style.css @@ -0,0 +1,26 @@ +html { + background-color: rgba(27, 38, 54, 1); + text-align: center; + color: white; +} + +body { + margin: 0; + color: white; + font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", + "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; +} + +@font-face { + font-family: "Nunito"; + font-style: normal; + font-weight: 400; + src: local(""), + url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2"); +} + +#app { + height: 100vh; + text-align: center; +} diff --git a/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.d.ts b/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.d.ts new file mode 100755 index 000000000..02a3bb988 --- /dev/null +++ b/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.d.ts @@ -0,0 +1,4 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export function Greet(arg1:string):Promise; diff --git a/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.js b/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.js new file mode 100755 index 000000000..c71ae77cb --- /dev/null +++ b/v2/examples/panic-recovery-test/frontend/wailsjs/go/main/App.js @@ -0,0 +1,7 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export function Greet(arg1) { + return window['go']['main']['App']['Greet'](arg1); +} diff --git a/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/package.json b/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/package.json new file mode 100644 index 000000000..1e7c8a5d7 --- /dev/null +++ b/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/package.json @@ -0,0 +1,24 @@ +{ + "name": "@wailsapp/runtime", + "version": "2.0.0", + "description": "Wails Javascript runtime library", + "main": "runtime.js", + "types": "runtime.d.ts", + "scripts": { + }, + "repository": { + "type": "git", + "url": "git+https://github.com/wailsapp/wails.git" + }, + "keywords": [ + "Wails", + "Javascript", + "Go" + ], + "author": "Lea Anthony ", + "license": "MIT", + "bugs": { + "url": "https://github.com/wailsapp/wails/issues" + }, + "homepage": "https://github.com/wailsapp/wails#readme" +} diff --git a/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.d.ts b/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.d.ts new file mode 100644 index 000000000..4445dac21 --- /dev/null +++ b/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.d.ts @@ -0,0 +1,249 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +export interface Position { + x: number; + y: number; +} + +export interface Size { + w: number; + h: number; +} + +export interface Screen { + isCurrent: boolean; + isPrimary: boolean; + width : number + height : number +} + +// Environment information such as platform, buildtype, ... +export interface EnvironmentInfo { + buildType: string; + platform: string; + arch: string; +} + +// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) +// emits the given event. Optional data may be passed with the event. +// This will trigger any event listeners. +export function EventsEmit(eventName: string, ...data: any): void; + +// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. +export function EventsOn(eventName: string, callback: (...data: any) => void): () => void; + +// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) +// sets up a listener for the given event name, but will only trigger a given number times. +export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void; + +// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) +// sets up a listener for the given event name, but will only trigger once. +export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void; + +// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff) +// unregisters the listener for the given event name. +export function EventsOff(eventName: string, ...additionalEventNames: string[]): void; + +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all listeners. +export function EventsOffAll(): void; + +// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) +// logs the given message as a raw message +export function LogPrint(message: string): void; + +// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) +// logs the given message at the `trace` log level. +export function LogTrace(message: string): void; + +// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) +// logs the given message at the `debug` log level. +export function LogDebug(message: string): void; + +// [LogError](https://wails.io/docs/reference/runtime/log#logerror) +// logs the given message at the `error` log level. +export function LogError(message: string): void; + +// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) +// logs the given message at the `fatal` log level. +// The application will quit after calling this method. +export function LogFatal(message: string): void; + +// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) +// logs the given message at the `info` log level. +export function LogInfo(message: string): void; + +// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) +// logs the given message at the `warning` log level. +export function LogWarning(message: string): void; + +// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) +// Forces a reload by the main application as well as connected browsers. +export function WindowReload(): void; + +// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) +// Reloads the application frontend. +export function WindowReloadApp(): void; + +// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) +// Sets the window AlwaysOnTop or not on top. +export function WindowSetAlwaysOnTop(b: boolean): void; + +// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) +// *Windows only* +// Sets window theme to system default (dark/light). +export function WindowSetSystemDefaultTheme(): void; + +// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) +// *Windows only* +// Sets window to light theme. +export function WindowSetLightTheme(): void; + +// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) +// *Windows only* +// Sets window to dark theme. +export function WindowSetDarkTheme(): void; + +// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) +// Centers the window on the monitor the window is currently on. +export function WindowCenter(): void; + +// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) +// Sets the text in the window title bar. +export function WindowSetTitle(title: string): void; + +// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) +// Makes the window full screen. +export function WindowFullscreen(): void; + +// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) +// Restores the previous window dimensions and position prior to full screen. +export function WindowUnfullscreen(): void; + +// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen) +// Returns the state of the window, i.e. whether the window is in full screen mode or not. +export function WindowIsFullscreen(): Promise; + +// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) +// Sets the width and height of the window. +export function WindowSetSize(width: number, height: number): void; + +// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) +// Gets the width and height of the window. +export function WindowGetSize(): Promise; + +// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) +// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. +// Setting a size of 0,0 will disable this constraint. +export function WindowSetMaxSize(width: number, height: number): void; + +// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) +// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. +// Setting a size of 0,0 will disable this constraint. +export function WindowSetMinSize(width: number, height: number): void; + +// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) +// Sets the window position relative to the monitor the window is currently on. +export function WindowSetPosition(x: number, y: number): void; + +// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) +// Gets the window position relative to the monitor the window is currently on. +export function WindowGetPosition(): Promise; + +// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) +// Hides the window. +export function WindowHide(): void; + +// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) +// Shows the window, if it is currently hidden. +export function WindowShow(): void; + +// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) +// Maximises the window to fill the screen. +export function WindowMaximise(): void; + +// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) +// Toggles between Maximised and UnMaximised. +export function WindowToggleMaximise(): void; + +// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) +// Restores the window to the dimensions and position prior to maximising. +export function WindowUnmaximise(): void; + +// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised) +// Returns the state of the window, i.e. whether the window is maximised or not. +export function WindowIsMaximised(): Promise; + +// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) +// Minimises the window. +export function WindowMinimise(): void; + +// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) +// Restores the window to the dimensions and position prior to minimising. +export function WindowUnminimise(): void; + +// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised) +// Returns the state of the window, i.e. whether the window is minimised or not. +export function WindowIsMinimised(): Promise; + +// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal) +// Returns the state of the window, i.e. whether the window is normal or not. +export function WindowIsNormal(): Promise; + +// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) +// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. +export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; + +// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) +// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. +export function ScreenGetAll(): Promise; + +// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) +// Opens the given URL in the system browser. +export function BrowserOpenURL(url: string): void; + +// [Environment](https://wails.io/docs/reference/runtime/intro#environment) +// Returns information about the environment +export function Environment(): Promise; + +// [Quit](https://wails.io/docs/reference/runtime/intro#quit) +// Quits the application. +export function Quit(): void; + +// [Hide](https://wails.io/docs/reference/runtime/intro#hide) +// Hides the application. +export function Hide(): void; + +// [Show](https://wails.io/docs/reference/runtime/intro#show) +// Shows the application. +export function Show(): void; + +// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext) +// Returns the current text stored on clipboard +export function ClipboardGetText(): Promise; + +// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext) +// Sets a text on the clipboard +export function ClipboardSetText(text: string): Promise; + +// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop) +// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. +export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void + +// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff) +// OnFileDropOff removes the drag and drop listeners and handlers. +export function OnFileDropOff() :void + +// Check if the file path resolver is available +export function CanResolveFilePaths(): boolean; + +// Resolves file paths for an array of files +export function ResolveFilePaths(files: File[]): void \ No newline at end of file diff --git a/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.js b/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.js new file mode 100644 index 000000000..7cb89d750 --- /dev/null +++ b/v2/examples/panic-recovery-test/frontend/wailsjs/runtime/runtime.js @@ -0,0 +1,242 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +export function LogPrint(message) { + window.runtime.LogPrint(message); +} + +export function LogTrace(message) { + window.runtime.LogTrace(message); +} + +export function LogDebug(message) { + window.runtime.LogDebug(message); +} + +export function LogInfo(message) { + window.runtime.LogInfo(message); +} + +export function LogWarning(message) { + window.runtime.LogWarning(message); +} + +export function LogError(message) { + window.runtime.LogError(message); +} + +export function LogFatal(message) { + window.runtime.LogFatal(message); +} + +export function EventsOnMultiple(eventName, callback, maxCallbacks) { + return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); +} + +export function EventsOn(eventName, callback) { + return EventsOnMultiple(eventName, callback, -1); +} + +export function EventsOff(eventName, ...additionalEventNames) { + return window.runtime.EventsOff(eventName, ...additionalEventNames); +} + +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + +export function EventsOnce(eventName, callback) { + return EventsOnMultiple(eventName, callback, 1); +} + +export function EventsEmit(eventName) { + let args = [eventName].slice.call(arguments); + return window.runtime.EventsEmit.apply(null, args); +} + +export function WindowReload() { + window.runtime.WindowReload(); +} + +export function WindowReloadApp() { + window.runtime.WindowReloadApp(); +} + +export function WindowSetAlwaysOnTop(b) { + window.runtime.WindowSetAlwaysOnTop(b); +} + +export function WindowSetSystemDefaultTheme() { + window.runtime.WindowSetSystemDefaultTheme(); +} + +export function WindowSetLightTheme() { + window.runtime.WindowSetLightTheme(); +} + +export function WindowSetDarkTheme() { + window.runtime.WindowSetDarkTheme(); +} + +export function WindowCenter() { + window.runtime.WindowCenter(); +} + +export function WindowSetTitle(title) { + window.runtime.WindowSetTitle(title); +} + +export function WindowFullscreen() { + window.runtime.WindowFullscreen(); +} + +export function WindowUnfullscreen() { + window.runtime.WindowUnfullscreen(); +} + +export function WindowIsFullscreen() { + return window.runtime.WindowIsFullscreen(); +} + +export function WindowGetSize() { + return window.runtime.WindowGetSize(); +} + +export function WindowSetSize(width, height) { + window.runtime.WindowSetSize(width, height); +} + +export function WindowSetMaxSize(width, height) { + window.runtime.WindowSetMaxSize(width, height); +} + +export function WindowSetMinSize(width, height) { + window.runtime.WindowSetMinSize(width, height); +} + +export function WindowSetPosition(x, y) { + window.runtime.WindowSetPosition(x, y); +} + +export function WindowGetPosition() { + return window.runtime.WindowGetPosition(); +} + +export function WindowHide() { + window.runtime.WindowHide(); +} + +export function WindowShow() { + window.runtime.WindowShow(); +} + +export function WindowMaximise() { + window.runtime.WindowMaximise(); +} + +export function WindowToggleMaximise() { + window.runtime.WindowToggleMaximise(); +} + +export function WindowUnmaximise() { + window.runtime.WindowUnmaximise(); +} + +export function WindowIsMaximised() { + return window.runtime.WindowIsMaximised(); +} + +export function WindowMinimise() { + window.runtime.WindowMinimise(); +} + +export function WindowUnminimise() { + window.runtime.WindowUnminimise(); +} + +export function WindowSetBackgroundColour(R, G, B, A) { + window.runtime.WindowSetBackgroundColour(R, G, B, A); +} + +export function ScreenGetAll() { + return window.runtime.ScreenGetAll(); +} + +export function WindowIsMinimised() { + return window.runtime.WindowIsMinimised(); +} + +export function WindowIsNormal() { + return window.runtime.WindowIsNormal(); +} + +export function BrowserOpenURL(url) { + window.runtime.BrowserOpenURL(url); +} + +export function Environment() { + return window.runtime.Environment(); +} + +export function Quit() { + window.runtime.Quit(); +} + +export function Hide() { + window.runtime.Hide(); +} + +export function Show() { + window.runtime.Show(); +} + +export function ClipboardGetText() { + return window.runtime.ClipboardGetText(); +} + +export function ClipboardSetText(text) { + return window.runtime.ClipboardSetText(text); +} + +/** + * Callback for OnFileDrop returns a slice of file path strings when a drop is finished. + * + * @export + * @callback OnFileDropCallback + * @param {number} x - x coordinate of the drop + * @param {number} y - y coordinate of the drop + * @param {string[]} paths - A list of file paths. + */ + +/** + * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. + * + * @export + * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished. + * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target) + */ +export function OnFileDrop(callback, useDropTarget) { + return window.runtime.OnFileDrop(callback, useDropTarget); +} + +/** + * OnFileDropOff removes the drag and drop listeners and handlers. + */ +export function OnFileDropOff() { + return window.runtime.OnFileDropOff(); +} + +export function CanResolveFilePaths() { + return window.runtime.CanResolveFilePaths(); +} + +export function ResolveFilePaths(files) { + return window.runtime.ResolveFilePaths(files); +} \ No newline at end of file diff --git a/v2/examples/panic-recovery-test/go.mod b/v2/examples/panic-recovery-test/go.mod new file mode 100644 index 000000000..026042cbf --- /dev/null +++ b/v2/examples/panic-recovery-test/go.mod @@ -0,0 +1,5 @@ +module panic-recovery-test + +go 1.21 + +require github.com/wailsapp/wails/v2 v2.11.0 diff --git a/v2/examples/panic-recovery-test/main.go b/v2/examples/panic-recovery-test/main.go new file mode 100644 index 000000000..f6a38e86c --- /dev/null +++ b/v2/examples/panic-recovery-test/main.go @@ -0,0 +1,36 @@ +package main + +import ( + "embed" + + "github.com/wailsapp/wails/v2" + "github.com/wailsapp/wails/v2/pkg/options" + "github.com/wailsapp/wails/v2/pkg/options/assetserver" +) + +//go:embed all:frontend/dist +var assets embed.FS + +func main() { + // Create an instance of the app structure + app := NewApp() + + // Create application with options + err := wails.Run(&options.App{ + Title: "panic-test", + Width: 1024, + Height: 768, + AssetServer: &assetserver.Options{ + Assets: assets, + }, + BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, + OnStartup: app.startup, + Bind: []interface{}{ + app, + }, + }) + + if err != nil { + println("Error:", err.Error()) + } +} diff --git a/v2/examples/panic-recovery-test/wails.json b/v2/examples/panic-recovery-test/wails.json new file mode 100644 index 000000000..56770f091 --- /dev/null +++ b/v2/examples/panic-recovery-test/wails.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://wails.io/schemas/config.v2.json", + "name": "panic-recovery-test", + "outputfilename": "panic-recovery-test", + "frontend:install": "npm install", + "frontend:build": "npm run build", + "frontend:dev:watcher": "npm run dev", + "frontend:dev:serverUrl": "auto", + "author": { + "name": "Lea Anthony", + "email": "lea.anthony@gmail.com" + } +} diff --git a/v2/go.mod b/v2/go.mod index 1a40badd2..2eb753ee2 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -17,7 +17,7 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.3 github.com/jackmordaunt/icns v1.0.0 - github.com/jaypipes/ghw v0.13.0 + github.com/jaypipes/ghw v0.21.3 github.com/labstack/echo/v4 v4.13.3 github.com/labstack/gommon v0.4.2 github.com/leaanthony/clir v1.3.0 @@ -53,7 +53,6 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v1.1.5 // indirect - github.com/StackExchange/wmi v1.2.1 // indirect github.com/alecthomas/chroma/v2 v2.14.0 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect @@ -72,7 +71,7 @@ require ( github.com/gorilla/css v1.0.1 // indirect github.com/itchyny/gojq v0.12.13 // indirect github.com/itchyny/timefmt-go v0.1.5 // indirect - github.com/jaypipes/pcidb v1.0.1 // indirect + github.com/jaypipes/pcidb v1.1.1 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect @@ -82,7 +81,6 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/microcosm-cc/bluemonday v1.0.27 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect @@ -101,6 +99,7 @@ require ( github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect golang.org/x/crypto v0.33.0 // indirect golang.org/x/image v0.12.0 // indirect golang.org/x/sync v0.11.0 // indirect @@ -108,6 +107,6 @@ require ( golang.org/x/text v0.22.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - howett.net/plist v1.0.0 // indirect + howett.net/plist v1.0.2-0.20250314012144-ee69052608d9 // indirect mvdan.cc/sh/v3 v3.7.0 // indirect ) diff --git a/v2/go.sum b/v2/go.sum index 53e56707e..f6df3507e 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -24,8 +24,6 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4= github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= -github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= @@ -88,7 +86,7 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMj github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0= github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A= -github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -117,10 +115,10 @@ github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ= github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo= -github.com/jaypipes/ghw v0.13.0 h1:log8MXuB8hzTNnSktqpXMHc0c/2k/WgjOMSUtnI1RV4= -github.com/jaypipes/ghw v0.13.0/go.mod h1:In8SsaDqlb1oTyrbmTC14uy+fbBMvp+xdqX51MidlD8= -github.com/jaypipes/pcidb v1.0.1 h1:WB2zh27T3nwg8AE8ei81sNRb9yWBii3JGNJtT7K9Oic= -github.com/jaypipes/pcidb v1.0.1/go.mod h1:6xYUz/yYEyOkIkUt2t2J2folIuZ4Yg6uByCGFXMCeE4= +github.com/jaypipes/ghw v0.21.3 h1:v5mUHM+RN854Vqmk49Uh213jyUA4+8uqaRajlYESsh8= +github.com/jaypipes/ghw v0.21.3/go.mod h1:GPrvwbtPoxYUenr74+nAnWbardIZq600vJDD5HnPsPE= +github.com/jaypipes/pcidb v1.1.1 h1:QmPhpsbmmnCwZmHeYAATxEaoRuiMAJusKYkUncMC0ro= +github.com/jaypipes/pcidb v1.1.1/go.mod h1:x27LT2krrUgjf875KxQXKB0Ha/YXLdZRVmw6hH0G7g8= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= @@ -178,8 +176,6 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg= @@ -263,6 +259,8 @@ github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4= github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -340,7 +338,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -348,7 +345,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= -howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= +howett.net/plist v1.0.2-0.20250314012144-ee69052608d9 h1:eeH1AIcPvSc0Z25ThsYF+Xoqbn0CI/YnXVYoTLFdGQw= +howett.net/plist v1.0.2-0.20250314012144-ee69052608d9/go.mod h1:fyFX5Hj5tP1Mpk8obqA9MZgXT416Q5711SDT7dQLTLk= mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= diff --git a/v2/internal/frontend/desktop/linux/frontend.go b/v2/internal/frontend/desktop/linux/frontend.go index c009a18ca..2942a112e 100644 --- a/v2/internal/frontend/desktop/linux/frontend.go +++ b/v2/internal/frontend/desktop/linux/frontend.go @@ -73,6 +73,16 @@ static void install_signal_handlers() #endif } +static gboolean install_signal_handlers_idle(gpointer data) { + (void)data; + install_signal_handlers(); + return G_SOURCE_REMOVE; +} + +static void fix_signal_handlers_after_gtk_init() { + g_idle_add(install_signal_handlers_idle, NULL); +} + */ import "C" import ( @@ -204,7 +214,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger. result.mainWindow = NewWindow(appoptions, result.debug, result.devtoolsEnabled) - C.install_signal_handlers() + C.fix_signal_handlers_after_gtk_init() if appoptions.Linux != nil && appoptions.Linux.ProgramName != "" { prgname := C.CString(appoptions.Linux.ProgramName) diff --git a/v2/internal/s/s.go b/v2/internal/s/s.go index 5ba0d2eaa..adb304178 100644 --- a/v2/internal/s/s.go +++ b/v2/internal/s/s.go @@ -5,7 +5,6 @@ import ( "encoding/hex" "fmt" "io" - "io/ioutil" "os" "path/filepath" "strings" @@ -29,7 +28,7 @@ func checkError(err error) { func mute() { originalOutput = Output - Output = ioutil.Discard + Output = io.Discard } func unmute() { diff --git a/v2/pkg/runtime/signal_linux.go b/v2/pkg/runtime/signal_linux.go new file mode 100644 index 000000000..6a7ed5db3 --- /dev/null +++ b/v2/pkg/runtime/signal_linux.go @@ -0,0 +1,65 @@ +//go:build linux + +package runtime + +/* +#include +#include +#include +#include + +static void fix_signal(int signum) +{ + struct sigaction st; + + if (sigaction(signum, NULL, &st) < 0) { + return; + } + st.sa_flags |= SA_ONSTACK; + sigaction(signum, &st, NULL); +} + +static void fix_all_signals() +{ +#if defined(SIGSEGV) + fix_signal(SIGSEGV); +#endif +#if defined(SIGBUS) + fix_signal(SIGBUS); +#endif +#if defined(SIGFPE) + fix_signal(SIGFPE); +#endif +#if defined(SIGABRT) + fix_signal(SIGABRT); +#endif +} +*/ +import "C" + +// ResetSignalHandlers resets signal handlers to allow panic recovery. +// +// On Linux, WebKit (used for the webview) may install signal handlers without +// the SA_ONSTACK flag, which prevents Go from properly recovering from panics +// caused by nil pointer dereferences or other memory access violations. +// +// Call this function immediately before code that might panic to ensure +// the signal handlers are properly configured for Go's panic recovery mechanism. +// +// Example usage: +// +// go func() { +// defer func() { +// if err := recover(); err != nil { +// log.Printf("Recovered from panic: %v", err) +// } +// }() +// runtime.ResetSignalHandlers() +// // Code that might panic... +// }() +// +// Note: This function only has an effect on Linux. On other platforms, +// it is a no-op. +func ResetSignalHandlers() { + C.fix_all_signals() +} diff --git a/v2/pkg/runtime/signal_other.go b/v2/pkg/runtime/signal_other.go new file mode 100644 index 000000000..3171a700c --- /dev/null +++ b/v2/pkg/runtime/signal_other.go @@ -0,0 +1,18 @@ +//go:build !linux + +package runtime + +// ResetSignalHandlers resets signal handlers to allow panic recovery. +// +// On Linux, WebKit (used for the webview) may install signal handlers without +// the SA_ONSTACK flag, which prevents Go from properly recovering from panics +// caused by nil pointer dereferences or other memory access violations. +// +// Call this function immediately before code that might panic to ensure +// the signal handlers are properly configured for Go's panic recovery mechanism. +// +// Note: This function only has an effect on Linux. On other platforms, +// it is a no-op. +func ResetSignalHandlers() { + // No-op on non-Linux platforms +} diff --git a/v2/pkg/templates/base/go.mod.tmpl b/v2/pkg/templates/base/go.mod.tmpl index dd7184879..4b34d1668 100644 --- a/v2/pkg/templates/base/go.mod.tmpl +++ b/v2/pkg/templates/base/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.18 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/generate/assets/common/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/generate/plain/go.mod.tmpl b/v2/pkg/templates/generate/plain/go.mod.tmpl index e01fbe9e7..f6d0daec4 100644 --- a/v2/pkg/templates/generate/plain/go.mod.tmpl +++ b/v2/pkg/templates/generate/plain/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.18 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates.go b/v2/pkg/templates/templates.go index 9b42ef365..e18185520 100644 --- a/v2/pkg/templates/templates.go +++ b/v2/pkg/templates/templates.go @@ -186,7 +186,16 @@ func Install(options *Options) (bool, *Template, error) { return false, nil, err } options.TargetDir = targetDir - if !fs.DirExists(options.TargetDir) { + if fs.DirExists(options.TargetDir) { + // Check if directory is non-empty + entries, err := os.ReadDir(options.TargetDir) + if err != nil { + return false, nil, err + } + if len(entries) > 0 { + return false, nil, fmt.Errorf("cannot initialise project in non-empty directory: %s", options.TargetDir) + } + } else { err := fs.Mkdir(options.TargetDir) if err != nil { return false, nil, err diff --git a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/lit-ts/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/lit-ts/go.mod.tmpl b/v2/pkg/templates/templates/lit-ts/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/lit-ts/go.mod.tmpl +++ b/v2/pkg/templates/templates/lit-ts/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/lit/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/lit/go.mod.tmpl b/v2/pkg/templates/templates/lit/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/lit/go.mod.tmpl +++ b/v2/pkg/templates/templates/lit/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/plain/go.mod.tmpl b/v2/pkg/templates/templates/plain/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/plain/go.mod.tmpl +++ b/v2/pkg/templates/templates/plain/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/preact-ts/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/preact-ts/go.mod.tmpl b/v2/pkg/templates/templates/preact-ts/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/preact-ts/go.mod.tmpl +++ b/v2/pkg/templates/templates/preact-ts/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/preact/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/preact/go.mod.tmpl b/v2/pkg/templates/templates/preact/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/preact/go.mod.tmpl +++ b/v2/pkg/templates/templates/preact/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/react-ts/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/react-ts/go.mod.tmpl b/v2/pkg/templates/templates/react-ts/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/react-ts/go.mod.tmpl +++ b/v2/pkg/templates/templates/react-ts/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/react/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/react/go.mod.tmpl b/v2/pkg/templates/templates/react/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/react/go.mod.tmpl +++ b/v2/pkg/templates/templates/react/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/svelte-ts/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/svelte-ts/go.mod.tmpl b/v2/pkg/templates/templates/svelte-ts/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/svelte-ts/go.mod.tmpl +++ b/v2/pkg/templates/templates/svelte-ts/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/svelte/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/svelte/go.mod.tmpl b/v2/pkg/templates/templates/svelte/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/svelte/go.mod.tmpl +++ b/v2/pkg/templates/templates/svelte/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/vanilla-ts/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/vanilla-ts/go.mod.tmpl b/v2/pkg/templates/templates/vanilla-ts/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/vanilla-ts/go.mod.tmpl +++ b/v2/pkg/templates/templates/vanilla-ts/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/vanilla/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/vanilla/go.mod.tmpl b/v2/pkg/templates/templates/vanilla/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/vanilla/go.mod.tmpl +++ b/v2/pkg/templates/templates/vanilla/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/vue-ts/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/vue-ts/go.mod.tmpl b/v2/pkg/templates/templates/vue-ts/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/vue-ts/go.mod.tmpl +++ b/v2/pkg/templates/templates/vue-ts/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.d.ts b/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.d.ts index 02e7bb46b..336fb07aa 100644 --- a/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.d.ts +++ b/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.d.ts @@ -52,6 +52,10 @@ export function EventsOnce(eventName: string, callback: (...data: any) => void): // unregisters the listener for the given event name. export function EventsOff(eventName: string): void; +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all event listeners. +export function EventsOffAll(): void; + // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) // logs the given message as a raw message export function LogPrint(message: string): void; diff --git a/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.js b/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.js index 2c3dafcc3..b5ae16d56 100644 --- a/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.js +++ b/v2/pkg/templates/templates/vue/frontend/wailsjs/runtime/runtime.js @@ -48,6 +48,10 @@ export function EventsOff(eventName) { return window.runtime.EventsOff(eventName); } +export function EventsOffAll() { + return window.runtime.EventsOffAll(); +} + export function EventsOnce(eventName, callback) { EventsOnMultiple(eventName, callback, 1); } diff --git a/v2/pkg/templates/templates/vue/go.mod.tmpl b/v2/pkg/templates/templates/vue/go.mod.tmpl index 0dd9f465a..4b34d1668 100644 --- a/v2/pkg/templates/templates/vue/go.mod.tmpl +++ b/v2/pkg/templates/templates/vue/go.mod.tmpl @@ -1,6 +1,6 @@ module changeme -go 1.23 +go 1.23.0 require github.com/wailsapp/wails/v2 {{.WailsVersion}} diff --git a/v2/pkg/templates/templates_test.go b/v2/pkg/templates/templates_test.go index 3b906601a..658ecadb6 100644 --- a/v2/pkg/templates/templates_test.go +++ b/v2/pkg/templates/templates_test.go @@ -52,3 +52,48 @@ func TestInstall(t *testing.T) { is2.NoErr(err) } + +func TestInstallFailsInNonEmptyDirectory(t *testing.T) { + is2 := is.New(t) + + // Create a temp directory with a file in it + tempDir, err := os.MkdirTemp("", "wails-test-nonempty-*") + is2.NoErr(err) + defer func() { + _ = os.RemoveAll(tempDir) + }() + + // Create a file in the directory to make it non-empty + err = os.WriteFile(filepath.Join(tempDir, "existing-file.txt"), []byte("test"), 0644) + is2.NoErr(err) + + options := &Options{ + ProjectName: "test", + TemplateName: "vanilla", + TargetDir: tempDir, + } + + _, _, err = Install(options) + is2.True(err != nil) // Should fail + is2.True(err.Error() == "cannot initialise project in non-empty directory: "+tempDir) +} + +func TestInstallSucceedsInEmptyDirectory(t *testing.T) { + is2 := is.New(t) + + // Create an empty temp directory + tempDir, err := os.MkdirTemp("", "wails-test-empty-*") + is2.NoErr(err) + defer func() { + _ = os.RemoveAll(tempDir) + }() + + options := &Options{ + ProjectName: "test", + TemplateName: "vanilla", + TargetDir: tempDir, + } + + _, _, err = Install(options) + is2.NoErr(err) // Should succeed in empty directory +} diff --git a/website/docs/guides/linux.mdx b/website/docs/guides/linux.mdx index 1b55297b5..2cfc2e62a 100644 --- a/website/docs/guides/linux.mdx +++ b/website/docs/guides/linux.mdx @@ -70,3 +70,57 @@ If the added package does not resolve the issue, additional GStreamer dependenci - This issue impacts [Tauri apps](https://tauri.app/). Source: [developomp](https://github.com/developomp) on the [Tauri discussion board](https://github.com/tauri-apps/tauri/issues/4642#issuecomment-1643229562). + +## Panic Recovery / Signal Handling Issues + +### App crashes with "non-Go code set up signal handler without SA_ONSTACK flag" + +On Linux, if your application crashes with an error like: + +``` +signal 11 received but handler not on signal stack +fatal error: non-Go code set up signal handler without SA_ONSTACK flag +``` + +This occurs because WebKit (used for the webview) installs signal handlers that interfere with Go's panic recovery mechanism. +Normally, Go can convert signals like SIGSEGV (from nil pointer dereferences) into recoverable panics, but WebKit's signal +handlers prevent this. + +### Solution + +Use the `runtime.ResetSignalHandlers()` function immediately before code that might panic: + +```go +import "github.com/wailsapp/wails/v2/pkg/runtime" + +go func() { + defer func() { + if err := recover(); err != nil { + log.Printf("Recovered from panic: %v", err) + } + }() + // Reset signal handlers right before potentially dangerous code + runtime.ResetSignalHandlers() + + // Your code that might panic... +}() +``` + +:::warning Important + +- Call `ResetSignalHandlers()` in each goroutine where you need panic recovery +- Call it immediately before the code that might panic, as WebKit may reset the handlers at any time +- This is only necessary on Linux - the function is a no-op on other platforms + +::: + +### Why This Happens + +WebKit installs its own signal handlers for garbage collection and other internal processes. These handlers don't include +the `SA_ONSTACK` flag that Go requires to properly handle signals on the correct stack. When a signal like SIGSEGV occurs, +Go's runtime can't recover because the signal is being handled on the wrong stack. + +The `ResetSignalHandlers()` function adds the `SA_ONSTACK` flag to the signal handlers for SIGSEGV, SIGBUS, SIGFPE, and +SIGABRT, allowing Go's panic recovery to work correctly. + +Source: [GitHub Issue #3965](https://github.com/wailsapp/wails/issues/3965) diff --git a/website/docs/howdoesitwork.mdx b/website/docs/howdoesitwork.mdx index bdfbcb278..405930492 100644 --- a/website/docs/howdoesitwork.mdx +++ b/website/docs/howdoesitwork.mdx @@ -235,7 +235,7 @@ var AllWeekdays = []struct { } ``` -```go {10-12} +```go {14-16} //... err := wails.Run(&options.App{ Title: "Basic Demo", diff --git a/website/docs/reference/runtime/events.mdx b/website/docs/reference/runtime/events.mdx index b9a6196e2..909cb79e9 100644 --- a/website/docs/reference/runtime/events.mdx +++ b/website/docs/reference/runtime/events.mdx @@ -23,6 +23,13 @@ This method unregisters the listener for the given event name, optionally multip Go: `EventsOff(ctx context.Context, eventName string, additionalEventNames ...string)`
JS: `EventsOff(eventName string, ...additionalEventNames)` +### EventsOffAll + +This method unregisters all event listeners. + +Go: `EventsOffAll(ctx context.Context)`
+JS: `EventsOffAll()` + ### EventsOnce This method sets up a listener for the given event name, but will only trigger once. It returns a function to cancel diff --git a/website/docs/reference/runtime/intro.mdx b/website/docs/reference/runtime/intro.mdx index 3c491ecf0..d67e76c64 100644 --- a/website/docs/reference/runtime/intro.mdx +++ b/website/docs/reference/runtime/intro.mdx @@ -98,3 +98,46 @@ interface EnvironmentInfo { arch: string; } ``` + +### ResetSignalHandlers + +Resets signal handlers to allow panic recovery from nil pointer dereferences and other memory access violations. + +Go: `ResetSignalHandlers()` + +:::info Linux Only + +This function only has an effect on Linux. On macOS and Windows, it is a no-op. + +On Linux, WebKit (used for the webview) may install signal handlers without the `SA_ONSTACK` flag, which prevents +Go from properly recovering from panics caused by nil pointer dereferences (SIGSEGV) or other memory access violations. + +Call this function immediately before code that might panic to ensure the signal handlers are properly configured +for Go's panic recovery mechanism. + +::: + +#### Example + +```go +go func() { + defer func() { + if err := recover(); err != nil { + log.Printf("Recovered from panic: %v", err) + } + }() + // Reset signal handlers right before potentially dangerous code + runtime.ResetSignalHandlers() + + // Code that might cause a nil pointer dereference... + var t *time.Time + fmt.Println(t.Unix()) // This would normally crash on Linux +}() +``` + +:::warning + +This function must be called in each goroutine where you want panic recovery to work, and should be called +immediately before the code that might panic, as WebKit may reset the signal handlers at any time. + +::: diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/events.mdx b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/events.mdx index 91cb7adeb..b3d3c0d65 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/events.mdx +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/reference/runtime/events.mdx @@ -18,6 +18,13 @@ This method unregisters the listener for the given event name, optionally multip Go: `EventsOff(ctx context.Context, eventName string, additionalEventNames ...string)`
JS: `EventsOff(eventName string, ...additionalEventNames)` +### EventsOffAll 移除所有事件侦听器 + +此方法注销所有事件侦听器。 + +Go: `EventsOffAll(ctx context.Context)`
+JS: `EventsOffAll()` + ### EventsOnce 添加只触发一次的事件侦听器 此方法为给定的事件名称设置一个侦听器,但只会触发一次。 它返回 一个函数来取消侦听器。 diff --git a/website/src/pages/changelog.mdx b/website/src/pages/changelog.mdx index 7cb1bff2f..50208109b 100644 --- a/website/src/pages/changelog.mdx +++ b/website/src/pages/changelog.mdx @@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fixed `wails init` to prevent initialization in non-empty directories when using the `-d` flag, avoiding accidental data loss [`#4940`](https://github.com/wailsapp/wails/issues/4940) by `@leaanthony` +- Fixed missing `EventsOffAll` in runtime templates for all frontend frameworks [#4883](https://github.com/wailsapp/wails/pull/4883) by @narcilee7 +- Fixed Linux crash on panic in JS-bound Go methods due to WebKit overriding signal handlers [#3965](https://github.com/wailsapp/wails/issues/3965) by @leaanthony +- Fixed code block range in "How Does It Work?" documentation [#4884](https://github.com/wailsapp/wails/pull/4884) by @msal4 - Fixed WebView crash on macOS 26 (Tahoe) during rapid UI updates [#4592](https://github.com/wailsapp/wails/issues/4592) by @leaanthony - Updated menu reference docs with complete imports by @agilgur5 in [#4727](https://github.com/wailsapp/wails/pull/4727) and [#4742](https://github.com/wailsapp/wails/pull/4742) - Fixed menu reference syntax by @agilgur5 in [#4726](https://github.com/wailsapp/wails/pull/4726) @@ -24,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed link to CoC in Community Guide when there was a trailing slash by @agilgur5 in [#4732](https://github.com/wailsapp/wails/pull/4732) - Fixed indentation in "How does it work?" page by @agilgur5 in [#4733](https://github.com/wailsapp/wails/pull/4733) - Updated wails installation documentation to allow copying the `install wails` command with one click by @tilak999 in [#4692](https://github.com/wailsapp/wails/pull/4692) +- Remove ioutl.Discard and replace it with io.Discard by @xjh22222228 in [#4877](https://github.com/wailsapp/wails/pull/4877) ## v2.11.0 - 2025-11-08 @@ -40,6 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added url validation for BrowserOpenURL by @APshenkin in [PR](https://github.com/wailsapp/wails/pull/4484) - Fixed C compilation error in onWayland on Linux due to declaration after label [#4446](https://github.com/wailsapp/wails/pull/4446) by [@jaesung9507](https://github.com/jaesung9507) - Use computed style when adding 'wails-drop-target-active' [PR](https://github.com/wailsapp/wails/pull/4420) by [@riannucci](https://github.com/riannucci) +- Fixed initialisation templates to the correct Go version [PR](https://github.com/wailsapp/wails/pull/4618) by [@Xelus22](https://github.com/Xelus22) - Fixed panic when adding menuroles on Linux [#4558](https://github.com/wailsapp/wails/pull/4558) by [@jaesung9507](https://github.com/jaesung9507) - Fixed generated enums ordering [#4664](https://github.com/wailsapp/wails/pull/4664) by [@rprtr258](https://github.com/rprtr258). - Fixed Discord badge in README by @sharkmu in [PR](https://github.com/wailsapp/wails/pull/4626) diff --git a/website/static/img/sponsors.svg b/website/static/img/sponsors.svg index feaed7e15..09df56549 100644 --- a/website/static/img/sponsors.svg +++ b/website/static/img/sponsors.svg @@ -16,12 +16,28 @@ text { } Silver Sponsors - Orb + Orb - + - + + + + Johno Scott + + + + + + + + James Clark + + + + + Bronze Sponsors Cody Bentley @@ -61,116 +77,68 @@ text { -Covering Costs - Marcus - - - - - - - - Iain - - - - - - - - Michael +Covering Costs + Michael - + - - - - BlueSky... - - - - - - - - Sergio - - - - - - - - Digital... - - - - - + Buying Breakfast - Tai Groot + Tai Groot - + - + - Tom Wu + Tom Wu - + - + - vaaski + vaaski - + - + - Sander + Sander - + - + - Kevin + Kevin - + - - - - elapse2039 - - - - - + - Zach + Zach - + - + - John + John - + - + Buying Coffee @@ -192,40 +160,40 @@ text { + + + + + + + - + - + - + - + - + - + - - - - - - - - + @@ -305,71 +273,92 @@ text { Helpers - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + - + - + - + - + - + - + + + + + + + + + + + + + + +