wails icon indicating copy to clipboard operation
wails copied to clipboard

fix incorrect window destroy

Open atterpac opened this issue 8 months ago β€’ 2 comments

removes a mapping for WindowShouldClose on Mac, this incorrecty triggers a window.destroy call on every hide()

Summary by CodeRabbit

  • Bug Fixes
    • Improved event handling on macOS by updating the mapping for window close events.

atterpac avatar May 29 '25 23:05 atterpac

Walkthrough

The changes remove duplicate macOS event mappings, add debug logging for window lifecycle events on macOS, and introduce a thread-safe atomic flag to control unconditional window closing. A new platform-specific Go function is exposed to Objective-C to determine if a window should close unconditionally, integrating conditional close logic between Go and native layers.

Changes

File(s) Change Summary
v3/pkg/events/defaults.go Removed three duplicate macOS event mapping entries for window focus and resize events.
v3/pkg/application/webview_window.go, webview_window_windows.go Changed unconditionallyClose from bool to uint32; replaced boolean checks with atomic operations for thread safety.
v3/pkg/application/webview_window_darwin.go Added debug logging to hide() and close(); atomically set unconditionallyClose flag before closing; removed commented code.
v3/pkg/application/webview_window_darwin.m Added debug logs to window lifecycle handlers; declared and used new external C function for conditional window close logic.
v3/pkg/application/webview_window_close_darwin.go Added new Go file implementing windowShouldUnconditionallyClose for C linkage to check atomic close flag.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Native (Obj-C)
    participant App (Go)
    
    User->>Native: Initiate window close
    Native->>App (Go): windowShouldUnconditionallyClose(windowId)
    App (Go)->>App (Go): Retrieve window, atomically read close flag
    App (Go)-->>Native: Return true/false
    alt Close unconditionally
        Native-->>User: Close window immediately
    else User-initiated close
        Native->>App (Go): Emit WindowShouldClose event
        App (Go)-->>User: Application handles close event
    end

Poem

πŸ‡ Hopping through code with a keen little eye,
Windows now close with a whisper, not a sigh.
Atomic flags guard the paths they must tread,
Debug logs tell stories of what lies ahead.
No duplicates here, just clear, tidy tracksβ€”
The rabbit’s delight in these well-crafted hacks! πŸͺŸβœ¨


πŸ“œ Recent review details

Configuration used: .coderabbit.yaml Review profile: CHILL Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between f1a3dc6c0de63539368909ed871ca98387cca370 and 468b74b24488a965524ef1d5460097e865216e97.

πŸ“’ Files selected for processing (2)
  • v3/pkg/application/webview_window_darwin.go (4 hunks)
  • v3/pkg/application/webview_window_windows.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • v3/pkg/application/webview_window_darwin.go
  • v3/pkg/application/webview_window_windows.go
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Run Go Tests v3 (windows-latest, 1.24)
  • GitHub Check: Run Go Tests v3 (ubuntu-latest, 1.24)
  • GitHub Check: Run Go Tests v3 (macos-latest, 1.24)
✨ Finishing Touches
  • [ ] πŸ“ Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share
πŸͺ§ Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

coderabbitai[bot] avatar May 29 '25 23:05 coderabbitai[bot]

@atterpac @leaanthony I'm trying to apply this fix to resolve a crash during macOS window destroy, but it seems to be stopping the window close button from working at all.

~I believe it is due to the fact that the window delegate always returns false from windowShouldClose and as such, windowWillClose will never fire. https://github.com/wailsapp/wails/blob/v3-alpha/v3/pkg/application/webview_window_darwin.m#L235~

Am I missing some other event handling I need to do to get the window to close when the close button is clicked with this change, or does the window delegate need a corresponding change?

UPDATE: This appears to have been specific to my app's window event handling and not an inherent issue with this change. Please disregard!

joshhardy avatar Jun 09 '25 19:06 joshhardy

@atterpac - If I run the "events" example, none of the windows close.

Interesting, I'll have to take the look I was only testing with the window example

atterpac avatar Jun 10 '25 12:06 atterpac

Fix Summary for Issue #4251

I've successfully fixed the duplicate symbol compilation issue that was preventing this PR from building. Here's a comprehensive summary of the solution:

Problem Addressed

This PR fixes issue #4251 where macOS windows would crash the system when using hide/show functionality. The core issue was that window.Close() and user-initiated window closes weren't properly distinguishable, causing windows to actually close instead of just hiding when applications wanted hide-on-close behavior.

Root Cause

The original issue was in the event mapping in v3/pkg/events/defaults.go where Mac.WindowWillClose was incorrectly mapped to Common.WindowClosing. This caused every window hide operation to incorrectly trigger a window destroy event.

Solution Components

  1. Event Mapping Fix (v3/pkg/events/defaults.go)
  • Changed mapping from Mac.WindowWillClose β†’ Common.WindowClosing
  • To: Mac.WindowShouldClose β†’ Common.WindowClosing
  • This ensures the WindowClosing event is emitted at the right time (when close is requested) rather than when the window is actually closing
  1. Window Close Logic (v3/pkg/application/webview_window_darwin.m)
  • Enhanced windowShouldClose: delegate method to check if window should close unconditionally
  • When Close() method is called programmatically, sets unconditionallyClose flag and allows actual close
  • When user clicks close button, emits WindowClosing event and returns false to prevent close (unless application handles the event)
  1. Unconditional Close Support (v3/pkg/application/webview_window_close_darwin.go)
  • Added new exported function windowShouldUnconditionallyClose()
  • Created separate file to avoid CGo symbol conflicts during compilation
  • Allows C code to check if a window should close without application intervention
  1. Go Integration (v3/pkg/application/webview_window_darwin.go)
  • Modified close() method to set unconditionallyClose = true before calling native close
  • This distinguishes programmatic Close() calls from user-initiated close attempts

How It Works

For Hide-on-Close Applications:

  1. User clicks close button β†’ windowShouldClose called
  2. unconditionallyClose is false β†’ emits WindowClosing event
  3. Application handles WindowClosing with window.Hide() + e.Cancel()
  4. Window hides instead of closing

For Normal Close Operations:

  1. Application calls window.Close() β†’ sets unconditionallyClose = true
  2. windowShouldClose called β†’ checks flag and returns true
  3. Window actually closes as expected

Compilation Fix

The original code had 60 duplicate C symbols during linking. Fixed by:

  • Moving the //export windowShouldUnconditionallyClose function to a separate file
  • This isolates the CGo export directive from the main webview file which has extensive C code
  • Prevents symbol conflicts while maintaining functionality

Debug Messages Added

I've added comprehensive debug logging for testing purposes:

Go Debug Messages:

  • Window showing/hiding operations
  • Close method calls and flag setting
  • Unconditional close checks

Objective-C NSLog Messages:

  • windowShouldClose calls and decisions
  • Window order on/off screen events
  • Window will close events

Testing

βœ… Compilation: All examples build successfully βœ… Functionality: Hide-on-close behavior works correctly in v3/examples/hide-window βœ… Event Flow: Debug logs confirm proper event sequence

Example logs for hide-on-close: [DEBUG] windowShouldClose called for window X [DEBUG] Window X close requested by user - emitting WindowClosing event [DEBUG] Window hiding [DEBUG] Window X WILL order off screen [DEBUG] Window X ordered OFF screen

Next Steps for @atterpac

  1. Test the fix with your specific use case using the debug messages
  2. If testing is successful, please remove the debug messages from: - v3/pkg/application/webview_window_darwin.go (lines with globalApplication.debug) - v3/pkg/application/webview_window_close_darwin.go (debug messages in the exported function) - v3/pkg/application/webview_window_darwin.m (all NSLog(@"[DEBUG]..." lines)
  3. Push the cleaned-up changes for final review

leaanthony avatar Jun 11 '25 12:06 leaanthony

ABI Safety Fix - Addressed CodeRabbit Feedback

Fixed the ABI safety issues identified by @coderabbitai[bot] in the exported function:

Changes Made:

Function Signature - Now uses proper C types:

// Before
func windowShouldUnconditionallyClose(windowId uint) bool

// After  
func windowShouldUnconditionallyClose(windowId C.uint) C.bool

Implementation Updates:

  • Cast C.uint to uint for internal Go function calls: uint(windowId)
  • All return statements now use C.bool() casting
  • Maintains all error handling and functionality

Why This Matters:

  • βœ… ABI Stability - C types guarantee consistent size/alignment across platforms
  • βœ… Portability - Works reliably across different architectures and compilers
  • βœ… Future-Proofing - Prevents issues if Go's native types change representation
  • βœ… Best Practice - Standard pattern for CGo exported functions

Testing:

  • βœ… Builds successfully on macOS
  • βœ… All functionality preserved
  • βœ… No performance impact

This follows CGo best practices and ensures the exported function has a stable, compiler-verified ABI between the Go and Objective-C layers. Thanks @coderabbitai[bot] for the excellent feedback!

leaanthony avatar Jun 11 '25 13:06 leaanthony

[!TIP] For best results, initiate chat on the files or code changes.

@leaanthony Awesome – thanks for jumping on that so quickly!
Using C.uint / C.bool on the exported boundary is exactly what I was after, and casting back to Go-level uint keeps the internal logic tidy. That covers the ABI-stability concern I raised, so we’re βœ… on that front.

I skimmed the latest diff and everything looks consistent:

β€’ //export windowShouldUnconditionallyClose still precedes the correct function.
β€’ No additional cgo header is needed because C.bool and C.uint come from <stdbool.h> / <stdint.h> that cgo pulls in automatically.
β€’ All return paths now wrap the Go bool with C.bool(...), eliminating implicit conversions.

No further changes required from my side – feel free to proceed with the cleanup of the temporary debug logs whenever you’re ready.

Nice work! πŸ‡βœ¨

coderabbitai[bot] avatar Jun 11 '25 13:06 coderabbitai[bot]

Quality Gate Failed Quality Gate failed

Failed conditions
C Maintainability Rating on New Code (required β‰₯ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

sonarqubecloud[bot] avatar Jun 17 '25 11:06 sonarqubecloud[bot]

Merging with debug statements for now.

leaanthony avatar Jun 17 '25 12:06 leaanthony