diff --git a/v3/examples/window/main.go b/v3/examples/window/main.go index 78b45f9f9..8d325344b 100644 --- a/v3/examples/window/main.go +++ b/v3/examples/window/main.go @@ -321,6 +321,15 @@ func main() { }) }) + if runtime.GOOS == "windows" { + stateMenu.Add("Flash Start").OnClick(func(ctx *application.Context) { + currentWindow(func(w *application.WebviewWindow) { + time.Sleep(2 * time.Second) + w.Flash(true) + }) + }) + } + printMenu := menu.AddSubmenu("Print") printMenu.Add("Print").OnClick(func(ctx *application.Context) { currentWindow(func(w *application.WebviewWindow) { diff --git a/v3/pkg/application/webview_window.go b/v3/pkg/application/webview_window.go index 9577a983b..333282a3a 100644 --- a/v3/pkg/application/webview_window.go +++ b/v3/pkg/application/webview_window.go @@ -70,6 +70,7 @@ type ( setEnabled(enabled bool) absolutePosition() (int, int) setAbsolutePosition(x int, y int) + flash(enabled bool) } ) @@ -418,6 +419,16 @@ func (w *WebviewWindow) SetFullscreenButtonEnabled(enabled bool) *WebviewWindow return w } +// Flash flashes the window's taskbar button/icon. Windows only. +func (w *WebviewWindow) Flash(enabled bool) { + if w.impl == nil { + return + } + invokeSync(func() { + w.impl.flash(enabled) + }) +} + // IsMinimised returns true if the window is minimised func (w *WebviewWindow) IsMinimised() bool { if w.impl == nil { diff --git a/v3/pkg/application/webview_window_darwin.go b/v3/pkg/application/webview_window_darwin.go index dfb905a35..6c3d1839e 100644 --- a/v3/pkg/application/webview_window_darwin.go +++ b/v3/pkg/application/webview_window_darwin.go @@ -944,6 +944,10 @@ func (w *macosWebviewWindow) setTitle(title string) { } } +func (w *macosWebviewWindow) flash(enabled bool) { + // Not supported on macOS +} + func (w *macosWebviewWindow) setSize(width, height int) { C.windowSetSize(w.nsWindow, C.int(width), C.int(height)) } diff --git a/v3/pkg/application/webview_window_linux.go b/v3/pkg/application/webview_window_linux.go index e2fe95ed9..fe6ddc808 100644 --- a/v3/pkg/application/webview_window_linux.go +++ b/v3/pkg/application/webview_window_linux.go @@ -179,6 +179,10 @@ func (w *linuxWebviewWindow) minimise() { windowMinimize(w.window) } +func (w *linuxWebviewWindow) flash(enabled bool) { + // Not supported on linux +} + func (w *linuxWebviewWindow) on(eventID uint) { // Don't think this is correct! // GTK Events are strings diff --git a/v3/pkg/application/webview_window_windows.go b/v3/pkg/application/webview_window_windows.go index 4d666c5f5..7c80d68a5 100644 --- a/v3/pkg/application/webview_window_windows.go +++ b/v3/pkg/application/webview_window_windows.go @@ -1464,6 +1464,10 @@ func (w *windowsWebviewWindow) setupChromium() { } +func (w *windowsWebviewWindow) flash(enabled bool) { + w32.FlashWindow(w.hwnd, enabled) +} + func (w *windowsWebviewWindow) navigationCompleted(sender *edge.ICoreWebView2, args *edge.ICoreWebView2NavigationCompletedEventArgs) { // Emit DomReady Event diff --git a/v3/pkg/w32/constants.go b/v3/pkg/w32/constants.go index 39097db1e..f6cab85c8 100644 --- a/v3/pkg/w32/constants.go +++ b/v3/pkg/w32/constants.go @@ -915,6 +915,15 @@ const ( SS_ELLIPSISMASK = 0x0000C000 ) +const ( + FLASHW_STOP = 0 // Stop flashing. The system restores the window to its original state. + FLASHW_CAPTION = 1 // Flash the window caption. + FLASHW_TRAY = 2 // Flash the taskbar button. + FLASHW_ALL = 3 // Flash both the window caption and taskbar button. This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags. + FLASHW_TIMER = 4 // Flash continuously, until the FLASHW_STOP flag is set. + FLASHW_TIMERNOFG = 12 // Flash continuously until the window comes to the foreground. +) + // Edit styles const ( ES_LEFT = 0x0000 diff --git a/v3/pkg/w32/typedef.go b/v3/pkg/w32/typedef.go index db02dacfc..433a375b3 100644 --- a/v3/pkg/w32/typedef.go +++ b/v3/pkg/w32/typedef.go @@ -1133,3 +1133,11 @@ type SCROLLINFO struct { NPos int32 NTrackPos int32 } + +type FLASHWINFO struct { + CbSize uint32 + Hwnd HWND + DwFlags DWORD + UCount uint32 + DwTimeout DWORD +} diff --git a/v3/pkg/w32/user32.go b/v3/pkg/w32/user32.go index 10ad2ddd1..6d0048253 100644 --- a/v3/pkg/w32/user32.go +++ b/v3/pkg/w32/user32.go @@ -166,6 +166,8 @@ var ( procGetScrollInfo = moduser32.NewProc("GetScrollInfo") procSetScrollInfo = moduser32.NewProc("SetScrollInfo") + procFlashWindowEx = moduser32.NewProc("FlashWindowEx") + mainThread HANDLE ) diff --git a/v3/pkg/w32/window.go b/v3/pkg/w32/window.go index f33ae3acb..b76d049d8 100644 --- a/v3/pkg/w32/window.go +++ b/v3/pkg/w32/window.go @@ -234,3 +234,15 @@ func RegisterWindow(name string, proc WindowProc) (HINSTANCE, error) { return applicationInstance, nil } + +func FlashWindow(hwnd HWND, enabled bool) { + var flashInfo FLASHWINFO + flashInfo.CbSize = uint32(unsafe.Sizeof(flashInfo)) + flashInfo.Hwnd = hwnd + if enabled { + flashInfo.DwFlags = FLASHW_ALL | FLASHW_TIMERNOFG + } else { + flashInfo.DwFlags = FLASHW_STOP + } + _, _, _ = procFlashWindowEx.Call(uintptr(unsafe.Pointer(&flashInfo))) +}