diff --git a/v3/examples/window/main.go b/v3/examples/window/main.go index 7a3c33274..ff911b47d 100644 --- a/v3/examples/window/main.go +++ b/v3/examples/window/main.go @@ -3,6 +3,7 @@ package main import ( _ "embed" "fmt" + "github.com/samber/lo" "github.com/wailsapp/wails/v3/pkg/events" "log" "math/rand" @@ -25,6 +26,8 @@ func main() { log.Println("ApplicationDidFinishLaunching") }) + var hiddenWindows []*application.WebviewWindow + currentWindow := func(fn func(window *application.WebviewWindow)) { if app.CurrentWindow() != nil { fn(app.CurrentWindow()) @@ -52,10 +55,29 @@ func main() { Show() windowCounter++ }) - myMenu.Add("New WebviewWindow (Hide on Close"). + myMenu.Add("New WebviewWindow (Hides on Close one time)"). SetAccelerator("CmdOrCtrl+H"). OnClick(func(ctx *application.Context) { - app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{HideOnClose: true}). + app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ + // This will be called when the user clicks the close button + // on the window. It will hide the window for 5 seconds. + // If the user clicks the close button again, the window will + // close. + ShouldClose: func(window *application.WebviewWindow) bool { + if !lo.Contains(hiddenWindows, window) { + hiddenWindows = append(hiddenWindows, window) + go func() { + time.Sleep(5 * time.Second) + window.Show() + }() + window.Hide() + return false + } + // Remove the window from the hiddenWindows list + hiddenWindows = lo.Without(hiddenWindows, window) + return true + }, + }). SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)). SetPosition(rand.Intn(1000), rand.Intn(800)). SetURL("https://wails.io"). diff --git a/v3/pkg/application/options_webview_window.go b/v3/pkg/application/options_webview_window.go index 36c10d73a..51df2b365 100644 --- a/v3/pkg/application/options_webview_window.go +++ b/v3/pkg/application/options_webview_window.go @@ -31,7 +31,6 @@ type WebviewWindowOptions struct { CSS string X int Y int - HideOnClose bool FullscreenButtonEnabled bool Hidden bool EnableFraudulentWebsiteWarnings bool @@ -43,6 +42,10 @@ type WebviewWindowOptions struct { Windows WindowsWindow Focused bool Menu *Menu + + // ShouldClose is called when the window is about to close. + // Return true to allow the window to close, or false to prevent it from closing. + ShouldClose func(window *WebviewWindow) bool } var WebviewWindowDefaults = &WebviewWindowOptions{ diff --git a/v3/pkg/application/webview_window.go b/v3/pkg/application/webview_window.go index 98bb45266..ef7d536ae 100644 --- a/v3/pkg/application/webview_window.go +++ b/v3/pkg/application/webview_window.go @@ -125,6 +125,18 @@ func NewWindow(options WebviewWindowOptions) *WebviewWindow { contextMenus: make(map[string]*Menu), } + // Listen for window closing events and de + result.On(events.Common.WindowClosing, func(ctx *WindowEventContext) { + shouldClose := true + if result.options.ShouldClose != nil { + shouldClose = result.options.ShouldClose(result) + } + if shouldClose { + globalApplication.deleteWindowByID(result.id) + invokeSync(result.impl.close) + } + }) + return result } @@ -629,12 +641,7 @@ func (w *WebviewWindow) Close() { if w.impl == nil { return } - if w.options.HideOnClose { - invokeSync(func() { w.Hide() }) - return - } - invokeSync(w.impl.close) - w.emit(events.Common.WindowClose) + w.emit(events.Common.WindowClosing) } func (w *WebviewWindow) Zoom() { diff --git a/v3/pkg/application/webview_window_darwin.go b/v3/pkg/application/webview_window_darwin.go index ccfd93144..406bd32a9 100644 --- a/v3/pkg/application/webview_window_darwin.go +++ b/v3/pkg/application/webview_window_darwin.go @@ -18,7 +18,7 @@ package application extern void registerListener(unsigned int event); // Create a new Window -void* windowNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, bool hideOnClose) { +void* windowNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop) { NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; if (frameless) { styleMask = NSWindowStyleMaskBorderless | NSWindowStyleMaskResizable; @@ -77,8 +77,6 @@ void* windowNew(unsigned int id, int width, int height, bool fraudulentWebsiteWa // Ensure webview resizes with the window [webView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - delegate.hideOnClose = hideOnClose; - if( enableDragAndDrop ) { WebviewDrag* dragView = [[WebviewDrag alloc] initWithFrame:NSMakeRect(0, 0, width-1, height-1)]; [dragView autorelease]; @@ -936,10 +934,6 @@ func (w *macosWebviewWindow) windowZoom() { } func (w *macosWebviewWindow) close() { - if w.parent.options.HideOnClose { - w.hide() - return - } C.windowClose(w.nsWindow) } @@ -1123,7 +1117,6 @@ func (w *macosWebviewWindow) run() { C.bool(w.parent.options.EnableFraudulentWebsiteWarnings), C.bool(w.parent.options.Frameless), C.bool(w.parent.options.EnableDragAndDrop), - C.bool(w.parent.options.HideOnClose), ) w.setTitle(w.parent.options.Title) w.setAlwaysOnTop(w.parent.options.AlwaysOnTop) @@ -1193,13 +1186,9 @@ func (w *macosWebviewWindow) run() { } }) - w.parent.On(events.Mac.WindowWillClose, func(_ *WindowEventContext) { - globalApplication.deleteWindowByID(w.parent.id) - }) - + // Translate ShouldClose to common WindowClosing event w.parent.On(events.Mac.WindowShouldClose, func(_ *WindowEventContext) { - // TODO: Process "should close" callback for user - w.close() + w.emit(events.Common.WindowClosing) }) if w.parent.options.HTML != "" { diff --git a/v3/pkg/application/webview_window_darwin.h b/v3/pkg/application/webview_window_darwin.h index 280ec934c..af2f146c8 100644 --- a/v3/pkg/application/webview_window_darwin.h +++ b/v3/pkg/application/webview_window_darwin.h @@ -20,7 +20,6 @@ @interface WebviewWindowDelegate : NSObject -@property bool hideOnClose; @property unsigned int windowId; @property (retain) NSEvent* leftMouseEvent; @property unsigned int invisibleTitleBarHeight; diff --git a/v3/pkg/application/webview_window_darwin.m b/v3/pkg/application/webview_window_darwin.m index c7315871d..1a5b80c85 100644 --- a/v3/pkg/application/webview_window_darwin.m +++ b/v3/pkg/application/webview_window_darwin.m @@ -48,14 +48,6 @@ extern bool hasListeners(unsigned int); } @end @implementation WebviewWindowDelegate -- (BOOL)windowShouldClose:(NSWindow *)sender { - if( self.hideOnClose ) { - [sender orderOut:nil]; - return false; - } - processWindowEvent(self.windowId, EventWindowShouldClose); - return false; -} - (void) dealloc { // Makes sure to remove the retained properties so the reference counter of the retains are decreased self.leftMouseEvent = nil; @@ -381,6 +373,12 @@ extern bool hasListeners(unsigned int); } } +- (void)windowShouldClose:(NSNotification *)notification { + if( hasListeners(EventWindowShouldClose) ) { + processWindowEvent(self.windowId, EventWindowShouldClose); + } +} + - (void)windowWillBecomeKey:(NSNotification *)notification { if( hasListeners(EventWindowWillBecomeKey) ) { processWindowEvent(self.windowId, EventWindowWillBecomeKey); diff --git a/v3/pkg/application/webview_window_windows.go b/v3/pkg/application/webview_window_windows.go index f269195c1..1b30361e5 100644 --- a/v3/pkg/application/webview_window_windows.go +++ b/v3/pkg/application/webview_window_windows.go @@ -390,6 +390,9 @@ func (w *windowsWebviewWindow) setZoom(zoom float64) { } func (w *windowsWebviewWindow) close() { + // Unregister the window with the application + windowsApp := globalApplication.impl.(*windowsApp) + windowsApp.unregisterWindow(w) w32.SendMessage(w.hwnd, w32.WM_CLOSE, 0, 0) } @@ -694,14 +697,8 @@ func (w *windowsWebviewWindow) WndProc(msg uint32, wparam, lparam uintptr) uintp w32.ExtendFrameIntoClientArea(w.hwnd, true) } case w32.WM_CLOSE: - if w.parent.options.HideOnClose { - w.hide() - return 0 // Do not let the DefWindowProc allow to close us - } - - // Unregister the window with the application - windowsApp := globalApplication.impl.(*windowsApp) - windowsApp.unregisterWindow(w) + w.parent.emit(events.Common.WindowClosing) + return 0 case w32.WM_NCLBUTTONDOWN: w32.SetFocus(w.hwnd) case w32.WM_MOVE, w32.WM_MOVING: @@ -729,6 +726,7 @@ func (w *windowsWebviewWindow) WndProc(msg uint32, wparam, lparam uintptr) uintp } else { w.chromium.Resize() } + return 0 case w32.WM_GETMINMAXINFO: mmi := (*w32.MINMAXINFO)(unsafe.Pointer(lparam)) diff --git a/v3/pkg/events/events.go b/v3/pkg/events/events.go index db74af9f7..fa5030145 100644 --- a/v3/pkg/events/events.go +++ b/v3/pkg/events/events.go @@ -18,7 +18,7 @@ type commonEvents struct { WindowRestore WindowEventType WindowMinimise WindowEventType WindowUnMinimise WindowEventType - WindowClose WindowEventType + WindowClosing WindowEventType WindowZoom WindowEventType WindowZoomIn WindowEventType WindowZoomOut WindowEventType @@ -39,7 +39,7 @@ func newCommonEvents() commonEvents { WindowRestore: 1159, WindowMinimise: 1160, WindowUnMinimise: 1161, - WindowClose: 1162, + WindowClosing: 1162, WindowZoom: 1163, WindowZoomIn: 1164, WindowZoomOut: 1165, diff --git a/v3/pkg/events/events.txt b/v3/pkg/events/events.txt index 167342cae..8f579f20e 100644 --- a/v3/pkg/events/events.txt +++ b/v3/pkg/events/events.txt @@ -63,7 +63,7 @@ mac:WindowDidUpdateShadow mac:WindowDidUpdateTitle mac:WindowDidUpdateToolbar mac:WindowDidUpdateVisibility -mac:WindowShouldClose! +mac:WindowShouldClose mac:WindowWillBecomeKey mac:WindowWillBecomeMain mac:WindowWillBeginSheet @@ -136,7 +136,7 @@ common:WindowUnFullscreen common:WindowRestore common:WindowMinimise common:WindowUnMinimise -common:WindowClose +common:WindowClosing common:WindowZoom common:WindowZoomIn common:WindowZoomOut