ui: Implement SetWindowDecorated and IsWindowDecorated

Fixes #430.
This commit is contained in:
Hajime Hoshi 2017-09-14 03:37:38 +09:00
parent ce4e00ff79
commit 526fbd3619
5 changed files with 120 additions and 13 deletions

View File

@ -18,6 +18,8 @@ package main
import ( import (
"bytes" "bytes"
"errors"
"flag"
"fmt" "fmt"
"image" "image"
"image/color" "image/color"
@ -33,6 +35,10 @@ import (
"github.com/hajimehoshi/ebiten/inpututil" "github.com/hajimehoshi/ebiten/inpututil"
) )
var (
windowDecorated = flag.Bool("windowdecorated", true, "whether the window is decorated")
)
func init() { func init() {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
} }
@ -67,7 +73,13 @@ func createRandomIconImage() image.Image {
return img return img
} }
var terminated = errors.New("terminated")
func update(screen *ebiten.Image) error { func update(screen *ebiten.Image) error {
if inpututil.IsKeyJustPressed(ebiten.KeyQ) {
return terminated
}
screenScale := ebiten.ScreenScale() screenScale := ebiten.ScreenScale()
d := int(32 / screenScale) d := int(32 / screenScale)
screenWidth, screenHeight := screen.Size() screenWidth, screenHeight := screen.Size()
@ -145,6 +157,7 @@ Press F key to switch the fullscreen state
Press B key to switch the run-in-background state Press B key to switch the run-in-background state
Press C key to switch the cursor visibility Press C key to switch the cursor visibility
Press I key to change the window icon Press I key to change the window icon
Press Q key to quit
Cursor: (%d, %d) Cursor: (%d, %d)
FPS: %0.2f`, x, y, ebiten.CurrentFPS()) FPS: %0.2f`, x, y, ebiten.CurrentFPS())
ebitenutil.DebugPrint(screen, msg) ebitenutil.DebugPrint(screen, msg)
@ -152,6 +165,8 @@ FPS: %0.2f`, x, y, ebiten.CurrentFPS())
} }
func main() { func main() {
flag.Parse()
fmt.Printf("Device scale factor: %0.2f\n", ebiten.DeviceScaleFactor()) fmt.Printf("Device scale factor: %0.2f\n", ebiten.DeviceScaleFactor())
// Decode image from a byte slice instead of a file so that // Decode image from a byte slice instead of a file so that
@ -171,7 +186,9 @@ func main() {
ebiten.SetWindowIcon([]image.Image{createRandomIconImage()}) ebiten.SetWindowIcon([]image.Image{createRandomIconImage()})
if err := ebiten.Run(update, initScreenWidth, initScreenHeight, initScreenScale, "Window Size (Ebiten Demo)"); err != nil { ebiten.SetWindowDecorated(*windowDecorated)
if err := ebiten.Run(update, initScreenWidth, initScreenHeight, initScreenScale, "Window Size (Ebiten Demo)"); err != nil && err != terminated {
log.Fatal(err) log.Fatal(err)
} }
} }

View File

@ -48,9 +48,10 @@ type userInterface struct {
origPosY int origPosY int
runnableInBackground bool runnableInBackground bool
initFullscreen bool initFullscreen bool
initCursorVisible bool initCursorVisible bool
initIconImages []image.Image initWindowDecorated bool
initIconImages []image.Image
funcs chan func() funcs chan func()
@ -59,10 +60,10 @@ type userInterface struct {
var ( var (
currentUI = &userInterface{ currentUI = &userInterface{
toChangeSize: true, origPosX: -1,
origPosX: -1, origPosY: -1,
origPosY: -1, initCursorVisible: true,
initCursorVisible: true, initWindowDecorated: true,
} }
currentUIInitialized = make(chan struct{}) currentUIInitialized = make(chan struct{})
) )
@ -80,6 +81,12 @@ func initialize() error {
glfw.WindowHint(glfw.ContextVersionMajor, 2) glfw.WindowHint(glfw.ContextVersionMajor, 2)
glfw.WindowHint(glfw.ContextVersionMinor, 1) glfw.WindowHint(glfw.ContextVersionMinor, 1)
decorated := glfw.False
if currentUI.isInitWindowDecorated() {
decorated = glfw.True
}
glfw.WindowHint(glfw.Decorated, decorated)
// As start, create an window with temporary size to create OpenGL context thread. // As start, create an window with temporary size to create OpenGL context thread.
window, err := glfw.CreateWindow(16, 16, "", nil, nil) window, err := glfw.CreateWindow(16, 16, "", nil, nil)
if err != nil { if err != nil {
@ -99,6 +106,7 @@ func initialize() error {
currentUI.window.SetIcon(i) currentUI.window.SetIcon(i)
} }
currentUI.window.SetInputMode(glfw.CursorMode, mode) currentUI.window.SetInputMode(glfw.CursorMode, mode)
currentUI.window.SetInputMode(glfw.StickyMouseButtonsMode, glfw.True) currentUI.window.SetInputMode(glfw.StickyMouseButtonsMode, glfw.True)
currentUI.window.SetInputMode(glfw.StickyKeysMode, glfw.True) currentUI.window.SetInputMode(glfw.StickyKeysMode, glfw.True)
return nil return nil
@ -167,6 +175,19 @@ func (u *userInterface) setInitCursorVisible(visible bool) {
u.m.Unlock() u.m.Unlock()
} }
func (u *userInterface) isInitWindowDecorated() bool {
u.m.Lock()
v := u.initWindowDecorated
u.m.Unlock()
return v
}
func (u *userInterface) setInitWindowDecorated(decorated bool) {
u.m.Lock()
u.initWindowDecorated = decorated
u.m.Unlock()
}
func (u *userInterface) isRunnableInBackground() bool { func (u *userInterface) isRunnableInBackground() bool {
u.m.Lock() u.m.Lock()
v := u.runnableInBackground v := u.runnableInBackground
@ -369,6 +390,40 @@ func SetCursorVisible(visible bool) {
}) })
} }
func IsWindowDecorated() bool {
u := currentUI
if !u.isRunning() {
return u.isInitWindowDecorated()
}
v := false
_ = currentUI.runOnMainThread(func() error {
v = currentUI.window.GetAttrib(glfw.Decorated) == glfw.True
return nil
})
return v
}
func SetWindowDecorated(decorated bool) {
u := currentUI
if !u.isRunning() {
u.setInitWindowDecorated(decorated)
return
}
panic("ui: SetWindowDecorated can't be called after Run so far.")
// TODO: Now SetAttrib doesn't exist on GLFW 3.2. Revisit later.
// If SetAttrib exists, the implementation would be:
//
// _ = currentUI.runOnMainThread(func() error {
// v := glfw.False
// if decorated {
// v = glfw.True
// }
// currentUI.window.SetAttrib(glfw.Decorated, v)
// return nil
}
func Run(width, height int, scale float64, title string, g GraphicsContext) error { func Run(width, height int, scale float64, title string, g GraphicsContext) error {
<-currentUIInitialized <-currentUIInitialized

View File

@ -98,6 +98,14 @@ func SetWindowIcon(iconImages []image.Image) {
// Do nothing // Do nothing
} }
func IsWindowDecorated() bool {
return false
}
func SetWindowDecorated(decorated bool) {
// Do nothing
}
func (u *userInterface) getScale() float64 { func (u *userInterface) getScale() float64 {
if !u.fullscreen { if !u.fullscreen {
return u.scale return u.scale

View File

@ -172,12 +172,15 @@ func SetCursorVisible(visible bool) {
// Do nothing // Do nothing
} }
func IsFullscreen() bool {
return false
}
func SetFullscreen(fullscreen bool) { func SetFullscreen(fullscreen bool) {
// Do nothing // Do nothing
} }
func IsFullscreen() bool { func IsRunnableInBackground() bool {
// Do nothing
return false return false
} }
@ -185,12 +188,15 @@ func SetRunnableInBackground(runnableInBackground bool) {
// Do nothing // Do nothing
} }
func IsRunnableInBackground() bool { func SetWindowIcon(iconImages []image.Image) {
// Do nothing // Do nothing
}
func IsWindowDecorated() bool {
return false return false
} }
func SetWindowIcon(iconImages []image.Image) { func SetWindowDecorated(decorated bool) {
// Do nothing // Do nothing
} }

23
run.go
View File

@ -246,13 +246,34 @@ func SetFullscreen(fullscreen bool) {
ui.SetFullscreen(fullscreen) ui.SetFullscreen(fullscreen)
} }
// IsRunnableInBackground returns a boolean value indicating whether the game runs even in background. // IsRunnableInBackground returns a boolean value indicating whether
// the game runs even in background.
// //
// This function is concurrent-safe. // This function is concurrent-safe.
func IsRunnableInBackground() bool { func IsRunnableInBackground() bool {
return ui.IsRunnableInBackground() return ui.IsRunnableInBackground()
} }
// SetWindowDecorated sets the state if the window is decorated.
//
// SetWindowDecorated works only on desktops.
// SetWindowDecorated does nothing on other platforms.
//
// SetWindowDecorated panics if SetWindowDecorated is called after Run.
//
// This function is concurrent-safe.
func SetWindowDecorated(decorated bool) {
ui.SetWindowDecorated(decorated)
}
// IsWindowDecorated returns a boolean value indicating whether
// the window is decorated.
//
// This function is concurrent-safe.
func IsWindowDecorated() bool {
return ui.IsWindowDecorated()
}
// SetRunnableInBackground sets the state if the game runs even in background. // SetRunnableInBackground sets the state if the game runs even in background.
// //
// If the given value is true, the game runs in background e.g. when losing focus. // If the given value is true, the game runs in background e.g. when losing focus.