ui/app: introduce DestroyEvent for ending the event loop

Replace the StageDead stage with DestroyEvent dedicated to ending
the event loop and, for premature window closes, the error.

Drop the error return from NewWindow; any errors in window creation
will appear as an immediate DestroyEvent with its Err field set.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-07-13 11:41:12 +02:00
parent 8e307b40a6
commit 59e92e8233
6 changed files with 51 additions and 30 deletions
+25 -16
View File
@@ -29,7 +29,6 @@ type Window struct {
drawStart time.Time
gpu *gpu.GPU
inputState key.TextInputState
err error
events chan Event
@@ -70,7 +69,7 @@ var ackEvent Event
// ignore or adjust them.
// If the current program is running on iOS and Android,
// NewWindow returns the window previously by the platform.
func NewWindow(opts *WindowOptions) (*Window, error) {
func NewWindow(opts *WindowOptions) *Window {
if opts == nil {
opts = &WindowOptions{
Width: ui.Dp(800),
@@ -87,9 +86,11 @@ func NewWindow(opts *WindowOptions) (*Window, error) {
stage: StagePaused,
}
if err := createWindow(w, opts); err != nil {
return nil, err
// For simplicity, NewWindow always succeeds. Send
// an immediate DestroyEvent instead of returning the error.
w.destroy(err)
}
return w, nil
return w
}
func (w *Window) Events() <-chan Event {
@@ -107,10 +108,6 @@ func (w *Window) setTextInput(s key.TextInputState) {
w.inputState = s
}
func (w *Window) Err() error {
return w.err
}
func (w *Window) Queue() input.Queue {
return &w.router
}
@@ -144,12 +141,12 @@ func (w *Window) Draw(root *ui.Ops) {
if w.gpu == nil {
ctx, err := newContext(driver)
if err != nil {
w.err = err
w.destroy(err)
return
}
w.gpu, err = gpu.NewGPU(ctx)
if err != nil {
w.err = err
w.destroy(err)
return
}
}
@@ -190,6 +187,9 @@ func (w *Window) updateAnimation() {
w.delayedDraw.Stop()
w.delayedDraw = nil
}
if !w.isAlive() {
return
}
if w.stage >= StageRunning && w.hasNextFrame {
if dt := time.Until(w.nextFrame); dt <= 0 {
animate = true
@@ -223,7 +223,7 @@ func (w *Window) Stage() Stage {
}
func (w *Window) isAlive() bool {
return w.stage > StageDead && w.err == nil
return w.driver != nil
}
func (w *Window) contextDriver() interface{} {
@@ -236,10 +236,18 @@ func (w *Window) setDriver(d *window) {
w.driver = d
}
func (w *Window) destroy(err error) {
w.setDriver(nil)
go func() {
w.event(DestroyEvent{err})
}()
}
func (w *Window) event(e Event) {
w.eventLock.Lock()
defer w.eventLock.Unlock()
w.mu.Lock()
died := false
needAck := false
switch e := e.(type) {
case input.Event:
@@ -248,12 +256,13 @@ func (w *Window) event(e Event) {
}
case *CommandEvent:
needAck = true
case DestroyEvent:
w.driver = nil
died = true
case StageEvent:
w.stage = e.Stage
if w.stage > StageDead {
needAck = true
w.syncGPU = true
}
needAck = true
w.syncGPU = true
case DrawEvent:
if e.Size == (image.Point{}) {
panic(errors.New("internal error: zero-sized Draw"))
@@ -290,7 +299,7 @@ func (w *Window) event(e Event) {
w.gpu.Refresh()
}
}
if stage == StageDead {
if died {
close(w.events)
}
}