diff --git a/internal/uidriver/glfw/ui_windows.go b/internal/uidriver/glfw/ui_windows.go index b15c8df6e..e3f044b8c 100644 --- a/internal/uidriver/glfw/ui_windows.go +++ b/internal/uidriver/glfw/ui_windows.go @@ -44,9 +44,11 @@ type monitorInfo struct { var ( // user32 is defined at hideconsole_windows.go - procGetSystemMetrics = user32.NewProc("GetSystemMetrics") - procMonitorFromWindow = user32.NewProc("MonitorFromWindow") - procGetMonitorInfoW = user32.NewProc("GetMonitorInfoW") + procGetSystemMetrics = user32.NewProc("GetSystemMetrics") + procGetActiveWindow = user32.NewProc("GetActiveWindow") + procGetForegroundWindow = user32.NewProc("GetForegroundWindow") + procMonitorFromWindow = user32.NewProc("MonitorFromWindow") + procGetMonitorInfoW = user32.NewProc("GetMonitorInfoW") ) func getSystemMetrics(nIndex int) (int, error) { @@ -57,6 +59,22 @@ func getSystemMetrics(nIndex int) (int, error) { return int(r), nil } +func getActiveWindow() (uintptr, error) { + r, _, e := procGetActiveWindow.Call() + if e != nil && e.(windows.Errno) != 0 { + return 0, fmt.Errorf("ui: GetActiveWindow failed: error code: %d", e) + } + return r, nil +} + +func getForegroundWindow() (uintptr, error) { + r, _, e := procGetForegroundWindow.Call() + if e != nil && e.(windows.Errno) != 0 { + return 0, fmt.Errorf("ui: GetForegroundWindow failed: error code: %d", e) + } + return r, nil +} + func monitorFromWindow(hwnd uintptr, dwFlags uint32) (uintptr, error) { r, _, e := procMonitorFromWindow.Call(hwnd, uintptr(dwFlags)) if e != nil && e.(windows.Errno) != 0 { @@ -116,11 +134,30 @@ func (u *UserInterface) adjustWindowPosition(x, y int) (int, int) { return x, y } -func currentMonitorByOS(w *glfw.Window) *glfw.Monitor { +func currentMonitorByOS(_ *glfw.Window) *glfw.Monitor { + // TODO: Should we return nil here? + w, err := getActiveWindow() + if err != nil { + panic(err) + } + + if w == 0 { + // The active window doesn't exist when launching, or the application is runnable on unfocused. + // Get the foreground window, that is common among multiple processes. + w, err = getForegroundWindow() + if err != nil { + panic(err) + } + if w == 0 { + // GetForegroundWindow can return null according to the document. + return nil + } + } + // Get the current monitor by the window handle instead of the window position. It is because the window // position is not relaiable in some cases e.g. when the window is put across multiple monitors. - m, err := monitorFromWindow(w.GetWin32Window(), monitorDefaultToNearest) + m, err := monitorFromWindow(w, monitorDefaultToNearest) if err != nil { // monitorFromWindow can return error on Wine. Ignore this. return nil