app: fix racing app.Window.Perform and app.Window.Option

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2022-06-23 14:21:44 +02:00
parent e31aa35622
commit 43116400d0
+44 -20
View File
@@ -54,17 +54,16 @@ type Window struct {
immediateRedraws chan struct{} immediateRedraws chan struct{}
// scheduledRedraws is sent the most recent delayed redraw time. // scheduledRedraws is sent the most recent delayed redraw time.
scheduledRedraws chan time.Time scheduledRedraws chan time.Time
// options are the options waiting to be applied.
options chan []Option
// actions are the actions waiting to be performed.
actions chan system.Action
out chan event.Event out chan event.Event
frames chan *op.Ops frames chan *op.Ops
frameAck chan struct{} frameAck chan struct{}
closing bool
// dead is closed when the window is destroyed. // dead is closed when the window is destroyed.
dead chan struct{} dead chan struct{}
// options are the options waiting to be applied.
options []Option
// actions are the actions waiting to be performed.
actions system.Action
stage system.Stage stage system.Stage
animating bool animating bool
@@ -154,6 +153,8 @@ func NewWindow(options ...Option) *Window {
wakeups: make(chan struct{}, 1), wakeups: make(chan struct{}, 1),
wakeupFuncs: make(chan func()), wakeupFuncs: make(chan func()),
dead: make(chan struct{}), dead: make(chan struct{}),
options: make(chan []Option, 1),
actions: make(chan system.Action, 1),
nocontext: cnf.CustomRenderer, nocontext: cnf.CustomRenderer,
} }
w.imeState.compose = key.Range{Start: -1, End: -1} w.imeState.compose = key.Range{Start: -1, End: -1}
@@ -333,8 +334,18 @@ func (w *Window) Invalidate() {
// Option applies the options to the window. // Option applies the options to the window.
func (w *Window) Option(opts ...Option) { func (w *Window) Option(opts ...Option) {
w.options = append(w.options, opts...) if len(opts) == 0 {
return
}
for {
select {
case old := <-w.options:
opts = append(old, opts...)
case w.options <- opts:
w.wakeup() w.wakeup()
return
}
}
} }
// ReadClipboard initiates a read of the clipboard in the form // ReadClipboard initiates a read of the clipboard in the form
@@ -445,19 +456,24 @@ func (c *callbacks) Event(e event.Event) bool {
c.waitEvents = c.waitEvents[:len(c.waitEvents)-1] c.waitEvents = c.waitEvents[:len(c.waitEvents)-1]
handled = c.w.processEvent(c.d, e) handled = c.w.processEvent(c.d, e)
} }
closing := false
if _, iswakeup := e.(wakeupEvent); iswakeup { if _, iswakeup := e.(wakeupEvent); iswakeup {
if len(c.w.options) > 0 { select {
c.d.Configure(c.w.options) case opts := <-c.w.options:
c.w.options = nil c.d.Configure(opts)
default:
} }
if c.w.actions != 0 { select {
c.d.Perform(c.w.actions) case acts := <-c.w.actions:
c.w.actions = 0 // Pospone closing to last.
closing = (acts & system.ActionClose) != 0
acts &^= system.ActionClose
c.d.Perform(acts)
default:
} }
} }
c.w.updateState(c.d) c.w.updateState(c.d)
if c.w.closing { if closing {
c.w.closing = false
c.d.Close() c.d.Close()
} }
return handled return handled
@@ -1008,20 +1024,28 @@ func (w *Window) Perform(actions system.Action) {
walkActions(actions, func(action system.Action) { walkActions(actions, func(action system.Action) {
switch action { switch action {
case system.ActionMinimize: case system.ActionMinimize:
w.options = append(w.options, Minimized.Option()) w.Option(Minimized.Option())
case system.ActionMaximize: case system.ActionMaximize:
w.options = append(w.options, Maximized.Option()) w.Option(Maximized.Option())
case system.ActionUnmaximize: case system.ActionUnmaximize:
w.options = append(w.options, Windowed.Option()) w.Option(Windowed.Option())
case system.ActionClose:
w.closing = true
default: default:
return return
} }
actions &^= action actions &^= action
}) })
w.actions = w.actions | actions if actions == 0 {
return
}
for {
select {
case old := <-w.actions:
actions |= old
case w.actions <- actions:
w.wakeup() w.wakeup()
return
}
}
} }
func (q *queue) Events(k event.Tag) []event.Event { func (q *queue) Events(k event.Tag) []event.Event {