From 957f759197d5a35aec180706fbf6659c2a805614 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sat, 14 Dec 2024 17:56:16 +1100 Subject: [PATCH] Improve window destroying on Mac --- v3/pkg/application/application.go | 85 +++++++++++++++++++------- v3/pkg/application/messageprocessor.go | 2 +- v3/pkg/application/webview_window.go | 29 ++++++--- 3 files changed, 85 insertions(+), 31 deletions(-) diff --git a/v3/pkg/application/application.go b/v3/pkg/application/application.go index 264f8e1fe..161761e81 100644 --- a/v3/pkg/application/application.go +++ b/v3/pkg/application/application.go @@ -20,10 +20,10 @@ import ( "github.com/wailsapp/wails/v3/internal/operatingsystem" - "github.com/pkg/browser" - "github.com/samber/lo" "github.com/wailsapp/wails/v3/internal/signal" + "github.com/pkg/browser" + "github.com/samber/lo" "github.com/wailsapp/wails/v3/internal/assetserver" "github.com/wailsapp/wails/v3/internal/assetserver/webview" "github.com/wailsapp/wails/v3/internal/capabilities" @@ -581,45 +581,73 @@ func (a *App) Run() error { a.impl = newPlatformApp(a) go func() { for { - event := <-applicationEvents - go a.handleApplicationEvent(event) + select { + case <-a.ctx.Done(): + return + case event := <-applicationEvents: + go a.handleApplicationEvent(event) + } } }() go func() { for { - event := <-windowEvents - go a.handleWindowEvent(event) + select { + case <-a.ctx.Done(): + return + case event := <-windowEvents: + go a.handleWindowEvent(event) + } } }() go func() { for { - request := <-webviewRequests - go a.handleWebViewRequest(request) + select { + case <-a.ctx.Done(): + return + case request := <-webviewRequests: + go a.handleWebViewRequest(request) + } } }() go func() { for { - event := <-windowMessageBuffer - go a.handleWindowMessage(event) + select { + case <-a.ctx.Done(): + return + case event := <-windowMessageBuffer: + go a.handleWindowMessage(event) + } } }() go func() { for { - event := <-windowKeyEvents - go a.handleWindowKeyEvent(event) + select { + case <-a.ctx.Done(): + return + case event := <-windowKeyEvents: + go a.handleWindowKeyEvent(event) + } } }() go func() { for { - dragAndDropMessage := <-windowDragAndDropBuffer - go a.handleDragAndDropMessage(dragAndDropMessage) + select { + case <-a.ctx.Done(): + return + case dragAndDropMessage := <-windowDragAndDropBuffer: + go a.handleDragAndDropMessage(dragAndDropMessage) + } } }() + go func() { + for { + select { + case <-a.ctx.Done(): + return + case menuItemID := <-menuItemClicked: - go func() { - for { - menuItemID := <-menuItemClicked - go a.handleMenuItemClicked(menuItemID) + go a.handleMenuItemClicked(menuItemID) + } } }() @@ -689,12 +717,15 @@ func (a *App) handleApplicationEvent(event *ApplicationEvent) { } func (a *App) handleDragAndDropMessage(event *dragAndDropMessage) { + if globalApplication.performingShutdown { + return + } // Get window from window map a.windowsLock.Lock() window, ok := a.windows[event.windowId] a.windowsLock.Unlock() if !ok { - log.Printf("WebviewWindow #%d not found", event.windowId) + log.Printf("handleDragAndDropMessage: WebviewWindow #%d not found", event.windowId) return } // Get callback from window @@ -702,12 +733,15 @@ func (a *App) handleDragAndDropMessage(event *dragAndDropMessage) { } func (a *App) handleWindowMessage(event *windowMessage) { + if globalApplication.performingShutdown { + return + } // Get window from window map a.windowsLock.RLock() window, ok := a.windows[event.windowId] a.windowsLock.RUnlock() if !ok { - log.Printf("WebviewWindow #%d not found", event.windowId) + log.Printf("handleWindowMessage: WebviewWindow #%d not found", event.windowId) return } // Check if the message starts with "wails:" @@ -725,18 +759,27 @@ func (a *App) handleWebViewRequest(request *webViewAssetRequest) { } func (a *App) handleWindowEvent(event *windowEvent) { + if globalApplication.performingShutdown { + return + } // Get window from window map a.windowsLock.RLock() window, ok := a.windows[event.WindowID] a.windowsLock.RUnlock() + if !ok { - log.Printf("Window #%d not found", event.WindowID) + // Window not found - it's probably been destroyed return } + + // Normal event handling for active windows window.HandleWindowEvent(event.EventID) } func (a *App) handleMenuItemClicked(menuItemID uint) { + if globalApplication.performingShutdown { + return + } menuItem := getMenuItemByID(menuItemID) if menuItem == nil { log.Printf("MenuItem #%d not found", menuItemID) diff --git a/v3/pkg/application/messageprocessor.go b/v3/pkg/application/messageprocessor.go index 62d7950dc..dd47ddf17 100644 --- a/v3/pkg/application/messageprocessor.go +++ b/v3/pkg/application/messageprocessor.go @@ -28,7 +28,7 @@ const ( ) type MessageProcessor struct { - logger *slog.Logger + logger *slog.Logger runningCalls map[string]context.CancelFunc l sync.Mutex diff --git a/v3/pkg/application/webview_window.go b/v3/pkg/application/webview_window.go index 5aed72475..39c08531d 100644 --- a/v3/pkg/application/webview_window.go +++ b/v3/pkg/application/webview_window.go @@ -110,6 +110,7 @@ type ( type WindowEvent struct { ctx *WindowEventContext Cancelled bool + WindowID uint } func (w *WindowEvent) Context() *WindowEventContext { @@ -718,7 +719,7 @@ func (w *WebviewWindow) startResize(border string) error { if w.impl == nil && !w.isDestroyed() { return nil } - return InvokeSyncWithResult(func() error { + return InvokeSyncWithError(func() error { return w.impl.startResize(border) }) } @@ -770,6 +771,7 @@ func (w *WebviewWindow) RegisterHook(eventType events.WindowEventType, callback } func (w *WebviewWindow) HandleWindowEvent(id uint) { + // Get hooks for this event w.eventListenersLock.RLock() defer w.eventListenersLock.RUnlock() @@ -780,6 +782,7 @@ func (w *WebviewWindow) HandleWindowEvent(id uint) { // Create new WindowEvent thisEvent := NewWindowEvent() + thisEvent.WindowID = w.id for _, thisHook := range hooks { thisHook.callback(thisEvent) @@ -905,11 +908,18 @@ func (w *WebviewWindow) Destroy() { return } - // Cancel the callbacks + // Mark as being destroyed - this prevents new events from being processed + w.markAsDestroyed() + + // Cancel all callbacks for _, cancelFunc := range w.cancellers { cancelFunc() } + // Remove from global application map and destroy the native window + globalApplication.windowsLock.Lock() + delete(globalApplication.windows, w.id) + globalApplication.windowsLock.Unlock() InvokeSync(w.impl.destroy) } @@ -1179,6 +1189,7 @@ func (w *WebviewWindow) HandleDragAndDropMessage(filenames []string) { ctx := newWindowEventContext() ctx.setDroppedFiles(filenames) thisEvent.ctx = ctx + thisEvent.WindowID = w.id for _, listener := range w.eventListeners[uint(events.Common.WindowFilesDropped)] { listener.callback(thisEvent) } @@ -1223,13 +1234,6 @@ func (w *WebviewWindow) Focus() { w.emit(events.Common.WindowFocus) } -func (w *WebviewWindow) emit(eventType events.WindowEventType) { - windowEvents <- &windowEvent{ - WindowID: w.id, - EventID: uint(eventType), - } -} - func (w *WebviewWindow) startDrag() error { if w.impl == nil && !w.isDestroyed() { return nil @@ -1358,3 +1362,10 @@ func (w *WebviewWindow) delete() { w.impl.delete() } } + +func (w *WebviewWindow) emit(eventType events.WindowEventType) { + windowEvents <- &windowEvent{ + WindowID: w.id, + EventID: uint(eventType), + } +}