mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 03:38:55 +01:00
internal/uidriver/glfw: Make a 'native' fullscreen on macOS
This is a breaking change. On macOS, `SetFullscreen` creates a new independent space and maximize the size of the window there. Updates #1506 Closes #1579
This commit is contained in:
parent
2a390c18c1
commit
428c079e52
@ -351,6 +351,10 @@ func WaitEvents() {
|
|||||||
glfw.WaitEvents()
|
glfw.WaitEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WaitEventsTimeout(timeout float64) {
|
||||||
|
glfw.WaitEventsTimeout(timeout)
|
||||||
|
}
|
||||||
|
|
||||||
func WindowHint(target Hint, hint int) {
|
func WindowHint(target Hint, hint int) {
|
||||||
glfw.WindowHint(glfw.Hint(target), hint)
|
glfw.WindowHint(glfw.Hint(target), hint)
|
||||||
}
|
}
|
||||||
|
@ -545,7 +545,7 @@ func (u *UserInterface) isFullscreen() bool {
|
|||||||
if !u.isRunning() {
|
if !u.isRunning() {
|
||||||
panic("glfw: isFullscreen can't be called before the main loop starts")
|
panic("glfw: isFullscreen can't be called before the main loop starts")
|
||||||
}
|
}
|
||||||
return u.window.GetMonitor() != nil
|
return u.window.GetMonitor() != nil || u.isNativeFullscreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInterface) IsFullscreen() bool {
|
func (u *UserInterface) IsFullscreen() bool {
|
||||||
@ -576,10 +576,6 @@ func (u *UserInterface) SetFullscreen(fullscreen bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ = u.t.Call(func() error {
|
_ = u.t.Call(func() error {
|
||||||
if u.isNativeFullscreen() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
w, h := u.windowWidth, u.windowHeight
|
w, h := u.windowWidth, u.windowHeight
|
||||||
u.setWindowSize(w, h, fullscreen)
|
u.setWindowSize(w, h, fullscreen)
|
||||||
return nil
|
return nil
|
||||||
@ -783,7 +779,7 @@ func (u *UserInterface) registerWindowSetSizeCallback() {
|
|||||||
if u.window.GetAttrib(glfw.Resizable) == glfw.False {
|
if u.window.GetAttrib(glfw.Resizable) == glfw.False {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if u.isFullscreen() {
|
if u.isFullscreen() && !u.isNativeFullscreen() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -849,8 +845,8 @@ func (u *UserInterface) init() error {
|
|||||||
glfw.WindowHint(glfw.ClientAPI, glfw.NoAPI)
|
glfw.WindowHint(glfw.ClientAPI, glfw.NoAPI)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable auto-iconifying on Windows and macOS until some fullscreen issues are solved (#1506).
|
// Enable auto-iconifying on Windows until some fullscreen issues are solved (#1506).
|
||||||
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
if runtime.GOOS == "windows" {
|
||||||
glfw.WindowHint(glfw.AutoIconify, glfw.True)
|
glfw.WindowHint(glfw.AutoIconify, glfw.True)
|
||||||
} else {
|
} else {
|
||||||
glfw.WindowHint(glfw.AutoIconify, glfw.False)
|
glfw.WindowHint(glfw.AutoIconify, glfw.False)
|
||||||
@ -1205,7 +1201,7 @@ func (u *UserInterface) adjustWindowSizeBasedOnSizeLimitsInDP(width, height int)
|
|||||||
func (u *UserInterface) setWindowSize(width, height int, fullscreen bool) {
|
func (u *UserInterface) setWindowSize(width, height int, fullscreen bool) {
|
||||||
width, height = u.adjustWindowSizeBasedOnSizeLimits(width, height)
|
width, height = u.adjustWindowSizeBasedOnSizeLimits(width, height)
|
||||||
|
|
||||||
u.Graphics().SetFullscreen(fullscreen || u.isNativeFullscreen())
|
u.Graphics().SetFullscreen(fullscreen)
|
||||||
|
|
||||||
if u.windowWidth == width && u.windowHeight == height && u.isFullscreen() == fullscreen && u.lastDeviceScaleFactor == u.deviceScaleFactor() {
|
if u.windowWidth == width && u.windowHeight == height && u.isFullscreen() == fullscreen && u.lastDeviceScaleFactor == u.deviceScaleFactor() {
|
||||||
return
|
return
|
||||||
@ -1235,12 +1231,32 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
windowRecreated := u.setWindowSizeImpl(width, height, fullscreen)
|
||||||
|
|
||||||
|
// As width might be updated, update windowWidth/Height here.
|
||||||
|
u.windowWidth = width
|
||||||
|
u.windowHeight = height
|
||||||
|
|
||||||
|
u.toChangeSize = true
|
||||||
|
|
||||||
|
if windowRecreated {
|
||||||
|
if g, ok := u.Graphics().(interface{ SetWindow(uintptr) }); ok {
|
||||||
|
g.SetWindow(u.nativeWindow())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) setWindowSizeImpl(width, height int, fullscreen bool) bool {
|
||||||
var windowRecreated bool
|
var windowRecreated bool
|
||||||
|
|
||||||
if fullscreen {
|
if fullscreen {
|
||||||
if u.origPosX == invalidPos || u.origPosY == invalidPos {
|
if x, y := u.origPos(); x == invalidPos || y == invalidPos {
|
||||||
u.origPosX, u.origPosY = u.window.GetPos()
|
u.setOrigPos(u.window.GetPos())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if u.isNativeFullscreenAvailable() {
|
||||||
|
u.setNativeFullscreen(fullscreen)
|
||||||
|
} else {
|
||||||
m := currentMonitor(u.window)
|
m := currentMonitor(u.window)
|
||||||
v := m.GetVideoMode()
|
v := m.GetVideoMode()
|
||||||
u.window.SetMonitor(m, 0, 0, v.Width, v.Height, v.RefreshRate)
|
u.window.SetMonitor(m, 0, 0, v.Width, v.Height, v.RefreshRate)
|
||||||
@ -1251,6 +1267,7 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool) {
|
|||||||
glfw.PollEvents()
|
glfw.PollEvents()
|
||||||
u.swapBuffers()
|
u.swapBuffers()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// On Windows, giving a too small width doesn't call a callback (#165).
|
// 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.
|
// To prevent hanging up, return asap if the width is too small.
|
||||||
@ -1263,7 +1280,9 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool) {
|
|||||||
width = minWindowWidth
|
width = minWindowWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.window.GetMonitor() != nil {
|
if u.isNativeFullscreenAvailable() && u.isNativeFullscreen() {
|
||||||
|
u.setNativeFullscreen(false)
|
||||||
|
} else if !u.isNativeFullscreenAvailable() && u.window.GetMonitor() != nil {
|
||||||
if u.Graphics().IsGL() {
|
if u.Graphics().IsGL() {
|
||||||
// When OpenGL is used, swapping buffer is enough to solve the image-lag
|
// When OpenGL is used, swapping buffer is enough to solve the image-lag
|
||||||
// issue (#1004). Rather, recreating window destroys GPU resources.
|
// issue (#1004). Rather, recreating window destroys GPU resources.
|
||||||
@ -1289,9 +1308,7 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.origPosX != invalidPos && u.origPosY != invalidPos {
|
if x, y := u.origPos(); x != invalidPos && y != invalidPos {
|
||||||
x := u.origPosX
|
|
||||||
y := u.origPosY
|
|
||||||
u.window.SetPos(x, y)
|
u.window.SetPos(x, y)
|
||||||
// Dirty hack for macOS (#703). Rendering doesn't work correctly with one SetPos, but
|
// Dirty hack for macOS (#703). Rendering doesn't work correctly with one SetPos, but
|
||||||
// work with two or more SetPos.
|
// work with two or more SetPos.
|
||||||
@ -1299,8 +1316,7 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool) {
|
|||||||
u.window.SetPos(x+1, y)
|
u.window.SetPos(x+1, y)
|
||||||
u.window.SetPos(x, y)
|
u.window.SetPos(x, y)
|
||||||
}
|
}
|
||||||
u.origPosX = invalidPos
|
u.setOrigPos(invalidPos, invalidPos)
|
||||||
u.origPosY = invalidPos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the window size after the position. The order matters.
|
// Set the window size after the position. The order matters.
|
||||||
@ -1350,17 +1366,7 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool) {
|
|||||||
u.window.SetTitle(u.title)
|
u.window.SetTitle(u.title)
|
||||||
}
|
}
|
||||||
|
|
||||||
// As width might be updated, update windowWidth/Height here.
|
return windowRecreated
|
||||||
u.windowWidth = width
|
|
||||||
u.windowHeight = height
|
|
||||||
|
|
||||||
u.toChangeSize = true
|
|
||||||
|
|
||||||
if windowRecreated {
|
|
||||||
if g, ok := u.Graphics().(interface{ SetWindow(uintptr) }); ok {
|
|
||||||
g.SetWindow(u.nativeWindow())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateVsync must be called on the main thread.
|
// updateVsync must be called on the main thread.
|
||||||
@ -1625,7 +1631,7 @@ func (u *UserInterface) setWindowPosition(x, y int) {
|
|||||||
xf := u.toGLFWPixel(float64(x))
|
xf := u.toGLFWPixel(float64(x))
|
||||||
yf := u.toGLFWPixel(float64(y))
|
yf := u.toGLFWPixel(float64(y))
|
||||||
if x, y := u.adjustWindowPosition(mx+int(xf), my+int(yf)); u.isFullscreen() {
|
if x, y := u.adjustWindowPosition(mx+int(xf), my+int(yf)); u.isFullscreen() {
|
||||||
u.origPosX, u.origPosY = x, y
|
u.setOrigPos(x, y)
|
||||||
} else {
|
} else {
|
||||||
u.window.SetPos(x, y)
|
u.window.SetPos(x, y)
|
||||||
}
|
}
|
||||||
@ -1654,3 +1660,26 @@ func (u *UserInterface) setWindowTitle(title string) {
|
|||||||
|
|
||||||
u.window.SetTitle(title)
|
u.window.SetTitle(title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) origPos() (int, int) {
|
||||||
|
// On macOS, the window can be fullscreened without calling an Ebiten function.
|
||||||
|
// Then, an original position might not be available by u.window.GetPos().
|
||||||
|
// Do not rely on the window position.
|
||||||
|
if u.isNativeFullscreenAvailable() {
|
||||||
|
return invalidPos, invalidPos
|
||||||
|
}
|
||||||
|
return u.origPosX, u.origPosY
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) setOrigPos(x, y int) {
|
||||||
|
// TODO: The original position should be updated at a 'PosCallback'.
|
||||||
|
|
||||||
|
// On macOS, the window can be fullscreened without calling an Ebiten function.
|
||||||
|
// Then, an original position might not be available by u.window.GetPos().
|
||||||
|
// Do not rely on the window position.
|
||||||
|
if u.isNativeFullscreenAvailable() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u.origPosX = x
|
||||||
|
u.origPosY = y
|
||||||
|
}
|
||||||
|
@ -50,6 +50,21 @@ package glfw
|
|||||||
// return (window.styleMask & NSWindowStyleMaskFullScreen) != 0;
|
// return (window.styleMask & NSWindowStyleMaskFullScreen) != 0;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
// static void setNativeFullscreen(uintptr_t windowPtr, bool fullscreen) {
|
||||||
|
// NSWindow* window = (NSWindow*)windowPtr;
|
||||||
|
// if (((window.styleMask & NSWindowStyleMaskFullScreen) != 0) == fullscreen) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// bool origResizable = window.styleMask & NSWindowStyleMaskResizable;
|
||||||
|
// if (!origResizable) {
|
||||||
|
// window.styleMask |= NSWindowStyleMaskResizable;
|
||||||
|
// }
|
||||||
|
// [window toggleFullScreen:nil];
|
||||||
|
// if (!origResizable) {
|
||||||
|
// window.styleMask &= ~NSWindowStyleMaskResizable;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
// static void setNativeCursor(int cursorID) {
|
// static void setNativeCursor(int cursorID) {
|
||||||
// id cursor = [[NSCursor class] performSelector:@selector(arrowCursor)];
|
// id cursor = [[NSCursor class] performSelector:@selector(arrowCursor)];
|
||||||
// switch (cursorID) {
|
// switch (cursorID) {
|
||||||
@ -139,3 +154,13 @@ func (u *UserInterface) isNativeFullscreen() bool {
|
|||||||
func (u *UserInterface) setNativeCursor(shape driver.CursorShape) {
|
func (u *UserInterface) setNativeCursor(shape driver.CursorShape) {
|
||||||
C.setNativeCursor(C.int(shape))
|
C.setNativeCursor(C.int(shape))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) isNativeFullscreenAvailable() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) setNativeFullscreen(fullscreen bool) {
|
||||||
|
// Toggling fullscreen might ignore events like keyUp. Ensure that events are fired.
|
||||||
|
glfw.WaitEventsTimeout(1)
|
||||||
|
C.setNativeFullscreen(C.uintptr_t(u.window.GetCocoaWindow()), C.bool(fullscreen))
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@ package glfw
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
"github.com/hajimehoshi/ebiten/v2/internal/driver"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/glfw"
|
"github.com/hajimehoshi/ebiten/v2/internal/glfw"
|
||||||
@ -146,3 +147,11 @@ func (u *UserInterface) setNativeCursor(shape driver.CursorShape) {
|
|||||||
// TODO: Use native API in the future (#1571)
|
// TODO: Use native API in the future (#1571)
|
||||||
u.window.SetCursor(glfwSystemCursors[shape])
|
u.window.SetCursor(glfwSystemCursors[shape])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) isNativeFullscreenAvailable() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) setNativeFullscreen(fullscreen bool) {
|
||||||
|
panic(fmt.Sprintf("glfw: setNativeFullscreen is not implemented in this environment: %s", runtime.GOOS))
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ package glfw
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
@ -194,3 +195,11 @@ func (u *UserInterface) setNativeCursor(shape driver.CursorShape) {
|
|||||||
// TODO: Use native API in the future (#1571)
|
// TODO: Use native API in the future (#1571)
|
||||||
u.window.SetCursor(glfwSystemCursors[shape])
|
u.window.SetCursor(glfwSystemCursors[shape])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) isNativeFullscreenAvailable() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserInterface) setNativeFullscreen(fullscreen bool) {
|
||||||
|
panic(fmt.Sprintf("glfw: setNativeFullscreen is not implemented in this environment: %s", runtime.GOOS))
|
||||||
|
}
|
||||||
|
@ -176,8 +176,8 @@ func (w *window) Position() (int, int) {
|
|||||||
x, y := 0, 0
|
x, y := 0, 0
|
||||||
_ = w.ui.t.Call(func() error {
|
_ = w.ui.t.Call(func() error {
|
||||||
var wx, wy int
|
var wx, wy int
|
||||||
if w.ui.isFullscreen() {
|
if w.ui.isFullscreen() && !w.ui.isNativeFullscreenAvailable() {
|
||||||
wx, wy = w.ui.origPosX, w.ui.origPosY
|
wx, wy = w.ui.origPos()
|
||||||
} else {
|
} else {
|
||||||
wx, wy = w.ui.window.GetPos()
|
wx, wy = w.ui.window.GetPos()
|
||||||
}
|
}
|
||||||
@ -223,6 +223,12 @@ func (w *window) SetSize(width, height int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = w.ui.t.Call(func() error {
|
_ = w.ui.t.Call(func() error {
|
||||||
|
// When a window is a native fullscreen, forcing to resize the window might leave unexpected image lags.
|
||||||
|
// Forbid this.
|
||||||
|
if w.ui.isNativeFullscreen() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
ww := int(w.ui.toGLFWPixel(float64(width)))
|
ww := int(w.ui.toGLFWPixel(float64(width)))
|
||||||
wh := int(w.ui.toGLFWPixel(float64(height)))
|
wh := int(w.ui.toGLFWPixel(float64(height)))
|
||||||
w.ui.setWindowSize(ww, wh, w.ui.isFullscreen())
|
w.ui.setWindowSize(ww, wh, w.ui.isFullscreen())
|
||||||
|
Loading…
Reference in New Issue
Block a user