From be1836339b046a35ed78b63a9b593b71e66ae0e0 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Mon, 21 Mar 2022 23:00:50 +0900 Subject: [PATCH] internal/ui: define the common struct UserInterface for all the environments The existing UserInterface structs became userInterfaceImpl structs. --- internal/ui/input_glfw.go | 2 +- internal/ui/input_js.go | 2 +- internal/ui/input_mobile.go | 2 +- internal/ui/run_notsinglethread.go | 4 +- internal/ui/run_singlethread.go | 4 +- internal/ui/ui.go | 11 ++ internal/ui/ui_cbackend.go | 48 ++++---- internal/ui/ui_glfw.go | 177 ++++++++++++++--------------- internal/ui/ui_glfw_darwin.go | 22 ++-- internal/ui/ui_glfw_unix.go | 22 ++-- internal/ui/ui_glfw_windows.go | 22 ++-- internal/ui/ui_js.go | 77 ++++++------- internal/ui/ui_mobile.go | 81 +++++++------ internal/ui/window_glfw.go | 2 +- 14 files changed, 232 insertions(+), 244 deletions(-) diff --git a/internal/ui/input_glfw.go b/internal/ui/input_glfw.go index 92b4568fc..e0f99ce09 100644 --- a/internal/ui/input_glfw.go +++ b/internal/ui/input_glfw.go @@ -36,7 +36,7 @@ type Input struct { cursorY int touches map[TouchID]pos // TODO: Implement this (#417) runeBuffer []rune - ui *UserInterface + ui *userInterfaceImpl } type pos struct { diff --git a/internal/ui/input_js.go b/internal/ui/input_js.go index d60a0f1ed..891f8822a 100644 --- a/internal/ui/input_js.go +++ b/internal/ui/input_js.go @@ -68,7 +68,7 @@ type Input struct { wheelY float64 touches map[TouchID]pos runeBuffer []rune - ui *UserInterface + ui *userInterfaceImpl } func (i *Input) CursorPosition() (x, y int) { diff --git a/internal/ui/input_mobile.go b/internal/ui/input_mobile.go index 30de71616..3dc88900f 100644 --- a/internal/ui/input_mobile.go +++ b/internal/ui/input_mobile.go @@ -22,7 +22,7 @@ type Input struct { keys map[Key]struct{} runes []rune touches []Touch - ui *UserInterface + ui *userInterfaceImpl } func (i *Input) CursorPosition() (x, y int) { diff --git a/internal/ui/run_notsinglethread.go b/internal/ui/run_notsinglethread.go index e40711c10..42c0f8fcd 100644 --- a/internal/ui/run_notsinglethread.go +++ b/internal/ui/run_notsinglethread.go @@ -22,7 +22,7 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/thread" ) -func (u *UserInterface) Run(game Game) error { +func (u *userInterfaceImpl) Run(game Game) error { u.context = newContextImpl(game) // Initialize the main thread first so the thread is available at u.run (#809). @@ -60,7 +60,7 @@ func (u *UserInterface) Run(game Game) error { // u.t is updated to the new thread until runOnAnotherThreadFromMainThread is called. // // Inside f, another functions that must be called from the main thread can be called safely. -func (u *UserInterface) runOnAnotherThreadFromMainThread(f func()) { +func (u *userInterfaceImpl) runOnAnotherThreadFromMainThread(f func()) { // As this function is called from the main thread, u.t should never be accessed and can be updated here. t := u.t defer func() { diff --git a/internal/ui/run_singlethread.go b/internal/ui/run_singlethread.go index 2628b86dc..dc640799f 100644 --- a/internal/ui/run_singlethread.go +++ b/internal/ui/run_singlethread.go @@ -22,7 +22,7 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/thread" ) -func (u *UserInterface) Run(game Game) error { +func (u *userInterfaceImpl) Run(game Game) error { u.context = newContextImpl(game) // Initialize the main thread first so the thread is available at u.run (#809). @@ -43,6 +43,6 @@ func (u *UserInterface) Run(game Game) error { return nil } -func (u *UserInterface) runOnAnotherThreadFromMainThread(f func()) { +func (u *userInterfaceImpl) runOnAnotherThreadFromMainThread(f func()) { f() } diff --git a/internal/ui/ui.go b/internal/ui/ui.go index d4287866e..125499040 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -71,6 +71,17 @@ const ( WindowResizingModeEnabled ) +type UserInterface struct { + userInterfaceImpl +} + +var theUI = &UserInterface{} + +func Get() *UserInterface { + // TODO: Get is a legacy API to access this package. Remove this. + return theUI +} + func (u *UserInterface) imageAt(mipmap *mipmap.Mipmap, x, y int) (r, g, b, a byte, err error) { return mipmap.At(graphicsDriver(), x, y) } diff --git a/internal/ui/ui_cbackend.go b/internal/ui/ui_cbackend.go index 102ed5831..3d047b3e0 100644 --- a/internal/ui/ui_cbackend.go +++ b/internal/ui/ui_cbackend.go @@ -29,18 +29,12 @@ func init() { runtime.LockOSThread() } -type UserInterface struct { +type userInterfaceImpl struct { context *contextImpl input Input } -var theUI UserInterface - -func Get() *UserInterface { - return &theUI -} - -func (u *UserInterface) Run(game Game) error { +func (u *userInterfaceImpl) Run(game Game) error { u.context = newContextImpl(game) cbackend.InitializeGame() for { @@ -56,69 +50,69 @@ func (u *UserInterface) Run(game Game) error { } } -func (*UserInterface) DeviceScaleFactor() float64 { +func (*userInterfaceImpl) DeviceScaleFactor() float64 { return deviceScaleFactor } -func (*UserInterface) IsFocused() bool { +func (*userInterfaceImpl) IsFocused() bool { return true } -func (*UserInterface) ScreenSizeInFullscreen() (int, int) { +func (*userInterfaceImpl) ScreenSizeInFullscreen() (int, int) { return 0, 0 } -func (*UserInterface) resetForTick() { +func (*userInterfaceImpl) resetForTick() { } -func (*UserInterface) CursorMode() CursorMode { +func (*userInterfaceImpl) CursorMode() CursorMode { return CursorModeHidden } -func (*UserInterface) SetCursorMode(mode CursorMode) { +func (*userInterfaceImpl) SetCursorMode(mode CursorMode) { } -func (*UserInterface) CursorShape() CursorShape { +func (*userInterfaceImpl) CursorShape() CursorShape { return CursorShapeDefault } -func (*UserInterface) SetCursorShape(shape CursorShape) { +func (*userInterfaceImpl) SetCursorShape(shape CursorShape) { } -func (*UserInterface) IsFullscreen() bool { +func (*userInterfaceImpl) IsFullscreen() bool { return false } -func (*UserInterface) SetFullscreen(fullscreen bool) { +func (*userInterfaceImpl) SetFullscreen(fullscreen bool) { } -func (*UserInterface) IsRunnableOnUnfocused() bool { +func (*userInterfaceImpl) IsRunnableOnUnfocused() bool { return false } -func (*UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) { +func (*userInterfaceImpl) SetRunnableOnUnfocused(runnableOnUnfocused bool) { } -func (*UserInterface) SetFPSMode(mode FPSModeType) { +func (*userInterfaceImpl) SetFPSMode(mode FPSModeType) { } -func (*UserInterface) ScheduleFrame() { +func (*userInterfaceImpl) ScheduleFrame() { } -func (*UserInterface) IsScreenTransparent() bool { +func (*userInterfaceImpl) IsScreenTransparent() bool { return false } -func (*UserInterface) SetScreenTransparent(transparent bool) { +func (*userInterfaceImpl) SetScreenTransparent(transparent bool) { } -func (*UserInterface) SetInitFocused(focused bool) { +func (*userInterfaceImpl) SetInitFocused(focused bool) { } -func (*UserInterface) Input() *Input { +func (*userInterfaceImpl) Input() *Input { return &theUI.input } -func (*UserInterface) Window() *Window { +func (*userInterfaceImpl) Window() *Window { return &Window{} } diff --git a/internal/ui/ui_glfw.go b/internal/ui/ui_glfw.go index 8681ee5a4..8fe5d3df3 100644 --- a/internal/ui/ui_glfw.go +++ b/internal/ui/ui_glfw.go @@ -45,7 +45,7 @@ func driverCursorModeToGLFWCursorMode(mode CursorMode) int { } } -type UserInterface struct { +type userInterfaceImpl struct { context *contextImpl title string window *glfw.Window @@ -120,8 +120,8 @@ const ( invalidPos = minInt ) -var ( - theUI = &UserInterface{ +func init() { + theUI.userInterfaceImpl = userInterfaceImpl{ runnableOnUnfocused: true, minWindowWidthInDIP: glfw.DontCare, minWindowHeightInDIP: glfw.DontCare, @@ -138,15 +138,8 @@ var ( initFocused: true, fpsMode: FPSModeVsyncOn, } -) - -func init() { - theUI.input.ui = theUI - theUI.iwindow.ui = theUI -} - -func Get() *UserInterface { - return theUI + theUI.input.ui = &theUI.userInterfaceImpl + theUI.iwindow.ui = &theUI.userInterfaceImpl } func init() { @@ -249,11 +242,11 @@ func getMonitorFromPosition(wx, wy int) *monitor { return nil } -func (u *UserInterface) isRunning() bool { +func (u *userInterfaceImpl) isRunning() bool { return atomic.LoadUint32(&u.running) != 0 } -func (u *UserInterface) setRunning(running bool) { +func (u *userInterfaceImpl) setRunning(running bool) { if running { atomic.StoreUint32(&u.running, 1) } else { @@ -261,13 +254,13 @@ func (u *UserInterface) setRunning(running bool) { } } -func (u *UserInterface) getWindowSizeLimitsInDIP() (minw, minh, maxw, maxh int) { +func (u *userInterfaceImpl) getWindowSizeLimitsInDIP() (minw, minh, maxw, maxh int) { u.m.RLock() defer u.m.RUnlock() return u.minWindowWidthInDIP, u.minWindowHeightInDIP, u.maxWindowWidthInDIP, u.maxWindowHeightInDIP } -func (u *UserInterface) setWindowSizeLimitsInDIP(minw, minh, maxw, maxh int) bool { +func (u *userInterfaceImpl) setWindowSizeLimitsInDIP(minw, minh, maxw, maxh int) bool { u.m.RLock() defer u.m.RUnlock() if u.minWindowWidthInDIP == minw && u.minWindowHeightInDIP == minh && u.maxWindowWidthInDIP == maxw && u.maxWindowHeightInDIP == maxh { @@ -280,40 +273,40 @@ func (u *UserInterface) setWindowSizeLimitsInDIP(minw, minh, maxw, maxh int) boo return true } -func (u *UserInterface) isInitFullscreen() bool { +func (u *userInterfaceImpl) isInitFullscreen() bool { u.m.RLock() v := u.initFullscreen u.m.RUnlock() return v } -func (u *UserInterface) setInitFullscreen(initFullscreen bool) { +func (u *userInterfaceImpl) setInitFullscreen(initFullscreen bool) { u.m.Lock() u.initFullscreen = initFullscreen u.m.Unlock() } -func (u *UserInterface) getInitCursorMode() CursorMode { +func (u *userInterfaceImpl) getInitCursorMode() CursorMode { u.m.RLock() v := u.initCursorMode u.m.RUnlock() return v } -func (u *UserInterface) setInitCursorMode(mode CursorMode) { +func (u *userInterfaceImpl) setInitCursorMode(mode CursorMode) { u.m.Lock() u.initCursorMode = mode u.m.Unlock() } -func (u *UserInterface) getCursorShape() CursorShape { +func (u *userInterfaceImpl) getCursorShape() CursorShape { u.m.RLock() v := u.cursorShape u.m.RUnlock() return v } -func (u *UserInterface) setCursorShape(shape CursorShape) CursorShape { +func (u *userInterfaceImpl) setCursorShape(shape CursorShape) CursorShape { u.m.Lock() old := u.cursorShape u.cursorShape = shape @@ -321,59 +314,59 @@ func (u *UserInterface) setCursorShape(shape CursorShape) CursorShape { return old } -func (u *UserInterface) isInitWindowDecorated() bool { +func (u *userInterfaceImpl) isInitWindowDecorated() bool { u.m.RLock() v := u.initWindowDecorated u.m.RUnlock() return v } -func (u *UserInterface) setInitWindowDecorated(decorated bool) { +func (u *userInterfaceImpl) setInitWindowDecorated(decorated bool) { u.m.Lock() u.initWindowDecorated = decorated u.m.Unlock() } -func (u *UserInterface) isRunnableOnUnfocused() bool { +func (u *userInterfaceImpl) isRunnableOnUnfocused() bool { u.m.RLock() v := u.runnableOnUnfocused u.m.RUnlock() return v } -func (u *UserInterface) setRunnableOnUnfocused(runnableOnUnfocused bool) { +func (u *userInterfaceImpl) setRunnableOnUnfocused(runnableOnUnfocused bool) { u.m.Lock() u.runnableOnUnfocused = runnableOnUnfocused u.m.Unlock() } -func (u *UserInterface) isInitScreenTransparent() bool { +func (u *userInterfaceImpl) isInitScreenTransparent() bool { u.m.RLock() v := u.initScreenTransparent u.m.RUnlock() return v } -func (u *UserInterface) setInitScreenTransparent(transparent bool) { +func (u *userInterfaceImpl) setInitScreenTransparent(transparent bool) { u.m.Lock() u.initScreenTransparent = transparent u.m.Unlock() } -func (u *UserInterface) getIconImages() []image.Image { +func (u *userInterfaceImpl) getIconImages() []image.Image { u.m.RLock() i := u.iconImages u.m.RUnlock() return i } -func (u *UserInterface) setIconImages(iconImages []image.Image) { +func (u *userInterfaceImpl) setIconImages(iconImages []image.Image) { u.m.Lock() u.iconImages = iconImages u.m.Unlock() } -func (u *UserInterface) getInitWindowPositionInDIP() (int, int) { +func (u *userInterfaceImpl) getInitWindowPositionInDIP() (int, int) { u.m.RLock() defer u.m.RUnlock() if u.initWindowPositionXInDIP != invalidPos && u.initWindowPositionYInDIP != invalidPos { @@ -382,7 +375,7 @@ func (u *UserInterface) getInitWindowPositionInDIP() (int, int) { return invalidPos, invalidPos } -func (u *UserInterface) setInitWindowPositionInDIP(x, y int) { +func (u *userInterfaceImpl) setInitWindowPositionInDIP(x, y int) { u.m.Lock() defer u.m.Unlock() @@ -391,79 +384,79 @@ func (u *UserInterface) setInitWindowPositionInDIP(x, y int) { u.initWindowPositionYInDIP = y } -func (u *UserInterface) getInitWindowSizeInDIP() (int, int) { +func (u *userInterfaceImpl) getInitWindowSizeInDIP() (int, int) { u.m.Lock() w, h := u.initWindowWidthInDIP, u.initWindowHeightInDIP u.m.Unlock() return w, h } -func (u *UserInterface) setInitWindowSizeInDIP(width, height int) { +func (u *userInterfaceImpl) setInitWindowSizeInDIP(width, height int) { u.m.Lock() u.initWindowWidthInDIP, u.initWindowHeightInDIP = width, height u.m.Unlock() } -func (u *UserInterface) isInitWindowFloating() bool { +func (u *userInterfaceImpl) isInitWindowFloating() bool { u.m.RLock() f := u.initWindowFloating u.m.RUnlock() return f } -func (u *UserInterface) setInitWindowFloating(floating bool) { +func (u *userInterfaceImpl) setInitWindowFloating(floating bool) { u.m.Lock() u.initWindowFloating = floating u.m.Unlock() } -func (u *UserInterface) isInitWindowMaximized() bool { +func (u *userInterfaceImpl) isInitWindowMaximized() bool { u.m.RLock() m := u.initWindowMaximized u.m.RUnlock() return m } -func (u *UserInterface) setInitWindowMaximized(maximized bool) { +func (u *userInterfaceImpl) setInitWindowMaximized(maximized bool) { u.m.Lock() u.initWindowMaximized = maximized u.m.Unlock() } -func (u *UserInterface) isWindowClosingHandled() bool { +func (u *userInterfaceImpl) isWindowClosingHandled() bool { u.m.RLock() v := u.windowClosingHandled u.m.RUnlock() return v } -func (u *UserInterface) setWindowClosingHandled(handled bool) { +func (u *userInterfaceImpl) setWindowClosingHandled(handled bool) { u.m.Lock() u.windowClosingHandled = handled u.m.Unlock() } -func (u *UserInterface) isWindowBeingClosed() bool { +func (u *userInterfaceImpl) isWindowBeingClosed() bool { u.m.RLock() v := u.windowBeingClosed u.m.RUnlock() return v } -func (u *UserInterface) isInitFocused() bool { +func (u *userInterfaceImpl) isInitFocused() bool { u.m.RLock() v := u.initFocused u.m.RUnlock() return v } -func (u *UserInterface) setInitFocused(focused bool) { +func (u *userInterfaceImpl) setInitFocused(focused bool) { u.m.Lock() u.initFocused = focused u.m.Unlock() } -func (u *UserInterface) ScreenSizeInFullscreen() (int, int) { +func (u *userInterfaceImpl) ScreenSizeInFullscreen() (int, int) { if !u.isRunning() { return u.initFullscreenWidthInDIP, u.initFullscreenHeightInDIP } @@ -479,14 +472,14 @@ func (u *UserInterface) ScreenSizeInFullscreen() (int, int) { } // isFullscreen must be called from the main thread. -func (u *UserInterface) isFullscreen() bool { +func (u *userInterfaceImpl) isFullscreen() bool { if !u.isRunning() { panic("ui: isFullscreen can't be called before the main loop starts") } return u.window.GetMonitor() != nil || u.isNativeFullscreen() } -func (u *UserInterface) IsFullscreen() bool { +func (u *userInterfaceImpl) IsFullscreen() bool { if !u.isRunning() { return u.isInitFullscreen() } @@ -497,7 +490,7 @@ func (u *UserInterface) IsFullscreen() bool { return b } -func (u *UserInterface) SetFullscreen(fullscreen bool) { +func (u *userInterfaceImpl) SetFullscreen(fullscreen bool) { if !u.isRunning() { u.setInitFullscreen(fullscreen) return @@ -517,7 +510,7 @@ func (u *UserInterface) SetFullscreen(fullscreen bool) { }) } -func (u *UserInterface) IsFocused() bool { +func (u *userInterfaceImpl) IsFocused() bool { if !u.isRunning() { return false } @@ -529,15 +522,15 @@ func (u *UserInterface) IsFocused() bool { return focused } -func (u *UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) { +func (u *userInterfaceImpl) SetRunnableOnUnfocused(runnableOnUnfocused bool) { u.setRunnableOnUnfocused(runnableOnUnfocused) } -func (u *UserInterface) IsRunnableOnUnfocused() bool { +func (u *userInterfaceImpl) IsRunnableOnUnfocused() bool { return u.isRunnableOnUnfocused() } -func (u *UserInterface) SetFPSMode(mode FPSModeType) { +func (u *userInterfaceImpl) SetFPSMode(mode FPSModeType) { if !u.isRunning() { u.m.Lock() u.fpsMode = mode @@ -554,7 +547,7 @@ func (u *UserInterface) SetFPSMode(mode FPSModeType) { }) } -func (u *UserInterface) ScheduleFrame() { +func (u *userInterfaceImpl) ScheduleFrame() { if !u.isRunning() { return } @@ -563,7 +556,7 @@ func (u *UserInterface) ScheduleFrame() { glfw.PostEmptyEvent() } -func (u *UserInterface) CursorMode() CursorMode { +func (u *userInterfaceImpl) CursorMode() CursorMode { if !u.isRunning() { return u.getInitCursorMode() } @@ -587,7 +580,7 @@ func (u *UserInterface) CursorMode() CursorMode { return v } -func (u *UserInterface) SetCursorMode(mode CursorMode) { +func (u *userInterfaceImpl) SetCursorMode(mode CursorMode) { if !u.isRunning() { u.setInitCursorMode(mode) return @@ -597,11 +590,11 @@ func (u *UserInterface) SetCursorMode(mode CursorMode) { }) } -func (u *UserInterface) CursorShape() CursorShape { +func (u *userInterfaceImpl) CursorShape() CursorShape { return u.getCursorShape() } -func (u *UserInterface) SetCursorShape(shape CursorShape) { +func (u *userInterfaceImpl) SetCursorShape(shape CursorShape) { old := u.setCursorShape(shape) if old == shape { return @@ -614,7 +607,7 @@ func (u *UserInterface) SetCursorShape(shape CursorShape) { }) } -func (u *UserInterface) DeviceScaleFactor() float64 { +func (u *userInterfaceImpl) DeviceScaleFactor() float64 { if !u.isRunning() { return u.deviceScaleFactor(u.currentMonitor()) } @@ -627,7 +620,7 @@ func (u *UserInterface) DeviceScaleFactor() float64 { } // deviceScaleFactor must be called from the main thread. -func (u *UserInterface) deviceScaleFactor(monitor *glfw.Monitor) float64 { +func (u *userInterfaceImpl) deviceScaleFactor(monitor *glfw.Monitor) float64 { // It is rare, but monitor can be nil when glfw.GetPrimaryMonitor returns nil. // In this case, return 1 as a tentative scale (#1878). if monitor == nil { @@ -650,7 +643,7 @@ func init() { // createWindow must be called from the main thread. // // createWindow does not set the position or size so far. -func (u *UserInterface) createWindow(width, height int) error { +func (u *userInterfaceImpl) createWindow(width, height int) error { if u.window != nil { panic("ui: u.window must not exist at createWindow") } @@ -686,7 +679,7 @@ func (u *UserInterface) createWindow(width, height int) error { } // registerWindowSetSizeCallback must be called from the main thread. -func (u *UserInterface) registerWindowSetSizeCallback() { +func (u *userInterfaceImpl) registerWindowSetSizeCallback() { if u.sizeCallback == 0 { u.sizeCallback = glfw.ToSizeCallback(func(_ *glfw.Window, width, height int) { if !u.setSizeCallbackEnabled { @@ -730,7 +723,7 @@ func (u *UserInterface) registerWindowSetSizeCallback() { } // registerWindowCloseCallback must be called from the main thread. -func (u *UserInterface) registerWindowCloseCallback() { +func (u *userInterfaceImpl) registerWindowCloseCallback() { if u.closeCallback == 0 { u.closeCallback = glfw.ToCloseCallback(func(_ *glfw.Window) { u.m.Lock() @@ -747,7 +740,7 @@ func (u *UserInterface) registerWindowCloseCallback() { } // registerWindowFramebufferSizeCallback must be called from the main thread. -func (u *UserInterface) registerWindowFramebufferSizeCallback() { +func (u *userInterfaceImpl) registerWindowFramebufferSizeCallback() { if u.defaultFramebufferSizeCallback == 0 { // When the window gets resized (either by manual window resize or a window // manager), glfw sends a framebuffer size callback which we need to handle (#1960). @@ -773,7 +766,7 @@ func (u *UserInterface) registerWindowFramebufferSizeCallback() { // If the callback is not invoked for a while, waitForFramebufferSizeCallback times out and return. // // waitForFramebufferSizeCallback must be called from the main thread. -func (u *UserInterface) waitForFramebufferSizeCallback(window *glfw.Window, f func()) { +func (u *userInterfaceImpl) waitForFramebufferSizeCallback(window *glfw.Window, f func()) { u.framebufferSizeCallbackCh = make(chan struct{}, 1) if u.framebufferSizeCallback == 0 { @@ -814,7 +807,7 @@ event: u.framebufferSizeCallbackCh = nil } -func (u *UserInterface) init() error { +func (u *userInterfaceImpl) init() error { if graphicsDriver().IsGL() { glfw.WindowHint(glfw.ClientAPI, glfw.OpenGLAPI) glfw.WindowHint(glfw.ContextVersionMajor, 2) @@ -895,7 +888,7 @@ func (u *UserInterface) init() error { return nil } -func (u *UserInterface) updateSize() (float64, float64) { +func (u *userInterfaceImpl) updateSize() (float64, float64) { ww, wh := u.windowWidthInDIP, u.windowHeightInDIP u.setWindowSizeInDIP(ww, wh, u.isFullscreen()) @@ -923,7 +916,7 @@ func (u *UserInterface) updateSize() (float64, float64) { } // setFPSMode must be called from the main thread. -func (u *UserInterface) setFPSMode(fpsMode FPSModeType) { +func (u *userInterfaceImpl) setFPSMode(fpsMode FPSModeType) { needUpdate := u.fpsMode != fpsMode || !u.fpsModeInited u.fpsMode = fpsMode u.fpsModeInited = true @@ -941,7 +934,7 @@ func (u *UserInterface) setFPSMode(fpsMode FPSModeType) { } // update must be called from the main thread. -func (u *UserInterface) update() (float64, float64, error) { +func (u *userInterfaceImpl) update() (float64, float64, error) { if u.err != nil { return 0, 0, u.err } @@ -996,7 +989,7 @@ func (u *UserInterface) update() (float64, float64, error) { return outsideWidth, outsideHeight, nil } -func (u *UserInterface) loop() error { +func (u *userInterfaceImpl) loop() error { defer u.t.Call(glfw.Terminate) for { @@ -1088,14 +1081,14 @@ func (u *UserInterface) loop() error { } // swapBuffers must be called from the main thread. -func (u *UserInterface) swapBuffers() { +func (u *userInterfaceImpl) swapBuffers() { if graphicsDriver().IsGL() { u.window.SwapBuffers() } } // updateWindowSizeLimits must be called from the main thread. -func (u *UserInterface) updateWindowSizeLimits() { +func (u *userInterfaceImpl) updateWindowSizeLimits() { m := u.currentMonitor() minw, minh, maxw, maxh := u.getWindowSizeLimitsInDIP() @@ -1125,7 +1118,7 @@ func (u *UserInterface) updateWindowSizeLimits() { // adjustWindowSizeBasedOnSizeLimitsInDIP adjust the size based on the window size limits. // width and height are in device-independent pixels. -func (u *UserInterface) adjustWindowSizeBasedOnSizeLimitsInDIP(width, height int) (int, int) { +func (u *userInterfaceImpl) adjustWindowSizeBasedOnSizeLimitsInDIP(width, height int) (int, int) { minw, minh, maxw, maxh := u.getWindowSizeLimitsInDIP() if minw >= 0 && width < minw { width = minw @@ -1143,7 +1136,7 @@ func (u *UserInterface) adjustWindowSizeBasedOnSizeLimitsInDIP(width, height int } // setWindowSize must be called from the main thread. -func (u *UserInterface) setWindowSizeInDIP(width, height int, fullscreen bool) { +func (u *userInterfaceImpl) setWindowSizeInDIP(width, height int, fullscreen bool) { width, height = u.adjustWindowSizeBasedOnSizeLimitsInDIP(width, height) graphicsDriver().SetFullscreen(fullscreen) @@ -1188,7 +1181,7 @@ func (u *UserInterface) setWindowSizeInDIP(width, height int, fullscreen bool) { u.windowHeightInDIP = height } -func (u *UserInterface) minimumWindowWidth() int { +func (u *userInterfaceImpl) minimumWindowWidth() int { if u.window.GetAttrib(glfw.Decorated) == glfw.False { return 1 } @@ -1205,7 +1198,7 @@ func (u *UserInterface) minimumWindowWidth() int { return 1 } -func (u *UserInterface) setWindowSizeInDIPImpl(width, height int, fullscreen bool) { +func (u *userInterfaceImpl) setWindowSizeInDIPImpl(width, height int, fullscreen bool) { if fullscreen { if x, y := u.origPos(); x == invalidPos || y == invalidPos { u.setOrigPos(u.window.GetPos()) @@ -1266,7 +1259,7 @@ func (u *UserInterface) setWindowSizeInDIPImpl(width, height int, fullscreen boo } // updateVsync must be called on the main thread. -func (u *UserInterface) updateVsync() { +func (u *userInterfaceImpl) updateVsync() { if graphicsDriver().IsGL() { // SwapInterval is affected by the current monitor of the window. // This needs to be called at least after SetMonitor. @@ -1287,7 +1280,7 @@ func (u *UserInterface) updateVsync() { // currentMonitor returns the current active monitor. // // currentMonitor must be called on the main thread. -func (u *UserInterface) currentMonitor() *glfw.Monitor { +func (u *userInterfaceImpl) currentMonitor() *glfw.Monitor { if u.window == nil { return u.initMonitor } @@ -1321,7 +1314,7 @@ func monitorFromWindow(window *glfw.Window) *glfw.Monitor { return nil } -func (u *UserInterface) SetScreenTransparent(transparent bool) { +func (u *userInterfaceImpl) SetScreenTransparent(transparent bool) { if !u.isRunning() { u.setInitScreenTransparent(transparent) return @@ -1329,7 +1322,7 @@ func (u *UserInterface) SetScreenTransparent(transparent bool) { panic("ui: SetScreenTransparent can't be called after the main loop starts") } -func (u *UserInterface) IsScreenTransparent() bool { +func (u *userInterfaceImpl) IsScreenTransparent() bool { if !u.isRunning() { return u.isInitScreenTransparent() } @@ -1340,7 +1333,7 @@ func (u *UserInterface) IsScreenTransparent() bool { return val } -func (u *UserInterface) resetForTick() { +func (u *userInterfaceImpl) resetForTick() { u.input.resetForTick() u.m.Lock() @@ -1348,18 +1341,18 @@ func (u *UserInterface) resetForTick() { u.m.Unlock() } -func (u *UserInterface) SetInitFocused(focused bool) { +func (u *userInterfaceImpl) SetInitFocused(focused bool) { if u.isRunning() { panic("ui: SetInitFocused must be called before the main loop") } u.setInitFocused(focused) } -func (u *UserInterface) Input() *Input { +func (u *userInterfaceImpl) Input() *Input { return &u.input } -func (u *UserInterface) Window() *Window { +func (u *userInterfaceImpl) Window() *Window { return &u.iwindow } @@ -1368,7 +1361,7 @@ func (u *UserInterface) Window() *Window { // disable the callback temporarily. // maximizeWindow must be called from the main thread. -func (u *UserInterface) maximizeWindow() { +func (u *userInterfaceImpl) maximizeWindow() { if u.isNativeFullscreen() { return } @@ -1399,7 +1392,7 @@ func (u *UserInterface) maximizeWindow() { } // iconifyWindow must be called from the main thread. -func (u *UserInterface) iconifyWindow() { +func (u *userInterfaceImpl) iconifyWindow() { if u.isNativeFullscreen() { return } @@ -1422,7 +1415,7 @@ func (u *UserInterface) iconifyWindow() { } // restoreWindow must be called from the main thread. -func (u *UserInterface) restoreWindow() { +func (u *userInterfaceImpl) restoreWindow() { if u.setSizeCallbackEnabled { u.setSizeCallbackEnabled = false defer func() { @@ -1452,7 +1445,7 @@ func (u *UserInterface) restoreWindow() { } // setWindowDecorated must be called from the main thread. -func (u *UserInterface) setWindowDecorated(decorated bool) { +func (u *userInterfaceImpl) setWindowDecorated(decorated bool) { if u.setSizeCallbackEnabled { u.setSizeCallbackEnabled = false defer func() { @@ -1472,7 +1465,7 @@ func (u *UserInterface) setWindowDecorated(decorated bool) { } // setWindowFloating must be called from the main thread. -func (u *UserInterface) setWindowFloating(floating bool) { +func (u *userInterfaceImpl) setWindowFloating(floating bool) { if u.setSizeCallbackEnabled { u.setSizeCallbackEnabled = false defer func() { @@ -1487,7 +1480,7 @@ func (u *UserInterface) setWindowFloating(floating bool) { } // setWindowResizingMode must be called from the main thread. -func (u *UserInterface) setWindowResizingMode(mode WindowResizingMode) { +func (u *userInterfaceImpl) setWindowResizingMode(mode WindowResizingMode) { if u.windowResizingMode == mode { return } @@ -1514,7 +1507,7 @@ func (u *UserInterface) setWindowResizingMode(mode WindowResizingMode) { // x and y are the position in device-independent pixels. // // setWindowPositionInDIP must be called from the main thread. -func (u *UserInterface) setWindowPositionInDIP(x, y int, monitor *glfw.Monitor) { +func (u *userInterfaceImpl) setWindowPositionInDIP(x, y int, monitor *glfw.Monitor) { if u.setSizeCallbackEnabled { u.setSizeCallbackEnabled = false defer func() { @@ -1547,7 +1540,7 @@ func (u *UserInterface) setWindowPositionInDIP(x, y int, monitor *glfw.Monitor) } // setWindowTitle must be called from the main thread. -func (u *UserInterface) setWindowTitle(title string) { +func (u *userInterfaceImpl) setWindowTitle(title string) { if u.setSizeCallbackEnabled { u.setSizeCallbackEnabled = false defer func() { @@ -1558,7 +1551,7 @@ func (u *UserInterface) setWindowTitle(title string) { u.window.SetTitle(title) } -func (u *UserInterface) origPos() (int, int) { +func (u *userInterfaceImpl) 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. @@ -1568,7 +1561,7 @@ func (u *UserInterface) origPos() (int, int) { return u.origPosX, u.origPosY } -func (u *UserInterface) setOrigPos(x, y int) { +func (u *userInterfaceImpl) 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. diff --git a/internal/ui/ui_glfw_darwin.go b/internal/ui/ui_glfw_darwin.go index fb9411b8e..2e9658dbf 100644 --- a/internal/ui/ui_glfw_darwin.go +++ b/internal/ui/ui_glfw_darwin.go @@ -233,12 +233,12 @@ import ( func clearVideoModeScaleCache() {} // dipFromGLFWMonitorPixel must be called from the main thread. -func (u *UserInterface) dipFromGLFWMonitorPixel(x float64, monitor *glfw.Monitor) float64 { +func (u *userInterfaceImpl) dipFromGLFWMonitorPixel(x float64, monitor *glfw.Monitor) float64 { return x } // dipFromGLFWPixel must be called from the main thread. -func (u *UserInterface) dipFromGLFWPixel(x float64, monitor *glfw.Monitor) float64 { +func (u *userInterfaceImpl) dipFromGLFWPixel(x float64, monitor *glfw.Monitor) float64 { // NOTE: On macOS, GLFW exposes the device independent coordinate system. // Thus, the conversion functions are unnecessary, // however we still need the deviceScaleFactor internally @@ -247,11 +247,11 @@ func (u *UserInterface) dipFromGLFWPixel(x float64, monitor *glfw.Monitor) float } // dipToGLFWPixel must be called from the main thread. -func (u *UserInterface) dipToGLFWPixel(x float64, monitor *glfw.Monitor) float64 { +func (u *userInterfaceImpl) dipToGLFWPixel(x float64, monitor *glfw.Monitor) float64 { return x } -func (u *UserInterface) adjustWindowPosition(x, y int, monitor *glfw.Monitor) (int, int) { +func (u *userInterfaceImpl) adjustWindowPosition(x, y int, monitor *glfw.Monitor) (int, int) { return x, y } @@ -291,38 +291,38 @@ func monitorFromWindowByOS(w *glfw.Window) *glfw.Monitor { return nil } -func (u *UserInterface) nativeWindow() uintptr { +func (u *userInterfaceImpl) nativeWindow() uintptr { return u.window.GetCocoaWindow() } -func (u *UserInterface) isNativeFullscreen() bool { +func (u *userInterfaceImpl) isNativeFullscreen() bool { return bool(C.isNativeFullscreen(C.uintptr_t(u.window.GetCocoaWindow()))) } -func (u *UserInterface) setNativeCursor(shape CursorShape) { +func (u *userInterfaceImpl) setNativeCursor(shape CursorShape) { C.setNativeCursor(C.int(shape)) } -func (u *UserInterface) isNativeFullscreenAvailable() bool { +func (u *userInterfaceImpl) isNativeFullscreenAvailable() bool { // TODO: If the window is transparent, we should use GLFW's windowed fullscreen (#1822, #1857). // However, if the user clicks the green button, should this window be in native fullscreen mode? return true } -func (u *UserInterface) setNativeFullscreen(fullscreen bool) { +func (u *userInterfaceImpl) setNativeFullscreen(fullscreen bool) { // Toggling fullscreen might ignore events like keyUp. Ensure that events are fired. glfw.WaitEventsTimeout(0.1) C.setNativeFullscreen(C.uintptr_t(u.window.GetCocoaWindow()), C.bool(fullscreen)) } -func (u *UserInterface) adjustViewSize() { +func (u *userInterfaceImpl) adjustViewSize() { if graphicsDriver().IsGL() { return } C.adjustViewSize(C.uintptr_t(u.window.GetCocoaWindow())) } -func (u *UserInterface) setWindowResizingModeForOS(mode WindowResizingMode) { +func (u *userInterfaceImpl) setWindowResizingModeForOS(mode WindowResizingMode) { allowFullscreen := mode == WindowResizingModeOnlyFullscreenEnabled || mode == WindowResizingModeEnabled C.setAllowFullscreen(C.uintptr_t(u.window.GetCocoaWindow()), C.bool(allowFullscreen)) diff --git a/internal/ui/ui_glfw_unix.go b/internal/ui/ui_glfw_unix.go index 0eee60fe4..28aac9f62 100644 --- a/internal/ui/ui_glfw_unix.go +++ b/internal/ui/ui_glfw_unix.go @@ -115,21 +115,21 @@ func videoModeScaleUncached(m *glfw.Monitor) float64 { } // dipFromGLFWMonitorPixel must be called from the main thread. -func (u *UserInterface) dipFromGLFWMonitorPixel(x float64, monitor *glfw.Monitor) float64 { +func (u *userInterfaceImpl) dipFromGLFWMonitorPixel(x float64, monitor *glfw.Monitor) float64 { return x / (videoModeScale(monitor) * u.deviceScaleFactor(monitor)) } // dipFromGLFWPixel must be called from the main thread. -func (u *UserInterface) dipFromGLFWPixel(x float64, monitor *glfw.Monitor) float64 { +func (u *userInterfaceImpl) dipFromGLFWPixel(x float64, monitor *glfw.Monitor) float64 { return x / u.deviceScaleFactor(monitor) } // dipToGLFWPixel must be called from the main thread. -func (u *UserInterface) dipToGLFWPixel(x float64, monitor *glfw.Monitor) float64 { +func (u *userInterfaceImpl) dipToGLFWPixel(x float64, monitor *glfw.Monitor) float64 { return x * u.deviceScaleFactor(monitor) } -func (u *UserInterface) adjustWindowPosition(x, y int, monitor *glfw.Monitor) (int, int) { +func (u *userInterfaceImpl) adjustWindowPosition(x, y int, monitor *glfw.Monitor) (int, int) { return x, y } @@ -164,32 +164,32 @@ func monitorFromWindowByOS(_ *glfw.Window) *glfw.Monitor { return nil } -func (u *UserInterface) nativeWindow() uintptr { +func (u *userInterfaceImpl) nativeWindow() uintptr { // TODO: Implement this. return 0 } -func (u *UserInterface) isNativeFullscreen() bool { +func (u *userInterfaceImpl) isNativeFullscreen() bool { return false } -func (u *UserInterface) setNativeCursor(shape CursorShape) { +func (u *userInterfaceImpl) setNativeCursor(shape CursorShape) { // TODO: Use native API in the future (#1571) u.window.SetCursor(glfwSystemCursors[shape]) } -func (u *UserInterface) isNativeFullscreenAvailable() bool { +func (u *userInterfaceImpl) isNativeFullscreenAvailable() bool { return false } -func (u *UserInterface) setNativeFullscreen(fullscreen bool) { +func (u *userInterfaceImpl) setNativeFullscreen(fullscreen bool) { panic(fmt.Sprintf("ui: setNativeFullscreen is not implemented in this environment: %s", runtime.GOOS)) } -func (u *UserInterface) adjustViewSize() { +func (u *userInterfaceImpl) adjustViewSize() { } -func (u *UserInterface) setWindowResizingModeForOS(mode WindowResizingMode) { +func (u *userInterfaceImpl) setWindowResizingModeForOS(mode WindowResizingMode) { } func initializeWindowAfterCreation(w *glfw.Window) { diff --git a/internal/ui/ui_glfw_windows.go b/internal/ui/ui_glfw_windows.go index 40a5d910a..2ddc72bb2 100644 --- a/internal/ui/ui_glfw_windows.go +++ b/internal/ui/ui_glfw_windows.go @@ -101,21 +101,21 @@ func getCursorPos() (int32, int32, error) { func clearVideoModeScaleCache() {} // dipFromGLFWMonitorPixel must be called from the main thread. -func (u *UserInterface) dipFromGLFWMonitorPixel(x float64, monitor *glfw.Monitor) float64 { +func (u *userInterfaceImpl) dipFromGLFWMonitorPixel(x float64, monitor *glfw.Monitor) float64 { return x / u.deviceScaleFactor(monitor) } // dipFromGLFWPixel must be called from the main thread. -func (u *UserInterface) dipFromGLFWPixel(x float64, monitor *glfw.Monitor) float64 { +func (u *userInterfaceImpl) dipFromGLFWPixel(x float64, monitor *glfw.Monitor) float64 { return x / u.deviceScaleFactor(monitor) } // dipToGLFWPixel must be called from the main thread. -func (u *UserInterface) dipToGLFWPixel(x float64, monitor *glfw.Monitor) float64 { +func (u *userInterfaceImpl) dipToGLFWPixel(x float64, monitor *glfw.Monitor) float64 { return x * u.deviceScaleFactor(monitor) } -func (u *UserInterface) adjustWindowPosition(x, y int, monitor *glfw.Monitor) (int, int) { +func (u *userInterfaceImpl) adjustWindowPosition(x, y int, monitor *glfw.Monitor) (int, int) { mx, my := monitor.GetPos() // As the video width/height might be wrong, // adjust x/y at least to enable to handle the window (#328) @@ -179,31 +179,31 @@ func monitorFromWin32Window(w windows.HWND) *glfw.Monitor { return nil } -func (u *UserInterface) nativeWindow() uintptr { +func (u *userInterfaceImpl) nativeWindow() uintptr { return u.window.GetWin32Window() } -func (u *UserInterface) isNativeFullscreen() bool { +func (u *userInterfaceImpl) isNativeFullscreen() bool { return false } -func (u *UserInterface) setNativeCursor(shape CursorShape) { +func (u *userInterfaceImpl) setNativeCursor(shape CursorShape) { // TODO: Use native API in the future (#1571) u.window.SetCursor(glfwSystemCursors[shape]) } -func (u *UserInterface) isNativeFullscreenAvailable() bool { +func (u *userInterfaceImpl) isNativeFullscreenAvailable() bool { return false } -func (u *UserInterface) setNativeFullscreen(fullscreen bool) { +func (u *userInterfaceImpl) setNativeFullscreen(fullscreen bool) { panic(fmt.Sprintf("ui: setNativeFullscreen is not implemented in this environment: %s", runtime.GOOS)) } -func (u *UserInterface) adjustViewSize() { +func (u *userInterfaceImpl) adjustViewSize() { } -func (u *UserInterface) setWindowResizingModeForOS(mode WindowResizingMode) { +func (u *userInterfaceImpl) setWindowResizingModeForOS(mode WindowResizingMode) { } func initializeWindowAfterCreation(w *glfw.Window) { diff --git a/internal/ui/ui_js.go b/internal/ui/ui_js.go index 7013d0a76..4705de7d5 100644 --- a/internal/ui/ui_js.go +++ b/internal/ui/ui_js.go @@ -46,7 +46,7 @@ func driverCursorShapeToCSSCursor(cursor CursorShape) string { return "auto" } -type UserInterface struct { +type userInterfaceImpl struct { runnableOnUnfocused bool fpsMode FPSModeType renderingScheduled bool @@ -63,17 +63,12 @@ type UserInterface struct { input Input } -var theUI = &UserInterface{ - runnableOnUnfocused: true, - initFocused: true, -} - func init() { - theUI.input.ui = theUI -} - -func Get() *UserInterface { - return theUI + theUI.userInterfaceImpl = userInterfaceImpl{ + runnableOnUnfocused: true, + initFocused: true, + } + theUI.input.ui = &theUI.userInterfaceImpl } var ( @@ -98,11 +93,11 @@ func init() { documentHidden = js.Global().Get("Object").Call("getOwnPropertyDescriptor", js.Global().Get("Document").Get("prototype"), "hidden").Get("get").Call("bind", document) } -func (u *UserInterface) ScreenSizeInFullscreen() (int, int) { +func (u *userInterfaceImpl) ScreenSizeInFullscreen() (int, int) { return window.Get("innerWidth").Int(), window.Get("innerHeight").Int() } -func (u *UserInterface) SetFullscreen(fullscreen bool) { +func (u *userInterfaceImpl) SetFullscreen(fullscreen bool) { if !canvas.Truthy() { return } @@ -127,7 +122,7 @@ func (u *UserInterface) SetFullscreen(fullscreen bool) { f.Call("bind", document).Invoke() } -func (u *UserInterface) IsFullscreen() bool { +func (u *userInterfaceImpl) IsFullscreen() bool { if !document.Truthy() { return false } @@ -137,34 +132,34 @@ func (u *UserInterface) IsFullscreen() bool { return true } -func (u *UserInterface) IsFocused() bool { +func (u *userInterfaceImpl) IsFocused() bool { return u.isFocused() } -func (u *UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) { +func (u *userInterfaceImpl) SetRunnableOnUnfocused(runnableOnUnfocused bool) { u.runnableOnUnfocused = runnableOnUnfocused } -func (u *UserInterface) IsRunnableOnUnfocused() bool { +func (u *userInterfaceImpl) IsRunnableOnUnfocused() bool { return u.runnableOnUnfocused } -func (u *UserInterface) SetFPSMode(mode FPSModeType) { +func (u *userInterfaceImpl) SetFPSMode(mode FPSModeType) { u.fpsMode = mode } -func (u *UserInterface) ScheduleFrame() { +func (u *userInterfaceImpl) ScheduleFrame() { u.renderingScheduled = true } -func (u *UserInterface) CursorMode() CursorMode { +func (u *userInterfaceImpl) CursorMode() CursorMode { if !canvas.Truthy() { return CursorModeHidden } return u.cursorMode } -func (u *UserInterface) SetCursorMode(mode CursorMode) { +func (u *userInterfaceImpl) SetCursorMode(mode CursorMode) { if !canvas.Truthy() { return } @@ -187,21 +182,21 @@ func (u *UserInterface) SetCursorMode(mode CursorMode) { } } -func (u *UserInterface) recoverCursorMode() { +func (u *userInterfaceImpl) recoverCursorMode() { if theUI.cursorPrevMode == CursorModeCaptured { panic("ui: cursorPrevMode must not be CursorModeCaptured at recoverCursorMode") } u.SetCursorMode(u.cursorPrevMode) } -func (u *UserInterface) CursorShape() CursorShape { +func (u *userInterfaceImpl) CursorShape() CursorShape { if !canvas.Truthy() { return CursorShapeDefault } return u.cursorShape } -func (u *UserInterface) SetCursorShape(shape CursorShape) { +func (u *userInterfaceImpl) SetCursorShape(shape CursorShape) { if !canvas.Truthy() { return } @@ -215,11 +210,11 @@ func (u *UserInterface) SetCursorShape(shape CursorShape) { } } -func (u *UserInterface) DeviceScaleFactor() float64 { +func (u *userInterfaceImpl) DeviceScaleFactor() float64 { return devicescale.GetAt(0, 0) } -func (u *UserInterface) outsideSize() (float64, float64) { +func (u *userInterfaceImpl) outsideSize() (float64, float64) { switch { case document.Truthy(): body := document.Get("body") @@ -236,14 +231,14 @@ func (u *UserInterface) outsideSize() (float64, float64) { } } -func (u *UserInterface) suspended() bool { +func (u *userInterfaceImpl) suspended() bool { if u.runnableOnUnfocused { return false } return !u.isFocused() } -func (u *UserInterface) isFocused() bool { +func (u *userInterfaceImpl) isFocused() bool { if go2cpp.Truthy() { return true } @@ -257,7 +252,7 @@ func (u *UserInterface) isFocused() bool { return true } -func (u *UserInterface) update() error { +func (u *userInterfaceImpl) update() error { if u.suspended() { return hooks.SuspendAudio() } @@ -267,7 +262,7 @@ func (u *UserInterface) update() error { return u.updateImpl(false) } -func (u *UserInterface) updateImpl(force bool) error { +func (u *userInterfaceImpl) updateImpl(force bool) error { // context can be nil when an event is fired but the loop doesn't start yet (#1928). if u.context == nil { return nil @@ -295,7 +290,7 @@ func (u *UserInterface) updateImpl(force bool) error { return nil } -func (u *UserInterface) needsUpdate() bool { +func (u *userInterfaceImpl) needsUpdate() bool { if u.fpsMode != FPSModeVsyncOffMinimum { return true } @@ -309,7 +304,7 @@ func (u *UserInterface) needsUpdate() bool { return false } -func (u *UserInterface) loop(game Game) <-chan error { +func (u *userInterfaceImpl) loop(game Game) <-chan error { u.context = newContextImpl(game) errCh := make(chan error, 1) @@ -575,14 +570,14 @@ func setCanvasEventHandlers(v js.Value) { })) } -func (u *UserInterface) forceUpdateOnMinimumFPSMode() { +func (u *userInterfaceImpl) forceUpdateOnMinimumFPSMode() { if u.fpsMode != FPSModeVsyncOffMinimum { return } u.updateImpl(true) } -func (u *UserInterface) Run(game Game) error { +func (u *userInterfaceImpl) Run(game Game) error { if u.initFocused && window.Truthy() { // Do not focus the canvas when the current document is in an iframe. // Otherwise, the parent page tries to focus the iframe on every loading, which is annoying (#1373). @@ -595,7 +590,7 @@ func (u *UserInterface) Run(game Game) error { return <-u.loop(game) } -func (u *UserInterface) updateScreenSize() { +func (u *userInterfaceImpl) updateScreenSize() { switch { case document.Truthy(): body := document.Get("body") @@ -608,7 +603,7 @@ func (u *UserInterface) updateScreenSize() { } } -func (u *UserInterface) SetScreenTransparent(transparent bool) { +func (u *userInterfaceImpl) SetScreenTransparent(transparent bool) { if u.running { panic("ui: SetScreenTransparent can't be called after the main loop starts") } @@ -621,26 +616,26 @@ func (u *UserInterface) SetScreenTransparent(transparent bool) { } } -func (u *UserInterface) IsScreenTransparent() bool { +func (u *userInterfaceImpl) IsScreenTransparent() bool { bodyStyle := document.Get("body").Get("style") return bodyStyle.Get("backgroundColor").Equal(stringTransparent) } -func (u *UserInterface) resetForTick() { +func (u *userInterfaceImpl) resetForTick() { u.input.resetForTick() } -func (u *UserInterface) SetInitFocused(focused bool) { +func (u *userInterfaceImpl) SetInitFocused(focused bool) { if u.running { panic("ui: SetInitFocused must be called before the main loop") } u.initFocused = focused } -func (u *UserInterface) Input() *Input { +func (u *userInterfaceImpl) Input() *Input { return &u.input } -func (u *UserInterface) Window() *Window { +func (u *userInterfaceImpl) Window() *Window { return &Window{} } diff --git a/internal/ui/ui_mobile.go b/internal/ui/ui_mobile.go index e7c8335cf..c4d9bba79 100644 --- a/internal/ui/ui_mobile.go +++ b/internal/ui/ui_mobile.go @@ -50,8 +50,10 @@ var ( // renderEndCh receives when updating finishes. renderEndCh = make(chan struct{}) +) - theUI = &UserInterface{ +func init() { + theUI.userInterfaceImpl = userInterfaceImpl{ foreground: 1, errCh: make(chan error), @@ -59,20 +61,13 @@ var ( outsideWidth: 640, outsideHeight: 480, } -) - -func init() { - theUI.input.ui = theUI -} - -func Get() *UserInterface { - return theUI + theUI.input.ui = &theUI.userInterfaceImpl } // Update is called from mobile/ebitenmobileview. // // Update must be called on the rendering thread. -func (u *UserInterface) Update() error { +func (u *userInterfaceImpl) Update() error { select { case err := <-u.errCh: return err @@ -94,7 +89,7 @@ func (u *UserInterface) Update() error { return nil } -type UserInterface struct { +type userInterfaceImpl struct { outsideWidth float64 outsideHeight float64 @@ -124,7 +119,7 @@ func deviceScale() float64 { } // appMain is the main routine for gomobile-build mode. -func (u *UserInterface) appMain(a app.App) { +func (u *userInterfaceImpl) appMain(a app.App) { var glctx gl.Context var sizeInited bool @@ -222,7 +217,7 @@ func (u *UserInterface) appMain(a app.App) { } } -func (u *UserInterface) SetForeground(foreground bool) error { +func (u *userInterfaceImpl) SetForeground(foreground bool) error { var v int32 if foreground { v = 1 @@ -236,7 +231,7 @@ func (u *UserInterface) SetForeground(foreground bool) error { } } -func (u *UserInterface) Run(game Game) error { +func (u *userInterfaceImpl) Run(game Game) error { u.setGBuildSizeCh = make(chan struct{}) go func() { if err := u.run(game, true); err != nil { @@ -252,7 +247,7 @@ func RunWithoutMainLoop(game Game) { theUI.runWithoutMainLoop(game) } -func (u *UserInterface) runWithoutMainLoop(game Game) { +func (u *userInterfaceImpl) runWithoutMainLoop(game Game) { go func() { if err := u.run(game, false); err != nil { u.errCh <- err @@ -260,7 +255,7 @@ func (u *UserInterface) runWithoutMainLoop(game Game) { }() } -func (u *UserInterface) run(game Game, mainloop bool) (err error) { +func (u *userInterfaceImpl) run(game Game, mainloop bool) (err error) { // Convert the panic to a regular error so that Java/Objective-C layer can treat this easily e.g., for // Crashlytics. A panic is treated as SIGABRT, and there is no way to handle this on Java/Objective-C layer // unfortunately. @@ -296,7 +291,7 @@ func (u *UserInterface) run(game Game, mainloop bool) (err error) { } // outsideSize must be called on the same goroutine as update(). -func (u *UserInterface) outsideSize() (float64, float64) { +func (u *userInterfaceImpl) outsideSize() (float64, float64) { var outsideWidth, outsideHeight float64 u.m.RLock() @@ -314,7 +309,7 @@ func (u *UserInterface) outsideSize() (float64, float64) { return outsideWidth, outsideHeight } -func (u *UserInterface) update() error { +func (u *userInterfaceImpl) update() error { <-renderCh defer func() { renderEndCh <- struct{}{} @@ -327,7 +322,7 @@ func (u *UserInterface) update() error { return nil } -func (u *UserInterface) ScreenSizeInFullscreen() (int, int) { +func (u *userInterfaceImpl) ScreenSizeInFullscreen() (int, int) { // TODO: This function should return gbuildWidthPx, gbuildHeightPx, // but these values are not initialized until the main loop starts. return 0, 0 @@ -336,7 +331,7 @@ func (u *UserInterface) ScreenSizeInFullscreen() (int, int) { // SetOutsideSize is called from mobile/ebitenmobileview. // // SetOutsideSize is concurrent safe. -func (u *UserInterface) SetOutsideSize(outsideWidth, outsideHeight float64) { +func (u *userInterfaceImpl) SetOutsideSize(outsideWidth, outsideHeight float64) { u.m.Lock() if u.outsideWidth != outsideWidth || u.outsideHeight != outsideHeight { u.outsideWidth = outsideWidth @@ -345,7 +340,7 @@ func (u *UserInterface) SetOutsideSize(outsideWidth, outsideHeight float64) { u.m.Unlock() } -func (u *UserInterface) setGBuildSize(widthPx, heightPx int) { +func (u *userInterfaceImpl) setGBuildSize(widthPx, heightPx int) { u.m.Lock() u.gbuildWidthPx = widthPx u.gbuildHeightPx = heightPx @@ -356,84 +351,84 @@ func (u *UserInterface) setGBuildSize(widthPx, heightPx int) { }) } -func (u *UserInterface) adjustPosition(x, y int) (int, int) { +func (u *userInterfaceImpl) adjustPosition(x, y int) (int, int) { xf, yf := u.context.adjustPosition(float64(x), float64(y), deviceScale()) return int(xf), int(yf) } -func (u *UserInterface) CursorMode() CursorMode { +func (u *userInterfaceImpl) CursorMode() CursorMode { return CursorModeHidden } -func (u *UserInterface) SetCursorMode(mode CursorMode) { +func (u *userInterfaceImpl) SetCursorMode(mode CursorMode) { // Do nothing } -func (u *UserInterface) CursorShape() CursorShape { +func (u *userInterfaceImpl) CursorShape() CursorShape { return CursorShapeDefault } -func (u *UserInterface) SetCursorShape(shape CursorShape) { +func (u *userInterfaceImpl) SetCursorShape(shape CursorShape) { // Do nothing } -func (u *UserInterface) IsFullscreen() bool { +func (u *userInterfaceImpl) IsFullscreen() bool { return false } -func (u *UserInterface) SetFullscreen(fullscreen bool) { +func (u *userInterfaceImpl) SetFullscreen(fullscreen bool) { // Do nothing } -func (u *UserInterface) IsFocused() bool { +func (u *userInterfaceImpl) IsFocused() bool { return atomic.LoadInt32(&u.foreground) != 0 } -func (u *UserInterface) IsRunnableOnUnfocused() bool { +func (u *userInterfaceImpl) IsRunnableOnUnfocused() bool { return false } -func (u *UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) { +func (u *userInterfaceImpl) SetRunnableOnUnfocused(runnableOnUnfocused bool) { // Do nothing } -func (u *UserInterface) SetFPSMode(mode FPSModeType) { +func (u *userInterfaceImpl) SetFPSMode(mode FPSModeType) { u.fpsMode = mode u.updateExplicitRenderingModeIfNeeded() } -func (u *UserInterface) updateExplicitRenderingModeIfNeeded() { +func (u *userInterfaceImpl) updateExplicitRenderingModeIfNeeded() { if u.renderRequester == nil { return } u.renderRequester.SetExplicitRenderingMode(u.fpsMode == FPSModeVsyncOffMinimum) } -func (u *UserInterface) DeviceScaleFactor() float64 { +func (u *userInterfaceImpl) DeviceScaleFactor() float64 { return deviceScale() } -func (u *UserInterface) SetScreenTransparent(transparent bool) { +func (u *userInterfaceImpl) SetScreenTransparent(transparent bool) { // Do nothing } -func (u *UserInterface) IsScreenTransparent() bool { +func (u *userInterfaceImpl) IsScreenTransparent() bool { return false } -func (u *UserInterface) resetForTick() { +func (u *userInterfaceImpl) resetForTick() { u.input.resetForTick() } -func (u *UserInterface) SetInitFocused(focused bool) { +func (u *userInterfaceImpl) SetInitFocused(focused bool) { // Do nothing } -func (u *UserInterface) Input() *Input { +func (u *userInterfaceImpl) Input() *Input { return &u.input } -func (u *UserInterface) Window() *Window { +func (u *userInterfaceImpl) Window() *Window { return &Window{} } @@ -443,7 +438,7 @@ type Touch struct { Y int } -func (u *UserInterface) UpdateInput(keys map[Key]struct{}, runes []rune, touches []Touch) { +func (u *userInterfaceImpl) UpdateInput(keys map[Key]struct{}, runes []rune, touches []Touch) { u.input.update(keys, runes, touches) if u.fpsMode == FPSModeVsyncOffMinimum { u.renderRequester.RequestRenderIfNeeded() @@ -455,12 +450,12 @@ type RenderRequester interface { RequestRenderIfNeeded() } -func (u *UserInterface) SetRenderRequester(renderRequester RenderRequester) { +func (u *userInterfaceImpl) SetRenderRequester(renderRequester RenderRequester) { u.renderRequester = renderRequester u.updateExplicitRenderingModeIfNeeded() } -func (u *UserInterface) ScheduleFrame() { +func (u *userInterfaceImpl) ScheduleFrame() { if u.renderRequester != nil && u.fpsMode == FPSModeVsyncOffMinimum { u.renderRequester.RequestRenderIfNeeded() } diff --git a/internal/ui/window_glfw.go b/internal/ui/window_glfw.go index cfbc95f73..126854f35 100644 --- a/internal/ui/window_glfw.go +++ b/internal/ui/window_glfw.go @@ -24,7 +24,7 @@ import ( ) type Window struct { - ui *UserInterface + ui *userInterfaceImpl } func (w *Window) IsDecorated() bool {