wails/v3/pkg/application/webview_window_close_darwin.go
Lea Anthony f3af37be72
fix(darwin): prevent window destruction when hiding with ApplicationShouldTerminateAfterLastWindowClosed (#4800)
* ## Summary

I've verified and fixed the bug reported in GitHub issue #4389. Here's what was done:

### Root Cause Analysis

The crash occurred on macOS when using `Hide()` and `Show()` to toggle window visibility via a system tray. The sequence was:

1. `Hide()` calls `orderOut:nil` which removes the window from screen
2. With `ApplicationShouldTerminateAfterLastWindowClosed = true` (default), macOS considers the app to have no visible windows
3. macOS triggers `windowShouldClose:` which emits `EventWindowShouldClose`
4. The event mapping translates this to `Common.WindowClosing`
5. The `WindowClosing` handler destroys the window and removes it from the window map
6. When `Show()` is called later, the window doesn't exist anymore → crash

### Fix Implementation

**File: `v3/pkg/application/webview_window_close_darwin.go`**
- Added new exported function `windowIsHidden()` that checks if a window is marked as hidden via `window.options.Hidden`

**File: `v3/pkg/application/webview_window_darwin.m`**
- Added extern declaration for `windowIsHidden`
- Modified `windowShouldClose:` delegate method to return `false` early (without emitting close events) if the window is hidden

The fix ensures that when a window is intentionally hidden (not closed), the close event sequence is not triggered, preserving the window for later re-showing.

### Test Case Created

Created `v3/tests/systray-hide-show-test/` - a test application that:
- Creates a window and system tray
- Clicking the tray toggles window visibility
- Previously crashed after hide→show→hide sequence; now works correctly

### Files Modified

1. `v3/pkg/application/webview_window_close_darwin.go` - Added `windowIsHidden()` function
2. `v3/pkg/application/webview_window_darwin.m` - Check hidden state in `windowShouldClose:`
3. `v3/UNRELEASED_CHANGELOG.md` - Added fix entry

### Files Added

1. `v3/tests/systray-hide-show-test/main.go` - Test case
2. `v3/tests/systray-hide-show-test/icon.png` - Icon for test

All existing tests pass. The fix is minimal and targeted, only affecting the specific scenario where a hidden window receives a close query.

* Done. The redundant test case has been removed. The fix is covered by the existing `v3/examples/hide-window/` example.

Current staged changes:
- Deleted `v3/tests/systray-hide-show-test/` (test case, icon, and binary)

The fix itself (in `webview_window_close_darwin.go` and `webview_window_darwin.m`) and the changelog entry were already committed in the previous commit.
2025-12-15 22:28:41 +11:00

33 lines
948 B
Go

//go:build darwin && !ios
package application
/*
#include <stdbool.h>
*/
import "C"
//export windowShouldUnconditionallyClose
func windowShouldUnconditionallyClose(windowId C.uint) C.bool {
window, _ := globalApplication.Window.GetByID(uint(windowId))
if window == nil {
globalApplication.debug("windowShouldUnconditionallyClose: window not found", "windowId", windowId)
return C.bool(false)
}
unconditionallyClose := window.shouldUnconditionallyClose()
globalApplication.debug("windowShouldUnconditionallyClose check", "windowId", windowId, "unconditionallyClose", unconditionallyClose)
return C.bool(unconditionallyClose)
}
//export windowIsHidden
func windowIsHidden(windowId C.uint) C.bool {
window, _ := globalApplication.Window.GetByID(uint(windowId))
if window == nil {
return C.bool(false)
}
webviewWindow, ok := window.(*WebviewWindow)
if !ok {
return C.bool(false)
}
return C.bool(webviewWindow.options.Hidden)
}