Skip to content

Commit

Permalink
uidriver/js: Bug fix: Watch the state regularly instead of events
Browse files Browse the repository at this point in the history
visibilitystate is sometimes not called and in this case the app
does not come back.

This fix creates another goroutine to watch the state, and remove
event handlers.

Fixes #961
  • Loading branch information
hajimehoshi committed Oct 20, 2019
1 parent 016a9a6 commit e761113
Showing 1 changed file with 29 additions and 38 deletions.
67 changes: 29 additions & 38 deletions internal/uidriver/js/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@ import (
"runtime"
"strconv"
"syscall/js"
"time"

"github.com/hajimehoshi/ebiten/internal/devicescale"
"github.com/hajimehoshi/ebiten/internal/driver"
)

var canvas js.Value

type UserInterface struct {
width int
height int
Expand All @@ -37,8 +36,6 @@ type UserInterface struct {
vsync bool

sizeChanged bool
windowFocus bool
pageVisible bool
contextLost bool

lastActualScale float64
Expand All @@ -53,8 +50,6 @@ type UserInterface struct {

var theUI = &UserInterface{
sizeChanged: true,
windowFocus: true,
pageVisible: true,
vsync: true,
}

Expand All @@ -69,6 +64,7 @@ func Get() *UserInterface {
var (
window = js.Global().Get("window")
document = js.Global().Get("document")
canvas js.Value
requestAnimationFrame = window.Get("requestAnimationFrame")
setTimeout = window.Get("setTimeout")
)
Expand Down Expand Up @@ -189,7 +185,17 @@ func (u *UserInterface) updateSize() {
}

func (u *UserInterface) suspended() bool {
return !u.runnableInBackground && (!u.windowFocus || !u.pageVisible)
if u.runnableInBackground {
return false
}

if !document.Call("hasFocus").Bool() {
return true
}
if document.Get("hidden").Bool() {
return true
}
return false
}

func (u *UserInterface) update() error {
Expand All @@ -210,7 +216,7 @@ func (u *UserInterface) update() error {
}

func (u *UserInterface) loop(context driver.UIContext) <-chan error {
u.init(context)
u.context = context

ch := make(chan error)
var cf js.Func
Expand Down Expand Up @@ -238,38 +244,23 @@ func (u *UserInterface) loop(context driver.UIContext) <-chan error {
go func() {
f(js.Value{}, nil)
}()
return ch
}

func (u *UserInterface) init(context driver.UIContext) {
u.context = context
window.Call("addEventListener", "focus", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
u.windowFocus = true
if u.suspended() {
u.context.SuspendAudio()
} else {
u.context.ResumeAudio()
}
return nil
}))
window.Call("addEventListener", "blur", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
u.windowFocus = false
if u.suspended() {
u.context.SuspendAudio()
} else {
u.context.ResumeAudio()
}
return nil
}))
document.Call("addEventListener", "visibilitychange", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
u.pageVisible = !document.Get("hidden").Bool()
if u.suspended() {
u.context.SuspendAudio()
} else {
u.context.ResumeAudio()
// Run another loop to watch suspended() as the above update function is never called when the tab is hidden.
// To check the document's visiblity, visibilitychange event should usually be used. However, this event is
// not reliable and sometimes it is not fired (#961). Then, watch the state regularly instead.
go func() {
t := time.NewTicker(100 * time.Millisecond)
defer t.Stop()
for range t.C {
if u.suspended() {
u.context.SuspendAudio()
} else {
u.context.ResumeAudio()
}
}
return nil
}))
}()

return ch
}

func init() {
Expand Down

0 comments on commit e761113

Please sign in to comment.