uidriver: Remove width/height/scale arguments from run

The initial window position is determined on ebiten package side.

Updates #943
This commit is contained in:
Hajime Hoshi 2019-12-17 12:28:52 +09:00
parent d07028735f
commit dabaf66b81
5 changed files with 108 additions and 61 deletions

View File

@ -44,6 +44,7 @@ type UI interface {
ScreenSizeInFullscreen() (int, int)
WindowPosition() (int, int)
IsScreenTransparent() bool
MonitorPosition() (int, int)
CanHaveWindow() bool // TODO: Create a 'Widnow' interface.
SetCursorMode(mode CursorMode)

View File

@ -129,14 +129,12 @@ func initialize() error {
panic("glfw: glfw.CreateWindow must not return nil")
}
// TODO: Fix this hack. currentMonitor now requires u.window on POSIX.
// Create a window and leave it as it is: this affects the result of currentMonitorFromPosition.
theUI.window = w
theUI.initMonitor = theUI.currentMonitor()
v := theUI.initMonitor.GetVideoMode()
theUI.initFullscreenWidthInDP = int(theUI.toDeviceIndependentPixel(float64(v.Width)))
theUI.initFullscreenHeightInDP = int(theUI.toDeviceIndependentPixel(float64(v.Height)))
theUI.window.Destroy()
theUI.window = nil
return nil
}
@ -568,7 +566,7 @@ func (u *UserInterface) Run(width, height int, scale float64, title string, uico
go func() {
defer cancel()
defer close(ch)
if err := u.run(width, height, scale, title, uicontext); err != nil {
if err := u.run(title, uicontext); err != nil {
ch <- err
}
}()
@ -632,15 +630,12 @@ func (u *UserInterface) createWindow() error {
return nil
}
func (u *UserInterface) run(width, height int, scale float64, title string, context driver.UIContext) error {
var (
m *glfw.Monitor
mx, my int
v *glfw.VidMode
ww, wh int
)
func (u *UserInterface) run(title string, context driver.UIContext) error {
if err := u.t.Call(func() error {
// The window is created at initialize().
u.window.Destroy()
u.window = nil
if u.graphics.IsGL() {
glfw.WindowHint(glfw.ContextVersionMajor, 2)
glfw.WindowHint(glfw.ContextVersionMinor, 1)
@ -679,53 +674,16 @@ func (u *UserInterface) run(width, height int, scale float64, title string, cont
if i := u.getInitIconImages(); i != nil {
u.window.SetIcon(i)
}
// Get the monitor before showing the window.
//
// On Windows, there are two types of windows:
//
// active window: The window that has input-focus and attached to the calling thread.
// foreground window: The window that has input-focus: this can be in another process
//
// currentMonitor returns the monitor for the active window when possible and then the monitor for
// the foreground window as fallback. In the current situation, the current window is hidden and
// there is not the active window but the foreground window. After showing the current window, the
// current window will be the active window. Thus, currentMonitor result varies before and after
// showing the window.
m = u.currentMonitor()
mx, my = m.GetPos()
v = m.GetVideoMode()
ww = int(u.toDeviceDependentPixel(float64(width) * scale))
wh = int(u.toDeviceDependentPixel(float64(height) * scale))
return nil
}); err != nil {
return err
}
// The game is in window mode (not fullscreen mode) at the first state.
// Don't refer u.initFullscreen here to avoid some GLFW problems.
u.setWindowSize(ww, wh, false, u.vsync)
u.SetWindowPosition(u.getInitWindowPosition())
_ = u.t.Call(func() error {
// Get the window size before showing it. Showing the window might change the current monitor which
// affects deviceDependentWindowSize result.
w, h := u.window.GetSize()
u.title = title
u.window.SetTitle(title)
x, y := u.getInitWindowPosition()
if x == invalidPos || y == invalidPos {
x = mx + (v.Width-w)/2
y = my + (v.Height-h)/3
}
// Adjusting the position is needed only when the monitor is primary. (#829)
if mx == 0 && my == 0 {
x, y = adjustWindowPosition(x, y)
}
u.window.SetPos(x, y)
u.window.Show()
return nil
@ -1042,9 +1000,11 @@ func (u *UserInterface) setWindowSize(width, height int, fullscreen bool, vsync
//
// currentMonitor must be called on the main thread.
func (u *UserInterface) currentMonitor() *glfw.Monitor {
w := u.window
if m := w.GetMonitor(); m != nil {
return m
if w := u.window; w != nil {
// TODO: When is the monitor nil?
if m := w.GetMonitor(); m != nil {
return m
}
}
// Get the monitor which the current window belongs to. This requires OS API.
return u.currentMonitorFromPosition()
@ -1058,10 +1018,11 @@ func (u *UserInterface) SetWindowPosition(x, y int) {
_ = u.t.Call(func() error {
xf := u.toDeviceDependentPixel(float64(x))
yf := u.toDeviceDependentPixel(float64(y))
x, y := adjustWindowPosition(int(xf), int(yf))
if u.isFullscreen() {
u.origPosX, u.origPosY = int(xf), int(yf)
u.origPosX, u.origPosY = x, y
} else {
u.window.SetPos(int(xf), int(yf))
u.window.SetPos(x, y)
}
return nil
})
@ -1116,6 +1077,23 @@ func (u *UserInterface) SetWindowSize(width, height int) {
u.setWindowSize(w, h, u.isFullscreen(), u.vsync)
}
func (u *UserInterface) MonitorPosition() (int, int) {
if !u.isRunning() {
return u.monitorPosition()
}
var mx, my int
_ = u.t.Call(func() error {
mx, my = u.monitorPosition()
return nil
})
return mx, my
}
func (u *UserInterface) monitorPosition() (int, int) {
// TODO: toDeviceIndependentPixel might be required.
return u.currentMonitor().GetPos()
}
func (u *UserInterface) CanHaveWindow() bool {
return true
}

View File

@ -59,12 +59,14 @@ func (u *UserInterface) currentMonitorFromPosition() *glfw.Monitor {
x := C.int(0)
y := C.int(0)
// Note: [NSApp mainWindow] is nil when it doesn't have its border. Use u.window here.
win := u.window.GetCocoaWindow()
C.currentMonitorPos(win, &x, &y)
for _, m := range glfw.GetMonitors() {
mx, my := m.GetPos()
if int(x) == mx && int(y) == my {
return m
if u.window != nil {
win := u.window.GetCocoaWindow()
C.currentMonitorPos(win, &x, &y)
for _, m := range glfw.GetMonitors() {
mx, my := m.GetPos()
if int(x) == mx && int(y) == my {
return m
}
}
}
return glfw.GetPrimaryMonitor()

1
run.go
View File

@ -156,6 +156,7 @@ func Run(f func(*Image) error, width, height int, scale float64, title string) e
}
theUIContext = newUIContext(game, scale)
fixWindowPosition(int(float64(width)*scale), int(float64(height)*scale))
if err := uiDriver().Run(width, height, scale, title, theUIContext, graphicsDriver()); err != nil {
if err == driver.RegularTermination {
return nil

View File

@ -16,6 +16,13 @@ package ebiten
import (
"image"
"sync"
)
const (
maxInt = int(^uint(0) >> 1)
minInt = -maxInt - 1
invalidPos = minInt
)
// SetWindowDecorated sets the state if the window is decorated.
@ -105,6 +112,9 @@ func SetWindowIcon(iconImages []image.Image) {
//
// WindowPosition is concurrent-safe.
func WindowPosition() (x, y int) {
if x, y, ok := initWindowPosition(); ok {
return x, y
}
return uiDriver().WindowPosition()
}
@ -118,5 +128,60 @@ func WindowPosition() (x, y int) {
//
// SetWindowPosition is concurrent-safe.
func SetWindowPosition(x, y int) {
if setInitWindowPosition(x, y) {
return
}
uiDriver().SetWindowPosition(x, y)
}
var (
windowM sync.Mutex
mainLoopStarted bool
initWindowPositionX = invalidPos
initWindowPositionY = invalidPos
)
func initWindowPosition() (x, y int, ok bool) {
windowM.Lock()
defer windowM.Unlock()
if mainLoopStarted {
return 0, 0, false
}
if initWindowPositionX == invalidPos || initWindowPositionY == invalidPos {
return 0, 0, false
}
return initWindowPositionX, initWindowPositionY, true
}
func setInitWindowPosition(x, y int) bool {
windowM.Lock()
defer windowM.Unlock()
if mainLoopStarted {
return false
}
initWindowPositionX, initWindowPositionY = x, y
return true
}
func fixWindowPosition(width, height int) {
windowM.Lock()
defer windowM.Unlock()
defer func() {
mainLoopStarted = true
}()
if !uiDriver().CanHaveWindow() {
return
}
if initWindowPositionX == invalidPos || initWindowPositionY == invalidPos {
mx, my := uiDriver().MonitorPosition()
sw, sh := uiDriver().ScreenSizeInFullscreen()
x := mx + (sw-width)/2
y := my + (sh-height)/3
uiDriver().SetWindowPosition(x, y)
} else {
uiDriver().SetWindowPosition(initWindowPositionX, initWindowPositionY)
}
}