app: ensure waiting window requests are stopped when a window closes

The Android RegisterFragment method would leak a goroutine if called
after the window was destroyed.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-05-16 11:13:37 +02:00
parent b99151c211
commit e093ea28f7
2 changed files with 20 additions and 7 deletions
+4 -6
View File
@@ -27,10 +27,8 @@ type androidDriver interface {
// and registers it as a Fragment in the Context in which the View was // and registers it as a Fragment in the Context in which the View was
// created. // created.
func (w *Window) RegisterFragment(del string) { func (w *Window) RegisterFragment(del string) {
go func() { w.driverDo(func() {
w.driverFuncs <- func() { d := w.driver.(androidDriver)
d := w.driver.(androidDriver) d.RegisterFragment(del)
d.RegisterFragment(del) })
}
}()
} }
+16 -1
View File
@@ -37,6 +37,8 @@ type Window struct {
invalidates chan struct{} invalidates chan struct{}
frames chan *op.Ops frames chan *op.Ops
frameAck chan struct{} frameAck chan struct{}
// dead is closed when the window is destroyed.
dead chan struct{}
stage system.Stage stage system.Stage
animating bool animating bool
@@ -96,6 +98,7 @@ func NewWindow(options ...Option) *Window {
frames: make(chan *op.Ops), frames: make(chan *op.Ops),
frameAck: make(chan struct{}), frameAck: make(chan struct{}),
driverFuncs: make(chan func()), driverFuncs: make(chan func()),
dead: make(chan struct{}),
} }
w.callbacks.w = w w.callbacks.w = w
go w.run(opts) go w.run(opts)
@@ -188,6 +191,17 @@ func (w *Window) Invalidate() {
} }
} }
// driverDo calls f as soon as the window has a valid driver attached,
// or does nothing if the window is destroyed while waiting.
func (w *Window) driverDo(f func()) {
go func() {
select {
case w.driverFuncs <- f:
case <-w.dead:
}
}()
}
func (w *Window) updateAnimation() { func (w *Window) updateAnimation() {
animate := false animate := false
if w.delayedDraw != nil { if w.delayedDraw != nil {
@@ -236,6 +250,7 @@ func (w *Window) destroy(err error) {
// Ack the current event. // Ack the current event.
w.ack <- struct{}{} w.ack <- struct{}{}
w.out <- system.DestroyEvent{Err: err} w.out <- system.DestroyEvent{Err: err}
close(w.dead)
for e := range w.in { for e := range w.in {
w.ack <- struct{}{} w.ack <- struct{}{}
if _, ok := e.(system.DestroyEvent); ok { if _, ok := e.(system.DestroyEvent); ok {
@@ -274,7 +289,7 @@ func (w *Window) run(opts *window.Options) {
return return
} }
for { for {
var driverFuncs chan func() = nil var driverFuncs chan func()
if w.driver != nil { if w.driver != nil {
driverFuncs = w.driverFuncs driverFuncs = w.driverFuncs
} }