io/input: implement lazy event routing

This change defers event routing from the time the event is queued until
the time Events is called. This allows a future change to execute
commands immediately and to react to event order changes during a frame.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2023-11-15 19:14:14 -06:00
parent 651094d692
commit 9dfada745c
8 changed files with 390 additions and 230 deletions
+24 -19
View File
@@ -9,8 +9,12 @@ import (
"gioui.org/io/event"
)
// clipboardState contains the state for clipboard event routing.
type clipboardState struct {
receivers []event.Tag
}
type clipboardQueue struct {
receivers map[event.Tag]struct{}
// request avoid read clipboard every frame while waiting.
requested bool
mime string
@@ -28,22 +32,21 @@ func (q *clipboardQueue) WriteClipboard() (mime string, content []byte, ok bool)
return q.mime, content, true
}
// ReadClipboard reports if any new handler is waiting
// ClipboardRequested reports if any new handler is waiting
// to read the clipboard.
func (q *clipboardQueue) ReadClipboard() bool {
if len(q.receivers) == 0 || q.requested {
return false
}
q.requested = true
return true
func (q *clipboardQueue) ClipboardRequested(state clipboardState) bool {
req := len(state.receivers) > 0 && q.requested
q.requested = false
return req
}
func (q *clipboardQueue) Push(evts []taggedEvent, e event.Event) []taggedEvent {
for r := range q.receivers {
func (q *clipboardQueue) Push(state clipboardState, e event.Event) (clipboardState, []taggedEvent) {
var evts []taggedEvent
for _, r := range state.receivers {
evts = append(evts, taggedEvent{tag: r, event: e})
delete(q.receivers, r)
}
return evts
state.receivers = nil
return state, evts
}
func (q *clipboardQueue) ProcessWriteClipboard(req clipboard.WriteCmd) {
@@ -56,12 +59,14 @@ func (q *clipboardQueue) ProcessWriteClipboard(req clipboard.WriteCmd) {
q.text = content
}
func (q *clipboardQueue) ProcessReadClipboard(tag event.Tag) {
if q.receivers == nil {
q.receivers = make(map[event.Tag]struct{})
}
if _, ok := q.receivers[tag]; !ok {
q.receivers[tag] = struct{}{}
q.requested = false
func (q *clipboardQueue) ProcessReadClipboard(state clipboardState, tag event.Tag) clipboardState {
for _, k := range state.receivers {
if k == tag {
return state
}
}
n := len(state.receivers)
state.receivers = append(state.receivers[:n:n], tag)
q.requested = true
return state
}