From 70ebd34d9936b4fe3bd9be84db79d075b4d0e806 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 25 Sep 2022 22:51:09 +0900 Subject: [PATCH] internal/ui: refactoring: separate setWindowSizeInDIPImpl to setWindowSizeInDIP and setFullscreen --- internal/ui/ui_glfw.go | 97 ++++++++++++++++++++-------------- internal/ui/ui_glfw_darwin.go | 5 +- internal/ui/ui_glfw_unix.go | 2 +- internal/ui/ui_glfw_windows.go | 2 +- 4 files changed, 62 insertions(+), 44 deletions(-) diff --git a/internal/ui/ui_glfw.go b/internal/ui/ui_glfw.go index 359df60a8..05a00af4d 100644 --- a/internal/ui/ui_glfw.go +++ b/internal/ui/ui_glfw.go @@ -737,7 +737,7 @@ func (u *userInterfaceImpl) registerWindowSetSizeCallback() { return } - u.adjustViewSize() + u.adjustViewSizeAfterFullscreen() if u.window.GetAttrib(glfw.Resizable) == glfw.False { return @@ -1272,11 +1272,22 @@ func (u *userInterfaceImpl) setWindowSizeInDIP(width, height int) { }() } - u.setWindowSizeInDIPImpl(width, height, u.isFullscreen()) + if !u.isFullscreen() { + // Set the window size after the position. The order matters. + // In the opposite order, the window size might not be correct when going back from fullscreen with multi monitors. + oldW, oldH := u.window.GetSize() + newW := int(u.dipToGLFWPixel(float64(width), u.currentMonitor())) + newH := int(u.dipToGLFWPixel(float64(height), u.currentMonitor())) + if oldW != newW || oldH != newH { + // Just after SetSize, GetSize is not reliable especially on Linux/UNIX. + // Let's wait for FramebufferSize callback in any cases. + u.waitForFramebufferSizeCallback(u.window, func() { + u.window.SetSize(newW, newH) + }) + } + } u.updateWindowSizeLimits() - - u.adjustViewSize() } // setFullscreen must be called from the main thread. @@ -1285,27 +1296,19 @@ func (u *userInterfaceImpl) setFullscreen(fullscreen bool) { return } u.graphicsDriver.SetFullscreen(fullscreen) - u.setWindowSizeInDIPImpl(u.origWindowWidthInDIP, u.origWindowHeightInDIP, fullscreen) -} -func (u *userInterfaceImpl) minimumWindowWidth() int { - if u.window.GetAttrib(glfw.Decorated) == glfw.False { - return 1 + // Disable the callback of SetSize. This callback can be invoked by SetMonitor or SetSize. + // ForceUpdateFrame is called from the callback. + // While setWindowSize can be called from UpdateFrame, + // calling ForceUpdateFrame inside UpdateFrame is illegal (#1505). + if u.setSizeCallbackEnabled { + u.setSizeCallbackEnabled = false + defer func() { + u.setSizeCallbackEnabled = true + }() } - // On Windows, giving a too small width doesn't call a callback (#165). - // To prevent hanging up, return asap if the width is too small. - // 126 is an arbitrary number and I guess this is small enough . - if runtime.GOOS == "windows" { - return 126 - } - - // On macOS, resizing the window by cursor sometimes ignores the minimum size. - // To avoid the flaky behavior, do not add a limitation. - return 1 -} - -func (u *userInterfaceImpl) setWindowSizeInDIPImpl(width, height int, fullscreen bool) { + // Enter the fullscreen. if fullscreen { if x, y := u.origWindowPos(); x == invalidPos || y == invalidPos { u.setOrigWindowPos(u.window.GetPos()) @@ -1329,27 +1332,29 @@ func (u *userInterfaceImpl) setWindowSizeInDIPImpl(width, height int, fullscreen u.swapBuffers() } } + u.adjustViewSizeAfterFullscreen() return } + // Exit the fullscreen. + // Get the original window position and size before changing the state of fullscreen. + // TODO: Why? origX, origY := u.origWindowPos() - wasFullscreen := u.isFullscreen() - if u.isNativeFullscreenAvailable() && u.isNativeFullscreen() { + ww := int(u.dipToGLFWPixel(float64(u.origWindowWidthInDIP), u.currentMonitor())) + wh := int(u.dipToGLFWPixel(float64(u.origWindowHeightInDIP), u.currentMonitor())) + if u.isNativeFullscreenAvailable() { u.setNativeFullscreen(false) + // Adjust the window size later (after adjusting the position). } else if !u.isNativeFullscreenAvailable() && u.window.GetMonitor() != nil { - ww := int(u.dipToGLFWPixel(float64(width), u.currentMonitor())) - wh := int(u.dipToGLFWPixel(float64(height), u.currentMonitor())) u.window.SetMonitor(nil, 0, 0, ww, wh, 0) glfw.PollEvents() u.swapBuffers() } - if wasFullscreen { - // glfw.PollEvents is necessary for macOS to enable (*glfw.Window).SetPos and SetSize (#2296). - glfw.PollEvents() - } + // glfw.PollEvents is necessary for macOS to enable (*glfw.Window).SetPos and SetSize (#2296). + glfw.PollEvents() if origX != invalidPos && origY != invalidPos { u.window.SetPos(origX, origY) @@ -1362,20 +1367,30 @@ func (u *userInterfaceImpl) setWindowSizeInDIPImpl(width, height int, fullscreen u.setOrigWindowPos(invalidPos, invalidPos) } - // Set the window size after the position. The order matters. - // In the opposite order, the window size might not be correct when going back from fullscreen with multi monitors. - oldW, oldH := u.window.GetSize() - newW := int(u.dipToGLFWPixel(float64(width), u.currentMonitor())) - newH := int(u.dipToGLFWPixel(float64(height), u.currentMonitor())) - if oldW != newW || oldH != newH { - // Just after SetSize, GetSize is not reliable especially on Linux/UNIX. - // Let's wait for FramebufferSize callback in any cases. - u.waitForFramebufferSizeCallback(u.window, func() { - u.window.SetSize(newW, newH) - }) + if u.isNativeFullscreenAvailable() { + // Set the window size after the position. The order matters. + // In the opposite order, the window size might not be correct when going back from fullscreen with multi monitors. + u.window.SetSize(ww, wh) } } +func (u *userInterfaceImpl) minimumWindowWidth() int { + if u.window.GetAttrib(glfw.Decorated) == glfw.False { + return 1 + } + + // On Windows, giving a too small width doesn't call a callback (#165). + // To prevent hanging up, return asap if the width is too small. + // 126 is an arbitrary number and I guess this is small enough . + if runtime.GOOS == "windows" { + return 126 + } + + // On macOS, resizing the window by cursor sometimes ignores the minimum size. + // To avoid the flaky behavior, do not add a limitation. + return 1 +} + // updateVsync must be called on the main thread. func (u *userInterfaceImpl) updateVsync() { if u.graphicsDriver.IsGL() { diff --git a/internal/ui/ui_glfw_darwin.go b/internal/ui/ui_glfw_darwin.go index 2aecf9a55..8f2e9a389 100644 --- a/internal/ui/ui_glfw_darwin.go +++ b/internal/ui/ui_glfw_darwin.go @@ -290,14 +290,16 @@ func (u *userInterfaceImpl) setNativeFullscreen(fullscreen bool) { } } -func (u *userInterfaceImpl) adjustViewSize() { +func (u *userInterfaceImpl) adjustViewSizeAfterFullscreen() { if u.graphicsDriver.IsGL() { return } + window := cocoa.NSWindow{ID: objc.ID(u.window.GetCocoaWindow())} if window.StyleMask()&cocoa.NSWindowStyleMaskFullScreen == 0 { return } + // Apparently, adjusting the view size is not needed as of macOS 12 (#1745). if cocoa.NSProcessInfo_processInfo().IsOperatingSystemAtLeastVersion(cocoa.NSOperatingSystemVersion{ Major: 12, @@ -315,6 +317,7 @@ func (u *userInterfaceImpl) adjustViewSize() { } viewSize.Width-- view.SetFrameSize(viewSize) + // NSColor.blackColor (0, 0, 0, 1) didn't work. // Use the transparent color instead. window.SetBackgroundColor(cocoa.NSColor_colorWithSRGBRedGreenBlueAlpha(0, 0, 0, 0)) diff --git a/internal/ui/ui_glfw_unix.go b/internal/ui/ui_glfw_unix.go index ff2f952c0..af0a3e7a7 100644 --- a/internal/ui/ui_glfw_unix.go +++ b/internal/ui/ui_glfw_unix.go @@ -214,7 +214,7 @@ func (u *userInterfaceImpl) setNativeFullscreen(fullscreen bool) { panic(fmt.Sprintf("ui: setNativeFullscreen is not implemented in this environment: %s", runtime.GOOS)) } -func (u *userInterfaceImpl) adjustViewSize() { +func (u *userInterfaceImpl) adjustViewSizeAfterFullscreen() { } func (u *userInterfaceImpl) setWindowResizingModeForOS(mode WindowResizingMode) { diff --git a/internal/ui/ui_glfw_windows.go b/internal/ui/ui_glfw_windows.go index 7ebf67c96..9350104ad 100644 --- a/internal/ui/ui_glfw_windows.go +++ b/internal/ui/ui_glfw_windows.go @@ -178,7 +178,7 @@ func (u *userInterfaceImpl) setNativeFullscreen(fullscreen bool) { panic(fmt.Sprintf("ui: setNativeFullscreen is not implemented in this environment: %s", runtime.GOOS)) } -func (u *userInterfaceImpl) adjustViewSize() { +func (u *userInterfaceImpl) adjustViewSizeAfterFullscreen() { } func (u *userInterfaceImpl) setWindowResizingModeForOS(mode WindowResizingMode) {