internal/driver: move some definitions to internal/ui

Updates #1983
This commit is contained in:
Hajime Hoshi 2022-02-06 17:43:52 +09:00
parent 149736c3cf
commit 6f72b15912
16 changed files with 161 additions and 199 deletions

View File

@ -14,27 +14,29 @@
package ebiten package ebiten
import "github.com/hajimehoshi/ebiten/v2/internal/driver" import (
"github.com/hajimehoshi/ebiten/v2/internal/ui"
)
// CursorModeType represents a render and coordinate mode of a mouse cursor. // CursorModeType represents a render and coordinate mode of a mouse cursor.
type CursorModeType = driver.CursorMode type CursorModeType = ui.CursorMode
// CursorModeTypes // CursorModeTypes
const ( const (
CursorModeVisible CursorModeType = CursorModeType(driver.CursorModeVisible) CursorModeVisible CursorModeType = CursorModeType(ui.CursorModeVisible)
CursorModeHidden CursorModeType = CursorModeType(driver.CursorModeHidden) CursorModeHidden CursorModeType = CursorModeType(ui.CursorModeHidden)
CursorModeCaptured CursorModeType = CursorModeType(driver.CursorModeCaptured) CursorModeCaptured CursorModeType = CursorModeType(ui.CursorModeCaptured)
) )
// CursorShapeType represents a shape of a mouse cursor. // CursorShapeType represents a shape of a mouse cursor.
type CursorShapeType = driver.CursorShape type CursorShapeType = ui.CursorShape
// CursorShapeTypes // CursorShapeTypes
const ( const (
CursorShapeDefault CursorShapeType = CursorShapeType(driver.CursorShapeDefault) CursorShapeDefault CursorShapeType = CursorShapeType(ui.CursorShapeDefault)
CursorShapeText CursorShapeType = CursorShapeType(driver.CursorShapeText) CursorShapeText CursorShapeType = CursorShapeType(ui.CursorShapeText)
CursorShapeCrosshair CursorShapeType = CursorShapeType(driver.CursorShapeCrosshair) CursorShapeCrosshair CursorShapeType = CursorShapeType(ui.CursorShapeCrosshair)
CursorShapePointer CursorShapeType = CursorShapeType(driver.CursorShapePointer) CursorShapePointer CursorShapeType = CursorShapeType(ui.CursorShapePointer)
CursorShapeEWResize CursorShapeType = CursorShapeType(driver.CursorShapeEWResize) CursorShapeEWResize CursorShapeType = CursorShapeType(ui.CursorShapeEWResize)
CursorShapeNSResize CursorShapeType = CursorShapeType(driver.CursorShapeNSResize) CursorShapeNSResize CursorShapeType = CursorShapeType(ui.CursorShapeNSResize)
) )

View File

@ -15,61 +15,9 @@
package driver package driver
import ( import (
"errors"
"image" "image"
"time"
) )
type UIContext interface {
UpdateFrame() error
ForceUpdateFrame() error
Layout(outsideWidth, outsideHeight float64)
// AdjustPosition can be called from a different goroutine from Update's or Layout's.
AdjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64)
}
// RegularTermination represents a regular termination.
// Run can return this error, and if this error is received,
// the game loop should be terminated as soon as possible.
var RegularTermination = errors.New("regular termination")
type UI interface {
Run(context UIContext) error
RunWithoutMainLoop(context UIContext)
DeviceScaleFactor() float64
IsFocused() bool
ScreenSizeInFullscreen() (int, int)
ResetForFrame()
CursorMode() CursorMode
SetCursorMode(mode CursorMode)
CursorShape() CursorShape
SetCursorShape(shape CursorShape)
IsFullscreen() bool
SetFullscreen(fullscreen bool)
IsRunnableOnUnfocused() bool
SetRunnableOnUnfocused(runnableOnUnfocused bool)
FPSMode() FPSMode
SetFPSMode(mode FPSMode)
ScheduleFrame()
IsScreenTransparent() bool
SetScreenTransparent(transparent bool)
SetInitFocused(focused bool)
Vibrate(duration time.Duration, magnitude float64)
Input() Input
Window() Window
Graphics() Graphics
}
type Window interface { type Window interface {
IsDecorated() bool IsDecorated() bool
SetDecorated(decorated bool) SetDecorated(decorated bool)
@ -102,11 +50,3 @@ type Window interface {
SetClosingHandled(handled bool) SetClosingHandled(handled bool)
IsClosingHandled() bool IsClosingHandled() bool
} }
type FPSMode int
const (
FPSModeVsyncOn FPSMode = iota
FPSModeVsyncOffMaximum
FPSModeVsyncOffMinimum
)

View File

@ -32,7 +32,7 @@ type Input struct {
m sync.Mutex m sync.Mutex
} }
func (i *Input) update(context driver.UIContext) { func (i *Input) update(context Context) {
i.m.Lock() i.m.Lock()
defer i.m.Unlock() defer i.m.Unlock()

View File

@ -156,7 +156,7 @@ var glfwMouseButtonToMouseButton = map[glfw.MouseButton]driver.MouseButton{
} }
// update must be called from the main thread. // update must be called from the main thread.
func (i *Input) update(window *glfw.Window, context driver.UIContext) error { func (i *Input) update(window *glfw.Window, context Context) error {
i.ui.m.Lock() i.ui.m.Lock()
defer i.ui.m.Unlock() defer i.ui.m.Unlock()

View File

@ -257,7 +257,7 @@ func (i *Input) updateFromEvent(e js.Value) {
} }
func (i *Input) setMouseCursorFromEvent(e js.Value) { func (i *Input) setMouseCursorFromEvent(e js.Value) {
if i.ui.cursorMode == driver.CursorModeCaptured { if i.ui.cursorMode == CursorModeCaptured {
x, y := e.Get("clientX").Int(), e.Get("clientY").Int() x, y := e.Get("clientX").Int(), e.Get("clientY").Int()
i.origCursorX, i.origCursorY = x, y i.origCursorX, i.origCursorY = x, y
dx, dy := e.Get("movementX").Int(), e.Get("movementY").Int() dx, dy := e.Get("movementX").Int(), e.Get("movementY").Int()

View File

@ -18,12 +18,11 @@
package ui package ui
import ( import (
"github.com/hajimehoshi/ebiten/v2/internal/driver"
"github.com/hajimehoshi/ebiten/v2/internal/graphicscommand" "github.com/hajimehoshi/ebiten/v2/internal/graphicscommand"
"github.com/hajimehoshi/ebiten/v2/internal/thread" "github.com/hajimehoshi/ebiten/v2/internal/thread"
) )
func (u *UserInterface) Run(uicontext driver.UIContext) error { func (u *UserInterface) Run(uicontext Context) error {
u.context = uicontext u.context = uicontext
// Initialize the main thread first so the thread is available at u.run (#809). // Initialize the main thread first so the thread is available at u.run (#809).

View File

@ -18,12 +18,11 @@
package ui package ui
import ( import (
"github.com/hajimehoshi/ebiten/v2/internal/driver"
"github.com/hajimehoshi/ebiten/v2/internal/graphicscommand" "github.com/hajimehoshi/ebiten/v2/internal/graphicscommand"
"github.com/hajimehoshi/ebiten/v2/internal/thread" "github.com/hajimehoshi/ebiten/v2/internal/thread"
) )
func (u *UserInterface) Run(uicontext driver.UIContext) error { func (u *UserInterface) Run(uicontext Context) error {
u.context = uicontext u.context = uicontext
// Initialize the main thread first so the thread is available at u.run (#809). // Initialize the main thread first so the thread is available at u.run (#809).

View File

@ -1,4 +1,4 @@
// Copyright 2019 The Ebiten Authors // Copyright 2022 The Ebiten Authors
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -12,7 +12,33 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package driver package ui
import (
"errors"
)
type Context interface {
UpdateFrame() error
ForceUpdateFrame() error
Layout(outsideWidth, outsideHeight float64)
// AdjustPosition can be called from a different goroutine from Update's or Layout's.
AdjustPosition(x, y float64, deviceScaleFactor float64) (float64, float64)
}
// RegularTermination represents a regular termination.
// Run can return this error, and if this error is received,
// the game loop should be terminated as soon as possible.
var RegularTermination = errors.New("regular termination")
type FPSMode int
const (
FPSModeVsyncOn FPSMode = iota
FPSModeVsyncOffMaximum
FPSModeVsyncOffMinimum
)
type CursorMode int type CursorMode int

View File

@ -41,7 +41,7 @@ func Get() *UserInterface {
return &theUserInterface return &theUserInterface
} }
func (u *UserInterface) Run(context driver.UIContext) error { func (u *UserInterface) Run(context Context) error {
cbackend.InitializeGame() cbackend.InitializeGame()
for { for {
w, h := cbackend.ScreenSize() w, h := cbackend.ScreenSize()
@ -58,7 +58,7 @@ func (u *UserInterface) Run(context driver.UIContext) error {
} }
} }
func (*UserInterface) RunWithoutMainLoop(context driver.UIContext) { func (*UserInterface) RunWithoutMainLoop(context Context) {
panic("ui: RunWithoutMainLoop is not implemented") panic("ui: RunWithoutMainLoop is not implemented")
} }
@ -77,18 +77,18 @@ func (*UserInterface) ScreenSizeInFullscreen() (int, int) {
func (*UserInterface) ResetForFrame() { func (*UserInterface) ResetForFrame() {
} }
func (*UserInterface) CursorMode() driver.CursorMode { func (*UserInterface) CursorMode() CursorMode {
return driver.CursorModeHidden return CursorModeHidden
} }
func (*UserInterface) SetCursorMode(mode driver.CursorMode) { func (*UserInterface) SetCursorMode(mode CursorMode) {
} }
func (*UserInterface) CursorShape() driver.CursorShape { func (*UserInterface) CursorShape() CursorShape {
return driver.CursorShapeDefault return CursorShapeDefault
} }
func (*UserInterface) SetCursorShape(shape driver.CursorShape) { func (*UserInterface) SetCursorShape(shape CursorShape) {
} }
func (*UserInterface) IsFullscreen() bool { func (*UserInterface) IsFullscreen() bool {
@ -105,11 +105,11 @@ func (*UserInterface) IsRunnableOnUnfocused() bool {
func (*UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) { func (*UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) {
} }
func (*UserInterface) FPSMode() driver.FPSMode { func (*UserInterface) FPSMode() FPSMode {
return driver.FPSModeVsyncOn return FPSModeVsyncOn
} }
func (*UserInterface) SetFPSMode(mode driver.FPSMode) { func (*UserInterface) SetFPSMode(mode FPSMode) {
} }
func (*UserInterface) ScheduleFrame() { func (*UserInterface) ScheduleFrame() {

View File

@ -123,7 +123,6 @@ package ui
import "C" import "C"
import ( import (
"github.com/hajimehoshi/ebiten/v2/internal/driver"
"github.com/hajimehoshi/ebiten/v2/internal/glfw" "github.com/hajimehoshi/ebiten/v2/internal/glfw"
) )
@ -179,7 +178,7 @@ func (u *UserInterface) isNativeFullscreen() bool {
return bool(C.isNativeFullscreen(C.uintptr_t(u.window.GetCocoaWindow()))) return bool(C.isNativeFullscreen(C.uintptr_t(u.window.GetCocoaWindow())))
} }
func (u *UserInterface) setNativeCursor(shape driver.CursorShape) { func (u *UserInterface) setNativeCursor(shape CursorShape) {
C.setNativeCursor(C.int(shape)) C.setNativeCursor(C.int(shape))
} }

View File

@ -33,21 +33,21 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/thread" "github.com/hajimehoshi/ebiten/v2/internal/thread"
) )
func driverCursorModeToGLFWCursorMode(mode driver.CursorMode) int { func driverCursorModeToGLFWCursorMode(mode CursorMode) int {
switch mode { switch mode {
case driver.CursorModeVisible: case CursorModeVisible:
return glfw.CursorNormal return glfw.CursorNormal
case driver.CursorModeHidden: case CursorModeHidden:
return glfw.CursorHidden return glfw.CursorHidden
case driver.CursorModeCaptured: case CursorModeCaptured:
return glfw.CursorDisabled return glfw.CursorDisabled
default: default:
panic(fmt.Sprintf("ui: invalid driver.CursorMode: %d", mode)) panic(fmt.Sprintf("ui: invalid CursorMode: %d", mode))
} }
} }
type UserInterface struct { type UserInterface struct {
context driver.UIContext context Context
title string title string
window *glfw.Window window *glfw.Window
@ -66,9 +66,9 @@ type UserInterface struct {
origPosX int origPosX int
origPosY int origPosY int
runnableOnUnfocused bool runnableOnUnfocused bool
fpsMode driver.FPSMode fpsMode FPSMode
iconImages []image.Image iconImages []image.Image
cursorShape driver.CursorShape cursorShape CursorShape
windowClosingHandled bool windowClosingHandled bool
windowBeingClosed bool windowBeingClosed bool
@ -87,7 +87,7 @@ type UserInterface struct {
initFullscreenHeightInDIP int initFullscreenHeightInDIP int
initFullscreen bool initFullscreen bool
initCursorMode driver.CursorMode initCursorMode CursorMode
initWindowDecorated bool initWindowDecorated bool
initWindowResizable bool initWindowResizable bool
initWindowPositionXInDIP int initWindowPositionXInDIP int
@ -129,14 +129,14 @@ var (
maxWindowHeightInDIP: glfw.DontCare, maxWindowHeightInDIP: glfw.DontCare,
origPosX: invalidPos, origPosX: invalidPos,
origPosY: invalidPos, origPosY: invalidPos,
initCursorMode: driver.CursorModeVisible, initCursorMode: CursorModeVisible,
initWindowDecorated: true, initWindowDecorated: true,
initWindowPositionXInDIP: invalidPos, initWindowPositionXInDIP: invalidPos,
initWindowPositionYInDIP: invalidPos, initWindowPositionYInDIP: invalidPos,
initWindowWidthInDIP: 640, initWindowWidthInDIP: 640,
initWindowHeightInDIP: 480, initWindowHeightInDIP: 480,
initFocused: true, initFocused: true,
fpsMode: driver.FPSModeVsyncOn, fpsMode: FPSModeVsyncOn,
} }
) )
@ -160,7 +160,7 @@ func init() {
updateMonitors() updateMonitors()
} }
var glfwSystemCursors = map[driver.CursorShape]*glfw.Cursor{} var glfwSystemCursors = map[CursorShape]*glfw.Cursor{}
func initialize() error { func initialize() error {
if err := glfw.Init(); err != nil { if err := glfw.Init(); err != nil {
@ -191,12 +191,12 @@ func initialize() error {
theUI.initFullscreenHeightInDIP = int(theUI.dipFromGLFWMonitorPixel(float64(v.Height), m)) theUI.initFullscreenHeightInDIP = int(theUI.dipFromGLFWMonitorPixel(float64(v.Height), m))
// Create system cursors. These cursors are destroyed at glfw.Terminate(). // Create system cursors. These cursors are destroyed at glfw.Terminate().
glfwSystemCursors[driver.CursorShapeDefault] = nil glfwSystemCursors[CursorShapeDefault] = nil
glfwSystemCursors[driver.CursorShapeText] = glfw.CreateStandardCursor(glfw.IBeamCursor) glfwSystemCursors[CursorShapeText] = glfw.CreateStandardCursor(glfw.IBeamCursor)
glfwSystemCursors[driver.CursorShapeCrosshair] = glfw.CreateStandardCursor(glfw.CrosshairCursor) glfwSystemCursors[CursorShapeCrosshair] = glfw.CreateStandardCursor(glfw.CrosshairCursor)
glfwSystemCursors[driver.CursorShapePointer] = glfw.CreateStandardCursor(glfw.HandCursor) glfwSystemCursors[CursorShapePointer] = glfw.CreateStandardCursor(glfw.HandCursor)
glfwSystemCursors[driver.CursorShapeEWResize] = glfw.CreateStandardCursor(glfw.HResizeCursor) glfwSystemCursors[CursorShapeEWResize] = glfw.CreateStandardCursor(glfw.HResizeCursor)
glfwSystemCursors[driver.CursorShapeNSResize] = glfw.CreateStandardCursor(glfw.VResizeCursor) glfwSystemCursors[CursorShapeNSResize] = glfw.CreateStandardCursor(glfw.VResizeCursor)
return nil return nil
} }
@ -298,27 +298,27 @@ func (u *UserInterface) setInitFullscreen(initFullscreen bool) {
u.m.Unlock() u.m.Unlock()
} }
func (u *UserInterface) getInitCursorMode() driver.CursorMode { func (u *UserInterface) getInitCursorMode() CursorMode {
u.m.RLock() u.m.RLock()
v := u.initCursorMode v := u.initCursorMode
u.m.RUnlock() u.m.RUnlock()
return v return v
} }
func (u *UserInterface) setInitCursorMode(mode driver.CursorMode) { func (u *UserInterface) setInitCursorMode(mode CursorMode) {
u.m.Lock() u.m.Lock()
u.initCursorMode = mode u.initCursorMode = mode
u.m.Unlock() u.m.Unlock()
} }
func (u *UserInterface) getCursorShape() driver.CursorShape { func (u *UserInterface) getCursorShape() CursorShape {
u.m.RLock() u.m.RLock()
v := u.cursorShape v := u.cursorShape
u.m.RUnlock() u.m.RUnlock()
return v return v
} }
func (u *UserInterface) setCursorShape(shape driver.CursorShape) driver.CursorShape { func (u *UserInterface) setCursorShape(shape CursorShape) CursorShape {
u.m.Lock() u.m.Lock()
old := u.cursorShape old := u.cursorShape
u.cursorShape = shape u.cursorShape = shape
@ -554,7 +554,7 @@ func (u *UserInterface) IsRunnableOnUnfocused() bool {
return u.isRunnableOnUnfocused() return u.isRunnableOnUnfocused()
} }
func (u *UserInterface) SetFPSMode(mode driver.FPSMode) { func (u *UserInterface) SetFPSMode(mode FPSMode) {
if !u.isRunning() { if !u.isRunning() {
u.m.Lock() u.m.Lock()
u.fpsMode = mode u.fpsMode = mode
@ -571,14 +571,14 @@ func (u *UserInterface) SetFPSMode(mode driver.FPSMode) {
}) })
} }
func (u *UserInterface) FPSMode() driver.FPSMode { func (u *UserInterface) FPSMode() FPSMode {
if !u.isRunning() { if !u.isRunning() {
u.m.Lock() u.m.Lock()
m := u.fpsMode m := u.fpsMode
u.m.Unlock() u.m.Unlock()
return m return m
} }
var v driver.FPSMode var v FPSMode
u.t.Call(func() { u.t.Call(func() {
v = u.fpsMode v = u.fpsMode
}) })
@ -594,7 +594,7 @@ func (u *UserInterface) ScheduleFrame() {
glfw.PostEmptyEvent() glfw.PostEmptyEvent()
} }
func (u *UserInterface) CursorMode() driver.CursorMode { func (u *UserInterface) CursorMode() CursorMode {
if !u.isRunning() { if !u.isRunning() {
return u.getInitCursorMode() return u.getInitCursorMode()
} }
@ -604,21 +604,21 @@ func (u *UserInterface) CursorMode() driver.CursorMode {
mode = u.window.GetInputMode(glfw.CursorMode) mode = u.window.GetInputMode(glfw.CursorMode)
}) })
var v driver.CursorMode var v CursorMode
switch mode { switch mode {
case glfw.CursorNormal: case glfw.CursorNormal:
v = driver.CursorModeVisible v = CursorModeVisible
case glfw.CursorHidden: case glfw.CursorHidden:
v = driver.CursorModeHidden v = CursorModeHidden
case glfw.CursorDisabled: case glfw.CursorDisabled:
v = driver.CursorModeCaptured v = CursorModeCaptured
default: default:
panic(fmt.Sprintf("ui: invalid GLFW cursor mode: %d", mode)) panic(fmt.Sprintf("ui: invalid GLFW cursor mode: %d", mode))
} }
return v return v
} }
func (u *UserInterface) SetCursorMode(mode driver.CursorMode) { func (u *UserInterface) SetCursorMode(mode CursorMode) {
if !u.isRunning() { if !u.isRunning() {
u.setInitCursorMode(mode) u.setInitCursorMode(mode)
return return
@ -628,11 +628,11 @@ func (u *UserInterface) SetCursorMode(mode driver.CursorMode) {
}) })
} }
func (u *UserInterface) CursorShape() driver.CursorShape { func (u *UserInterface) CursorShape() CursorShape {
return u.getCursorShape() return u.getCursorShape()
} }
func (u *UserInterface) SetCursorShape(shape driver.CursorShape) { func (u *UserInterface) SetCursorShape(shape CursorShape) {
old := u.setCursorShape(shape) old := u.setCursorShape(shape)
if old == shape { if old == shape {
return return
@ -675,7 +675,7 @@ func init() {
runtime.LockOSThread() runtime.LockOSThread()
} }
func (u *UserInterface) RunWithoutMainLoop(context driver.UIContext) { func (u *UserInterface) RunWithoutMainLoop(context Context) {
panic("ui: RunWithoutMainLoop is not implemented") panic("ui: RunWithoutMainLoop is not implemented")
} }
@ -967,7 +967,7 @@ func (u *UserInterface) updateSize() (float64, float64) {
} }
// setFPSMode must be called from the main thread. // setFPSMode must be called from the main thread.
func (u *UserInterface) setFPSMode(fpsMode driver.FPSMode) { func (u *UserInterface) setFPSMode(fpsMode FPSMode) {
needUpdate := u.fpsMode != fpsMode || !u.fpsModeInited needUpdate := u.fpsMode != fpsMode || !u.fpsModeInited
u.fpsMode = fpsMode u.fpsMode = fpsMode
u.fpsModeInited = true u.fpsModeInited = true
@ -977,7 +977,7 @@ func (u *UserInterface) setFPSMode(fpsMode driver.FPSMode) {
} }
sticky := glfw.True sticky := glfw.True
if fpsMode == driver.FPSModeVsyncOffMinimum { if fpsMode == FPSModeVsyncOffMinimum {
sticky = glfw.False sticky = glfw.False
} }
u.window.SetInputMode(glfw.StickyMouseButtonsMode, sticky) u.window.SetInputMode(glfw.StickyMouseButtonsMode, sticky)
@ -991,7 +991,7 @@ func (u *UserInterface) update() (float64, float64, error) {
} }
if u.window.ShouldClose() { if u.window.ShouldClose() {
return 0, 0, driver.RegularTermination return 0, 0, RegularTermination
} }
if u.isInitFullscreen() { if u.isInitFullscreen() {
@ -1015,7 +1015,7 @@ func (u *UserInterface) update() (float64, float64, error) {
outsideWidth, outsideHeight := u.updateSize() outsideWidth, outsideHeight := u.updateSize()
if u.fpsMode != driver.FPSModeVsyncOffMinimum { if u.fpsMode != FPSModeVsyncOffMinimum {
// TODO: Updating the input can be skipped when clock.Update returns 0 (#1367). // TODO: Updating the input can be skipped when clock.Update returns 0 (#1367).
glfw.PollEvents() glfw.PollEvents()
} else { } else {
@ -1335,13 +1335,13 @@ func (u *UserInterface) updateVsync() {
// TODO: (#405) If triple buffering is needed, SwapInterval(0) should be called, // TODO: (#405) If triple buffering is needed, SwapInterval(0) should be called,
// but is this correct? If glfw.SwapInterval(0) and the driver doesn't support triple // but is this correct? If glfw.SwapInterval(0) and the driver doesn't support triple
// buffering, what will happen? // buffering, what will happen?
if u.fpsMode == driver.FPSModeVsyncOn { if u.fpsMode == FPSModeVsyncOn {
glfw.SwapInterval(1) glfw.SwapInterval(1)
} else { } else {
glfw.SwapInterval(0) glfw.SwapInterval(0)
} }
} }
u.Graphics().SetVsyncEnabled(u.fpsMode == driver.FPSModeVsyncOn) u.Graphics().SetVsyncEnabled(u.fpsMode == FPSModeVsyncOn)
} }
// initialMonitor returns the initial monitor to show the window. // initialMonitor returns the initial monitor to show the window.

View File

@ -29,19 +29,19 @@ var (
stringTransparent = js.ValueOf("transparent") stringTransparent = js.ValueOf("transparent")
) )
func driverCursorShapeToCSSCursor(cursor driver.CursorShape) string { func driverCursorShapeToCSSCursor(cursor CursorShape) string {
switch cursor { switch cursor {
case driver.CursorShapeDefault: case CursorShapeDefault:
return "default" return "default"
case driver.CursorShapeText: case CursorShapeText:
return "text" return "text"
case driver.CursorShapeCrosshair: case CursorShapeCrosshair:
return "crosshair" return "crosshair"
case driver.CursorShapePointer: case CursorShapePointer:
return "pointer" return "pointer"
case driver.CursorShapeEWResize: case CursorShapeEWResize:
return "ew-resize" return "ew-resize"
case driver.CursorShapeNSResize: case CursorShapeNSResize:
return "ns-resize" return "ns-resize"
} }
return "auto" return "auto"
@ -49,20 +49,20 @@ func driverCursorShapeToCSSCursor(cursor driver.CursorShape) string {
type UserInterface struct { type UserInterface struct {
runnableOnUnfocused bool runnableOnUnfocused bool
fpsMode driver.FPSMode fpsMode FPSMode
renderingScheduled bool renderingScheduled bool
running bool running bool
initFocused bool initFocused bool
cursorMode driver.CursorMode cursorMode CursorMode
cursorPrevMode driver.CursorMode cursorPrevMode CursorMode
cursorShape driver.CursorShape cursorShape CursorShape
onceUpdateCalled bool onceUpdateCalled bool
sizeChanged bool sizeChanged bool
lastDeviceScaleFactor float64 lastDeviceScaleFactor float64
context driver.UIContext context Context
input Input input Input
} }
@ -153,11 +153,11 @@ func (u *UserInterface) IsRunnableOnUnfocused() bool {
return u.runnableOnUnfocused return u.runnableOnUnfocused
} }
func (u *UserInterface) SetFPSMode(mode driver.FPSMode) { func (u *UserInterface) SetFPSMode(mode FPSMode) {
u.fpsMode = mode u.fpsMode = mode
} }
func (u *UserInterface) FPSMode() driver.FPSMode { func (u *UserInterface) FPSMode() FPSMode {
return u.fpsMode return u.fpsMode
} }
@ -165,14 +165,14 @@ func (u *UserInterface) ScheduleFrame() {
u.renderingScheduled = true u.renderingScheduled = true
} }
func (u *UserInterface) CursorMode() driver.CursorMode { func (u *UserInterface) CursorMode() CursorMode {
if !canvas.Truthy() { if !canvas.Truthy() {
return driver.CursorModeHidden return CursorModeHidden
} }
return u.cursorMode return u.cursorMode
} }
func (u *UserInterface) SetCursorMode(mode driver.CursorMode) { func (u *UserInterface) SetCursorMode(mode CursorMode) {
if !canvas.Truthy() { if !canvas.Truthy() {
return return
} }
@ -181,35 +181,35 @@ func (u *UserInterface) SetCursorMode(mode driver.CursorMode) {
} }
// Remember the previous cursor mode in the case when the pointer lock exits by pressing ESC. // Remember the previous cursor mode in the case when the pointer lock exits by pressing ESC.
u.cursorPrevMode = u.cursorMode u.cursorPrevMode = u.cursorMode
if u.cursorMode == driver.CursorModeCaptured { if u.cursorMode == CursorModeCaptured {
document.Call("exitPointerLock") document.Call("exitPointerLock")
} }
u.cursorMode = mode u.cursorMode = mode
switch mode { switch mode {
case driver.CursorModeVisible: case CursorModeVisible:
canvas.Get("style").Set("cursor", driverCursorShapeToCSSCursor(u.cursorShape)) canvas.Get("style").Set("cursor", driverCursorShapeToCSSCursor(u.cursorShape))
case driver.CursorModeHidden: case CursorModeHidden:
canvas.Get("style").Set("cursor", stringNone) canvas.Get("style").Set("cursor", stringNone)
case driver.CursorModeCaptured: case CursorModeCaptured:
canvas.Call("requestPointerLock") canvas.Call("requestPointerLock")
} }
} }
func (u *UserInterface) recoverCursorMode() { func (u *UserInterface) recoverCursorMode() {
if theUI.cursorPrevMode == driver.CursorModeCaptured { if theUI.cursorPrevMode == CursorModeCaptured {
panic("ui: cursorPrevMode must not be driver.CursorModeCaptured at recoverCursorMode") panic("ui: cursorPrevMode must not be CursorModeCaptured at recoverCursorMode")
} }
u.SetCursorMode(u.cursorPrevMode) u.SetCursorMode(u.cursorPrevMode)
} }
func (u *UserInterface) CursorShape() driver.CursorShape { func (u *UserInterface) CursorShape() CursorShape {
if !canvas.Truthy() { if !canvas.Truthy() {
return driver.CursorShapeDefault return CursorShapeDefault
} }
return u.cursorShape return u.cursorShape
} }
func (u *UserInterface) SetCursorShape(shape driver.CursorShape) { func (u *UserInterface) SetCursorShape(shape CursorShape) {
if !canvas.Truthy() { if !canvas.Truthy() {
return return
} }
@ -218,7 +218,7 @@ func (u *UserInterface) SetCursorShape(shape driver.CursorShape) {
} }
u.cursorShape = shape u.cursorShape = shape
if u.cursorMode == driver.CursorModeVisible { if u.cursorMode == CursorModeVisible {
canvas.Get("style").Set("cursor", driverCursorShapeToCSSCursor(u.cursorShape)) canvas.Get("style").Set("cursor", driverCursorShapeToCSSCursor(u.cursorShape))
} }
} }
@ -306,7 +306,7 @@ func (u *UserInterface) updateImpl(force bool) error {
} }
func (u *UserInterface) needsUpdate() bool { func (u *UserInterface) needsUpdate() bool {
if u.fpsMode != driver.FPSModeVsyncOffMinimum { if u.fpsMode != FPSModeVsyncOffMinimum {
return true return true
} }
if !u.onceUpdateCalled { if !u.onceUpdateCalled {
@ -319,7 +319,7 @@ func (u *UserInterface) needsUpdate() bool {
return false return false
} }
func (u *UserInterface) loop(context driver.UIContext) <-chan error { func (u *UserInterface) loop(context Context) <-chan error {
u.context = context u.context = context
errCh := make(chan error, 1) errCh := make(chan error, 1)
@ -340,11 +340,11 @@ func (u *UserInterface) loop(context driver.UIContext) <-chan error {
} }
} }
switch u.fpsMode { switch u.fpsMode {
case driver.FPSModeVsyncOn: case FPSModeVsyncOn:
requestAnimationFrame.Invoke(cf) requestAnimationFrame.Invoke(cf)
case driver.FPSModeVsyncOffMaximum: case FPSModeVsyncOffMaximum:
setTimeout.Invoke(cf, 0) setTimeout.Invoke(cf, 0)
case driver.FPSModeVsyncOffMinimum: case FPSModeVsyncOffMinimum:
requestAnimationFrame.Invoke(cf) requestAnimationFrame.Invoke(cf)
} }
} }
@ -463,7 +463,7 @@ func init() {
// Recover the state correctly when the pointer lock exits. // Recover the state correctly when the pointer lock exits.
// A user can exit the pointer lock by pressing ESC. In this case, sync the cursor mode state. // A user can exit the pointer lock by pressing ESC. In this case, sync the cursor mode state.
if theUI.cursorMode == driver.CursorModeCaptured { if theUI.cursorMode == CursorModeCaptured {
theUI.recoverCursorMode() theUI.recoverCursorMode()
} }
theUI.input.recoverCursorPosition() theUI.input.recoverCursorPosition()
@ -586,13 +586,13 @@ func setCanvasEventHandlers(v js.Value) {
} }
func (u *UserInterface) forceUpdateOnMinimumFPSMode() { func (u *UserInterface) forceUpdateOnMinimumFPSMode() {
if u.fpsMode != driver.FPSModeVsyncOffMinimum { if u.fpsMode != FPSModeVsyncOffMinimum {
return return
} }
u.updateImpl(true) u.updateImpl(true)
} }
func (u *UserInterface) Run(context driver.UIContext) error { func (u *UserInterface) Run(context Context) error {
if u.initFocused && window.Truthy() { if u.initFocused && window.Truthy() {
// Do not focus the canvas when the current document is in an iframe. // 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). // Otherwise, the parent page tries to focus the iframe on every loading, which is annoying (#1373).
@ -605,7 +605,7 @@ func (u *UserInterface) Run(context driver.UIContext) error {
return <-u.loop(context) return <-u.loop(context)
} }
func (u *UserInterface) RunWithoutMainLoop(context driver.UIContext) { func (u *UserInterface) RunWithoutMainLoop(context Context) {
panic("ui: RunWithoutMainLoop is not implemented") panic("ui: RunWithoutMainLoop is not implemented")
} }

View File

@ -110,11 +110,11 @@ type UserInterface struct {
setGBuildSizeCh chan struct{} setGBuildSizeCh chan struct{}
once sync.Once once sync.Once
context driver.UIContext context Context
input Input input Input
fpsMode driver.FPSMode fpsMode FPSMode
renderRequester RenderRequester renderRequester RenderRequester
t *thread.OSThread t *thread.OSThread
@ -239,7 +239,7 @@ func (u *UserInterface) SetForeground(foreground bool) error {
} }
} }
func (u *UserInterface) Run(context driver.UIContext) error { func (u *UserInterface) Run(context Context) error {
u.setGBuildSizeCh = make(chan struct{}) u.setGBuildSizeCh = make(chan struct{})
go func() { go func() {
if err := u.run(context, true); err != nil { if err := u.run(context, true); err != nil {
@ -251,7 +251,7 @@ func (u *UserInterface) Run(context driver.UIContext) error {
return nil return nil
} }
func (u *UserInterface) RunWithoutMainLoop(context driver.UIContext) { func (u *UserInterface) RunWithoutMainLoop(context Context) {
go func() { go func() {
if err := u.run(context, false); err != nil { if err := u.run(context, false); err != nil {
u.errCh <- err u.errCh <- err
@ -259,7 +259,7 @@ func (u *UserInterface) RunWithoutMainLoop(context driver.UIContext) {
}() }()
} }
func (u *UserInterface) run(context driver.UIContext, mainloop bool) (err error) { func (u *UserInterface) run(context Context, mainloop bool) (err error) {
// Convert the panic to a regular error so that Java/Objective-C layer can treat this easily e.g., for // 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 // Crashlytics. A panic is treated as SIGABRT, and there is no way to handle this on Java/Objective-C layer
// unfortunately. // unfortunately.
@ -373,19 +373,19 @@ func (u *UserInterface) adjustPosition(x, y int) (int, int) {
return int(xf), int(yf) return int(xf), int(yf)
} }
func (u *UserInterface) CursorMode() driver.CursorMode { func (u *UserInterface) CursorMode() CursorMode {
return driver.CursorModeHidden return CursorModeHidden
} }
func (u *UserInterface) SetCursorMode(mode driver.CursorMode) { func (u *UserInterface) SetCursorMode(mode CursorMode) {
// Do nothing // Do nothing
} }
func (u *UserInterface) CursorShape() driver.CursorShape { func (u *UserInterface) CursorShape() CursorShape {
return driver.CursorShapeDefault return CursorShapeDefault
} }
func (u *UserInterface) SetCursorShape(shape driver.CursorShape) { func (u *UserInterface) SetCursorShape(shape CursorShape) {
// Do nothing // Do nothing
} }
@ -409,11 +409,11 @@ func (u *UserInterface) SetRunnableOnUnfocused(runnableOnUnfocused bool) {
// Do nothing // Do nothing
} }
func (u *UserInterface) FPSMode() driver.FPSMode { func (u *UserInterface) FPSMode() FPSMode {
return u.fpsMode return u.fpsMode
} }
func (u *UserInterface) SetFPSMode(mode driver.FPSMode) { func (u *UserInterface) SetFPSMode(mode FPSMode) {
u.fpsMode = mode u.fpsMode = mode
u.updateExplicitRenderingModeIfNeeded() u.updateExplicitRenderingModeIfNeeded()
} }
@ -422,7 +422,7 @@ func (u *UserInterface) updateExplicitRenderingModeIfNeeded() {
if u.renderRequester == nil { if u.renderRequester == nil {
return return
} }
u.renderRequester.SetExplicitRenderingMode(u.fpsMode == driver.FPSModeVsyncOffMinimum) u.renderRequester.SetExplicitRenderingMode(u.fpsMode == FPSModeVsyncOffMinimum)
} }
func (u *UserInterface) DeviceScaleFactor() float64 { func (u *UserInterface) DeviceScaleFactor() float64 {
@ -462,7 +462,7 @@ type Touch struct {
func (u *UserInterface) UpdateInput(keys map[driver.Key]struct{}, runes []rune, touches []Touch) { func (u *UserInterface) UpdateInput(keys map[driver.Key]struct{}, runes []rune, touches []Touch) {
u.input.update(keys, runes, touches) u.input.update(keys, runes, touches)
if u.fpsMode == driver.FPSModeVsyncOffMinimum { if u.fpsMode == FPSModeVsyncOffMinimum {
u.renderRequester.RequestRenderIfNeeded() u.renderRequester.RequestRenderIfNeeded()
} }
} }
@ -478,7 +478,7 @@ func (u *UserInterface) SetRenderRequester(renderRequester RenderRequester) {
} }
func (u *UserInterface) ScheduleFrame() { func (u *UserInterface) ScheduleFrame() {
if u.renderRequester != nil && u.fpsMode == driver.FPSModeVsyncOffMinimum { if u.renderRequester != nil && u.fpsMode == FPSModeVsyncOffMinimum {
u.renderRequester.RequestRenderIfNeeded() u.renderRequester.RequestRenderIfNeeded()
} }
} }

View File

@ -22,7 +22,6 @@ import (
"math" "math"
"runtime" "runtime"
"github.com/hajimehoshi/ebiten/v2/internal/driver"
"github.com/hajimehoshi/ebiten/v2/internal/glfw" "github.com/hajimehoshi/ebiten/v2/internal/glfw"
"github.com/jezek/xgb" "github.com/jezek/xgb"
"github.com/jezek/xgb/randr" "github.com/jezek/xgb/randr"
@ -152,7 +151,7 @@ func (u *UserInterface) isNativeFullscreen() bool {
return false return false
} }
func (u *UserInterface) setNativeCursor(shape driver.CursorShape) { func (u *UserInterface) setNativeCursor(shape 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])
} }

View File

@ -24,7 +24,6 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"github.com/hajimehoshi/ebiten/v2/internal/driver"
"github.com/hajimehoshi/ebiten/v2/internal/glfw" "github.com/hajimehoshi/ebiten/v2/internal/glfw"
) )
@ -168,7 +167,7 @@ func (u *UserInterface) isNativeFullscreen() bool {
return false return false
} }
func (u *UserInterface) setNativeCursor(shape driver.CursorShape) { func (u *UserInterface) setNativeCursor(shape 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])
} }

17
run.go
View File

@ -18,7 +18,6 @@ import (
"sync/atomic" "sync/atomic"
"github.com/hajimehoshi/ebiten/v2/internal/clock" "github.com/hajimehoshi/ebiten/v2/internal/clock"
"github.com/hajimehoshi/ebiten/v2/internal/driver"
"github.com/hajimehoshi/ebiten/v2/internal/graphicscommand" "github.com/hajimehoshi/ebiten/v2/internal/graphicscommand"
"github.com/hajimehoshi/ebiten/v2/internal/ui" "github.com/hajimehoshi/ebiten/v2/internal/ui"
) )
@ -162,7 +161,7 @@ func RunGame(game Game) error {
game: game, game: game,
}) })
if err := ui.Get().Run(theUIContext); err != nil { if err := ui.Get().Run(theUIContext); err != nil {
if err == driver.RegularTermination { if err == ui.RegularTermination {
return nil return nil
} }
return err return err
@ -325,7 +324,7 @@ func DeviceScaleFactor() float64 {
// //
// Deprecated: as of v2.2. Use FPSMode instead. // Deprecated: as of v2.2. Use FPSMode instead.
func IsVsyncEnabled() bool { func IsVsyncEnabled() bool {
return ui.Get().FPSMode() == driver.FPSModeVsyncOn return ui.Get().FPSMode() == ui.FPSModeVsyncOn
} }
// SetVsyncEnabled sets a boolean value indicating whether // SetVsyncEnabled sets a boolean value indicating whether
@ -334,19 +333,19 @@ func IsVsyncEnabled() bool {
// Deprecated: as of v2.2. Use SetFPSMode instead. // Deprecated: as of v2.2. Use SetFPSMode instead.
func SetVsyncEnabled(enabled bool) { func SetVsyncEnabled(enabled bool) {
if enabled { if enabled {
ui.Get().SetFPSMode(driver.FPSModeVsyncOn) ui.Get().SetFPSMode(ui.FPSModeVsyncOn)
} else { } else {
ui.Get().SetFPSMode(driver.FPSModeVsyncOffMaximum) ui.Get().SetFPSMode(ui.FPSModeVsyncOffMaximum)
} }
} }
// FPSModeType is a type of FPS modes. // FPSModeType is a type of FPS modes.
type FPSModeType = driver.FPSMode type FPSModeType = ui.FPSMode
const ( const (
// FPSModeVsyncOn indicates that the game tries to sync the display's refresh rate. // FPSModeVsyncOn indicates that the game tries to sync the display's refresh rate.
// FPSModeVsyncOn is the default mode. // FPSModeVsyncOn is the default mode.
FPSModeVsyncOn FPSModeType = driver.FPSModeVsyncOn FPSModeVsyncOn FPSModeType = ui.FPSModeVsyncOn
// FPSModeVsyncOffMaximum indicates that the game doesn't sync with vsync, and // FPSModeVsyncOffMaximum indicates that the game doesn't sync with vsync, and
// the game is updated whenever possible. // the game is updated whenever possible.
@ -355,7 +354,7 @@ const (
// //
// In FPSModeVsyncOffMaximum, the game's Draw is called almost without sleeping. // In FPSModeVsyncOffMaximum, the game's Draw is called almost without sleeping.
// The game's Update is called based on the specified TPS. // The game's Update is called based on the specified TPS.
FPSModeVsyncOffMaximum FPSModeType = driver.FPSModeVsyncOffMaximum FPSModeVsyncOffMaximum FPSModeType = ui.FPSModeVsyncOffMaximum
// FPSModeVsyncOffMinimum indicates that the game doesn't sync with vsync, and // FPSModeVsyncOffMinimum indicates that the game doesn't sync with vsync, and
// the game is updated only when necessary. // the game is updated only when necessary.
@ -365,7 +364,7 @@ const (
// In FPSModeVsyncOffMinimum, the game's Update and Draw are called only when // In FPSModeVsyncOffMinimum, the game's Update and Draw are called only when
// 1) new inputting except for gamepads is detected, or 2) ScheduleFrame is called. // 1) new inputting except for gamepads is detected, or 2) ScheduleFrame is called.
// In FPSModeVsyncOffMinimum, TPS is SyncWithFPS no matter what TPS is specified at SetMaxTPS. // In FPSModeVsyncOffMinimum, TPS is SyncWithFPS no matter what TPS is specified at SetMaxTPS.
FPSModeVsyncOffMinimum FPSModeType = driver.FPSModeVsyncOffMinimum FPSModeVsyncOffMinimum FPSModeType = ui.FPSModeVsyncOffMinimum
) )
// FPSMode returns the current FPS mode. // FPSMode returns the current FPS mode.