This is an automated email from the ASF dual-hosted git repository.

hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-gateway.git

commit 5378983355409066acf2c9f0b328008f8008e146
Author: Yang Luo <[email protected]>
AuthorDate: Mon Aug 24 22:42:21 2026 +0800

    fix(desktop): hide the window on close so reopening is instant
---
 desktop/focus_windows.go  | 83 +++++++++++++++++++++++++++++++++--------------
 desktop/hide_windows.go   | 43 +++++++++++-------------
 desktop/window_windows.go |  5 ++-
 3 files changed, 82 insertions(+), 49 deletions(-)

diff --git a/desktop/focus_windows.go b/desktop/focus_windows.go
index 1cf4aaf..a249f9a 100644
--- a/desktop/focus_windows.go
+++ b/desktop/focus_windows.go
@@ -12,13 +12,26 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+
 package main
 
 import (
+       "sync"
        "syscall"
        "unsafe"
 )
 
+// webviewClass is the window class go-webview2 registers. The window is looked
+// up by class rather than by "is it visible", because the whole point is to
+// find it again once closing has hidden it.
+const webviewClass = "webview"
+
+const (
+       swHide    = 0
+       swShow    = 5
+       swRestore = 9
+)
+
 var (
        shell32 = syscall.NewLazyDLL("shell32.dll")
        user32  = syscall.NewLazyDLL("user32.dll")
@@ -26,13 +39,12 @@ var (
        procSetAppId            = 
shell32.NewProc("SetCurrentProcessExplicitAppUserModelID")
        procEnumWindows         = user32.NewProc("EnumWindows")
        procGetWindowThreadPid  = user32.NewProc("GetWindowThreadProcessId")
-       procIsWindowVisible     = user32.NewProc("IsWindowVisible")
+       procGetClassNameW       = user32.NewProc("GetClassNameW")
+       procIsIconic            = user32.NewProc("IsIconic")
        procShowWindow          = user32.NewProc("ShowWindow")
        procSetForegroundWindow = user32.NewProc("SetForegroundWindow")
 )
 
-const swRestore = 9
-
 func setAppUserModelId() {
        id, err := syscall.UTF16PtrFromString(appId)
        if err != nil {
@@ -41,30 +53,53 @@ func setAppUserModelId() {
        _, _, _ = procSetAppId.Call(uintptr(unsafe.Pointer(id)))
 }
 
-// focusWindow raises the window process's own window, so that clicking the 
tray
-// while it is already open brings it to the front instead of doing nothing.
+// focusWindow shows the window process's own window and raises it, so that
+// clicking the tray brings back the window the user closed — the same one, 
with
+// the page still loaded — rather than starting over.
 func focusWindow(pid int) {
-       var found uintptr
+       hwnd := findWindow(pid)
+       if hwnd == 0 {
+               return
+       }
 
-       callback := syscall.NewCallback(func(hwnd uintptr, _ uintptr) uintptr {
-               visible, _, _ := procIsWindowVisible.Call(hwnd)
-               if visible == 0 {
-                       return 1
-               }
-               var owner uint32
-               _, _, _ = procGetWindowThreadPid.Call(hwnd, 
uintptr(unsafe.Pointer(&owner)))
-               if owner != uint32(pid) {
-                       return 1
-               }
-               found = hwnd
-               return 0
-       })
+       show := uintptr(swShow)
+       if iconic, _, _ := procIsIconic.Call(hwnd); iconic != 0 {
+               show = swRestore
+       }
+       _, _, _ = procShowWindow.Call(hwnd, show)
+       _, _, _ = procSetForegroundWindow.Call(hwnd)
+}
 
-       _, _, _ = procEnumWindows.Call(callback, 0)
-       if found == 0 {
-               return
+// search is package level because syscall.NewCallback allocates a callback 
that
+// is never freed, so the enumeration cannot make one per click.
+var search struct {
+       sync.Mutex
+       pid   uint32
+       found uintptr
+}
+
+var enumWindowsCallback = syscall.NewCallback(func(hwnd, _ uintptr) uintptr {
+       var owner uint32
+       _, _, _ = procGetWindowThreadPid.Call(hwnd, 
uintptr(unsafe.Pointer(&owner)))
+       if owner != search.pid || windowClass(hwnd) != webviewClass {
+               return 1
        }
+       search.found = hwnd
+       return 0
+})
+
+func findWindow(pid int) uintptr {
+       search.Lock()
+       defer search.Unlock()
+
+       search.pid = uint32(pid)
+       search.found = 0
+       _, _, _ = procEnumWindows.Call(enumWindowsCallback, 0)
+       return search.found
+}
 
-       _, _, _ = procShowWindow.Call(found, swRestore)
-       _, _, _ = procSetForegroundWindow.Call(found)
+func windowClass(hwnd uintptr) string {
+       var name [64]uint16
+       n, _, _ := procGetClassNameW.Call(hwnd, 
uintptr(unsafe.Pointer(&name[0])), uintptr(len(name)))
+       return syscall.UTF16ToString(name[:n])
 }
diff --git a/desktop/hide_windows.go b/desktop/hide_windows.go
index b42d365..cb20788 100644
--- a/desktop/hide_windows.go
+++ b/desktop/hide_windows.go
@@ -12,44 +12,39 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+
 package main
 
-import "syscall"
+import (
+       "syscall"
+       "unsafe"
+)
 
 const (
        wmClose     = 0x0010
-       swHide      = 0
-       swShow      = 5
-       swRestore   = 9
        gwlpWndProc = ^uintptr(3) // GWLP_WNDPROC, which is -4
 
        // DWMWA_TRANSITIONS_FORCEDISABLED, which turns off the animation the 
window
-       // manager plays when a window is shown, hidden or restored.
+       // manager plays when a window is shown, hidden, minimized or restored.
        dwmTransitionsForceDisabled = 3
 )
 
 var (
        dwmapi = syscall.NewLazyDLL("dwmapi.dll")
 
-       procSetWindowLongPtrW    = user32.NewProc("SetWindowLongPtrW")
-       procSetWindowLongW       = user32.NewProc("SetWindowLongW")
-       procCallWindowProcW      = user32.NewProc("CallWindowProcW")
-       procDwmSetWindowAttrib   = dwmapi.NewProc("DwmSetWindowAttribute")
-       procIsIconic             = user32.NewProc("IsIconic")
-       procBringWindowToTop     = user32.NewProc("BringWindowToTop")
-       procAttachThreadInput    = user32.NewProc("AttachThreadInput")
-       procGetForegroundWindow  = user32.NewProc("GetForegroundWindow")
-       procGetCurrentThreadId   = kernel32.NewProc("GetCurrentThreadId")
-       kernel32                 = syscall.NewLazyDLL("kernel32.dll")
-       previousWindowProc       uintptr
-       hideOnCloseProcCallback  = syscall.NewCallback(hideOnClose)
+       procSetWindowLongPtrW  = user32.NewProc("SetWindowLongPtrW")
+       procSetWindowLongW     = user32.NewProc("SetWindowLongW")
+       procCallWindowProcW    = user32.NewProc("CallWindowProcW")
+       procDwmSetWindowAttrib = dwmapi.NewProc("DwmSetWindowAttribute")
+
+       previousWindowProc  uintptr
+       hideOnCloseCallback = syscall.NewCallback(hideOnClose)
 )
 
 // keepWindowAlive makes closing the window hide it instead of destroying it.
-// The webview's own window procedure answers WM_CLOSE with DestroyWindow, 
which
-// ends the run loop and the process with it — which is why reopening from the
-// tray used to reload everything from scratch. Hiding keeps the page loaded, 
so
-// the window comes back instantly.
+// The webview answers WM_CLOSE with DestroyWindow, which ends the run loop and
+// the process with it — which is why reopening from the tray reloaded the 
whole
+// UI. Hiding keeps the page loaded, so the window comes back instantly.
 func keepWindowAlive(hwnd uintptr) {
        if hwnd == 0 {
                return
@@ -66,7 +61,7 @@ func keepWindowAlive(hwnd uintptr) {
                return
        }
 
-       previousWindowProc, _, _ = setLong.Call(hwnd, gwlpWndProc, 
hideOnCloseProcCallback)
+       previousWindowProc, _, _ = setLong.Call(hwnd, gwlpWndProc, 
hideOnCloseCallback)
 }
 
 func hideOnClose(hwnd, msg, wparam, lparam uintptr) uintptr {
@@ -88,7 +83,7 @@ func disableWindowAnimations(hwnd uintptr) {
        _, _, _ = procDwmSetWindowAttrib.Call(
                hwnd,
                dwmTransitionsForceDisabled,
-               uintptr(unsafePointerTo(&disabled)),
-               4,
+               uintptr(unsafe.Pointer(&disabled)),
+               unsafe.Sizeof(disabled),
        )
 }
diff --git a/desktop/window_windows.go b/desktop/window_windows.go
index fe45551..8acefe4 100644
--- a/desktop/window_windows.go
+++ b/desktop/window_windows.go
@@ -70,7 +70,10 @@ func runWindow(url string) error {
        }
        defer view.Destroy()
 
-       setWindowIcon(uintptr(view.Window()))
+       hwnd := uintptr(view.Window())
+       setWindowIcon(hwnd)
+       keepWindowAlive(hwnd)
+
        view.Navigate(url)
        view.Run()
        return nil


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to