io/input: merge event queues

Replace the per-event event queues with a single queue of events, each
marked with the target tag. This change is a prerequisite for lazy event
delivery.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2023-11-15 17:25:16 -06:00
parent 3ba5fc557c
commit 651094d692
4 changed files with 141 additions and 141 deletions
+3 -2
View File
@@ -38,11 +38,12 @@ func (q *clipboardQueue) ReadClipboard() bool {
return true return true
} }
func (q *clipboardQueue) Push(e event.Event, events *handlerEvents) { func (q *clipboardQueue) Push(evts []taggedEvent, e event.Event) []taggedEvent {
for r := range q.receivers { for r := range q.receivers {
events.Add(r, e) evts = append(evts, taggedEvent{tag: r, event: e})
delete(q.receivers, r) delete(q.receivers, r)
} }
return evts
} }
func (q *clipboardQueue) ProcessWriteClipboard(req clipboard.WriteCmd) { func (q *clipboardQueue) ProcessWriteClipboard(req clipboard.WriteCmd) {
+12 -14
View File
@@ -167,10 +167,10 @@ func (q *keyQueue) updateFocusLayout() {
} }
} }
// MoveFocus attempts to move the focus in the direction of dir, returning true if it succeeds. // MoveFocus attempts to move the focus in the direction of dir.
func (q *keyQueue) MoveFocus(dir key.FocusDirection, events *handlerEvents) bool { func (q *keyQueue) MoveFocus(evts []taggedEvent, dir key.FocusDirection) []taggedEvent {
if len(q.dirOrder) == 0 { if len(q.dirOrder) == 0 {
return false return nil
} }
order := 0 order := 0
if q.focus != nil { if q.focus != nil {
@@ -195,8 +195,7 @@ func (q *keyQueue) MoveFocus(dir key.FocusDirection, events *handlerEvents) bool
} }
} }
order = (order + len(q.order)) % len(q.order) order = (order + len(q.order)) % len(q.order)
q.Focus(q.order[order], events) return q.Focus(evts, q.order[order])
return true
case key.FocusRight, key.FocusLeft: case key.FocusRight, key.FocusLeft:
next := order next := order
if q.focus != nil { if q.focus != nil {
@@ -208,8 +207,7 @@ func (q *keyQueue) MoveFocus(dir key.FocusDirection, events *handlerEvents) bool
if 0 <= next && next < len(q.dirOrder) { if 0 <= next && next < len(q.dirOrder) {
newFocus := q.dirOrder[next] newFocus := q.dirOrder[next]
if newFocus.row == focus.row { if newFocus.row == focus.row {
q.Focus(newFocus.tag, events) return q.Focus(evts, newFocus.tag)
return true
} }
} }
case key.FocusUp, key.FocusDown: case key.FocusUp, key.FocusDown:
@@ -245,11 +243,10 @@ func (q *keyQueue) MoveFocus(dir key.FocusDirection, events *handlerEvents) bool
order += delta order += delta
} }
if closest != nil { if closest != nil {
q.Focus(closest, events) return q.Focus(evts, closest)
return true
} }
} }
return false return nil
} }
func (q *keyQueue) BoundsFor(t event.Tag) image.Rectangle { func (q *keyQueue) BoundsFor(t event.Tag) image.Rectangle {
@@ -284,26 +281,27 @@ func keyFilterMatch(f key.Filter, e key.Event) bool {
return true return true
} }
func (q *keyQueue) Focus(focus event.Tag, events *handlerEvents) { func (q *keyQueue) Focus(evts []taggedEvent, focus event.Tag) []taggedEvent {
if focus != nil { if focus != nil {
if _, exists := q.handlers[focus]; !exists { if _, exists := q.handlers[focus]; !exists {
focus = nil focus = nil
} }
} }
if focus == q.focus { if focus == q.focus {
return return evts
} }
q.content = EditorState{} q.content = EditorState{}
if q.focus != nil { if q.focus != nil {
events.Add(q.focus, key.FocusEvent{Focus: false}) evts = append(evts, taggedEvent{tag: q.focus, event: key.FocusEvent{Focus: false}})
} }
q.focus = focus q.focus = focus
if q.focus != nil { if q.focus != nil {
events.Add(q.focus, key.FocusEvent{Focus: true}) evts = append(evts, taggedEvent{tag: q.focus, event: key.FocusEvent{Focus: true}})
} }
if q.focus == nil || q.state == TextInputKeep { if q.focus == nil || q.state == TextInputKeep {
q.state = TextInputClose q.state = TextInputClose
} }
return evts
} }
func (q *keyQueue) softKeyboard(show bool) { func (q *keyQueue) softKeyboard(show bool) {
+70 -50
View File
@@ -264,7 +264,7 @@ func (c *pointerCollector) actionInputOp(act system.Action) {
area.action = act area.action = act
} }
func (q *pointerQueue) grab(req pointer.GrabCmd, events *handlerEvents) { func (q *pointerQueue) grab(evts []taggedEvent, req pointer.GrabCmd) []taggedEvent {
for _, p := range q.pointers { for _, p := range q.pointers {
if !p.pressed || p.id != req.ID { if !p.pressed || p.id != req.ID {
continue continue
@@ -272,11 +272,16 @@ func (q *pointerQueue) grab(req pointer.GrabCmd, events *handlerEvents) {
// Drop other handlers that lost their grab. // Drop other handlers that lost their grab.
for i := len(p.handlers) - 1; i >= 0; i-- { for i := len(p.handlers) - 1; i >= 0; i-- {
if tag := p.handlers[i]; tag != req.Tag { if tag := p.handlers[i]; tag != req.Tag {
q.dropHandler(events, tag) evts = append(evts, taggedEvent{
tag: tag,
event: pointer.Event{Kind: pointer.Cancel},
})
q.dropHandler(tag)
} }
} }
break break
} }
return evts
} }
func (c *pointerCollector) inputOp(tag event.Tag) { func (c *pointerCollector) inputOp(tag event.Tag) {
@@ -352,27 +357,29 @@ func (q *pointerQueue) targetFilter(tag event.Tag, f transfer.TargetFilter) {
h.targetMimes = append(h.targetMimes, f.Type) h.targetMimes = append(h.targetMimes, f.Type)
} }
func (q *pointerQueue) offerData(req transfer.OfferCmd, events *handlerEvents) { func (q *pointerQueue) offerData(evts []taggedEvent, req transfer.OfferCmd) []taggedEvent {
transferIdx := len(q.transfers) transferIdx := len(q.transfers)
q.transfers = append(q.transfers, req.Data) q.transfers = append(q.transfers, req.Data)
for i := range q.pointers { for i := range q.pointers {
p := &q.pointers[i] p := q.pointers[i]
if p.dataSource != req.Tag { if p.dataSource != req.Tag {
continue continue
} }
defer q.deliverTransferCancelEvent(p, events)
if p.dataTarget == nil { if p.dataTarget == nil {
return q.pointers[i], evts = q.deliverTransferCancelEvent(p, evts)
break
} }
events.Add(p.dataTarget, transfer.DataEvent{ evts = append(evts, taggedEvent{tag: p.dataTarget, event: transfer.DataEvent{
Type: req.Type, Type: req.Type,
Open: func() io.ReadCloser { Open: func() io.ReadCloser {
q.transfers[transferIdx] = nil q.transfers[transferIdx] = nil
return req.Data return req.Data
}, },
}) }})
q.pointers[i], evts = q.deliverTransferCancelEvent(p, evts)
break break
} }
return evts
} }
func (c *pointerCollector) reset() { func (c *pointerCollector) reset() {
@@ -596,10 +603,10 @@ func (q *pointerQueue) reset() {
q.transfers = nil q.transfers = nil
} }
func (q *pointerQueue) Frame(events *handlerEvents) { func (q *pointerQueue) Frame(evts []taggedEvent) []taggedEvent {
for k, h := range q.handlers { for k, h := range q.handlers {
if !h.active { if !h.active {
q.dropHandler(nil, k) q.dropHandler(k)
delete(q.handlers, k) delete(q.handlers, k)
continue continue
} }
@@ -616,15 +623,13 @@ func (q *pointerQueue) Frame(events *handlerEvents) {
} }
} }
for i := range q.pointers { for i := range q.pointers {
p := &q.pointers[i] p := q.pointers[i]
q.deliverEnterLeaveEvents(p, events, p.last) q.pointers[i], evts = q.deliverEnterLeaveEvents(p, evts, p.last)
} }
return evts
} }
func (q *pointerQueue) dropHandler(events *handlerEvents, tag event.Tag) { func (q *pointerQueue) dropHandler(tag event.Tag) {
if events != nil {
events.Add(tag, pointer.Event{Kind: pointer.Cancel})
}
for i := range q.pointers { for i := range q.pointers {
p := &q.pointers[i] p := &q.pointers[i]
for i := len(p.handlers) - 1; i >= 0; i-- { for i := len(p.handlers) - 1; i >= 0; i-- {
@@ -652,7 +657,7 @@ func (q *pointerQueue) pointerOf(e pointer.Event) int {
} }
// Deliver is like Push, but delivers an event to a particular area. // Deliver is like Push, but delivers an event to a particular area.
func (q *pointerQueue) Deliver(areaIdx int, e pointer.Event, events *handlerEvents) { func (q *pointerQueue) Deliver(areaIdx int, e pointer.Event) []taggedEvent {
var sx, sy = e.Scroll.X, e.Scroll.Y var sx, sy = e.Scroll.X, e.Scroll.Y
idx := len(q.hitTree) - 1 idx := len(q.hitTree) - 1
// Locate first potential receiver. // Locate first potential receiver.
@@ -663,6 +668,7 @@ func (q *pointerQueue) Deliver(areaIdx int, e pointer.Event, events *handlerEven
} }
idx-- idx--
} }
var evts []taggedEvent
for idx != -1 { for idx != -1 {
n := &q.hitTree[idx] n := &q.hitTree[idx]
idx = n.next idx = n.next
@@ -683,11 +689,12 @@ func (q *pointerQueue) Deliver(areaIdx int, e pointer.Event, events *handlerEven
sy, e.Scroll.Y = setScrollEvent(sy, h.scrollRange.Min.Y, h.scrollRange.Max.Y) sy, e.Scroll.Y = setScrollEvent(sy, h.scrollRange.Min.Y, h.scrollRange.Max.Y)
} }
e.Position = q.invTransform(h.area, e.Position) e.Position = q.invTransform(h.area, e.Position)
events.Add(n.tag, e) evts = append(evts, taggedEvent{tag: n.tag, event: e})
if e.Kind != pointer.Scroll { if e.Kind != pointer.Scroll {
break break
} }
} }
return evts
} }
// SemanticArea returns the sematic content for area, and its parent area. // SemanticArea returns the sematic content for area, and its parent area.
@@ -703,51 +710,60 @@ func (q *pointerQueue) SemanticArea(areaIdx int) (semanticContent, int) {
return semanticContent{}, -1 return semanticContent{}, -1
} }
func (q *pointerQueue) Push(e pointer.Event, events *handlerEvents) { func (q *pointerQueue) Push(evts []taggedEvent, e pointer.Event) []taggedEvent {
if e.Kind == pointer.Cancel { if e.Kind == pointer.Cancel {
for k := range q.handlers {
evts = append(evts, taggedEvent{
event: pointer.Event{Kind: pointer.Cancel},
tag: k,
})
}
q.pointers = q.pointers[:0] q.pointers = q.pointers[:0]
for k := range q.handlers { for k := range q.handlers {
q.dropHandler(events, k) q.dropHandler(k)
} }
return return evts
} }
pidx := q.pointerOf(e) pidx := q.pointerOf(e)
p := &q.pointers[pidx] p := q.pointers[pidx]
p.last = e
switch e.Kind { switch e.Kind {
case pointer.Press: case pointer.Press:
q.deliverEnterLeaveEvents(p, events, e) p, evts = q.deliverEnterLeaveEvents(p, evts, e)
p.pressed = true p.pressed = true
q.deliverEvent(p, events, e) evts = q.deliverEvent(p, evts, e)
case pointer.Move: case pointer.Move:
if p.pressed { if p.pressed {
e.Kind = pointer.Drag e.Kind = pointer.Drag
} }
q.deliverEnterLeaveEvents(p, events, e) p, evts = q.deliverEnterLeaveEvents(p, evts, e)
q.deliverEvent(p, events, e) evts = q.deliverEvent(p, evts, e)
if p.pressed { if p.pressed {
q.deliverDragEvent(p, events) p, evts = q.deliverDragEvent(p, evts)
} }
case pointer.Release: case pointer.Release:
q.deliverEvent(p, events, e) evts = q.deliverEvent(p, evts, e)
p.pressed = false p.pressed = false
q.deliverEnterLeaveEvents(p, events, e) p, evts = q.deliverEnterLeaveEvents(p, evts, e)
q.deliverDropEvent(p, events) p, evts = q.deliverDropEvent(p, evts)
case pointer.Scroll: case pointer.Scroll:
q.deliverEnterLeaveEvents(p, events, e) p, evts = q.deliverEnterLeaveEvents(p, evts, e)
q.deliverEvent(p, events, e) evts = q.deliverEvent(p, evts, e)
default: default:
panic("unsupported pointer event type") panic("unsupported pointer event type")
} }
q.pointers[pidx] = p
p.last = e
if !p.pressed && len(p.entered) == 0 { if !p.pressed && len(p.entered) == 0 {
// No longer need to track pointer. // No longer need to track pointer.
q.pointers = append(q.pointers[:pidx], q.pointers[pidx+1:]...) q.pointers = append(q.pointers[:pidx], q.pointers[pidx+1:]...)
} }
return evts
} }
func (q *pointerQueue) deliverEvent(p *pointerInfo, events *handlerEvents, e pointer.Event) { func (q *pointerQueue) deliverEvent(p pointerInfo, evts []taggedEvent, e pointer.Event) []taggedEvent {
foremost := true foremost := true
if p.pressed && len(p.handlers) == 1 { if p.pressed && len(p.handlers) == 1 {
e.Priority = pointer.Grabbed e.Priority = pointer.Grabbed
@@ -758,7 +774,7 @@ func (q *pointerQueue) deliverEvent(p *pointerInfo, events *handlerEvents, e poi
h := q.handlers[k] h := q.handlers[k]
if e.Kind == pointer.Scroll { if e.Kind == pointer.Scroll {
if sx == 0 && sy == 0 { if sx == 0 && sy == 0 {
return return evts
} }
// Distribute the scroll to the handler based on its ScrollRange. // Distribute the scroll to the handler based on its ScrollRange.
sx, e.Scroll.X = setScrollEvent(sx, h.scrollRange.Min.X, h.scrollRange.Max.X) sx, e.Scroll.X = setScrollEvent(sx, h.scrollRange.Min.X, h.scrollRange.Max.X)
@@ -773,11 +789,12 @@ func (q *pointerQueue) deliverEvent(p *pointerInfo, events *handlerEvents, e poi
e.Priority = pointer.Foremost e.Priority = pointer.Foremost
} }
e.Position = q.invTransform(h.area, e.Position) e.Position = q.invTransform(h.area, e.Position)
events.Add(k, e) evts = append(evts, taggedEvent{event: e, tag: k})
} }
return evts
} }
func (q *pointerQueue) deliverEnterLeaveEvents(p *pointerInfo, events *handlerEvents, e pointer.Event) { func (q *pointerQueue) deliverEnterLeaveEvents(p pointerInfo, evts []taggedEvent, e pointer.Event) (pointerInfo, []taggedEvent) {
var hits []event.Tag var hits []event.Tag
if e.Source != pointer.Mouse && !p.pressed && e.Kind != pointer.Press { if e.Source != pointer.Mouse && !p.pressed && e.Kind != pointer.Press {
// Consider non-mouse pointers leaving when they're released. // Consider non-mouse pointers leaving when they're released.
@@ -816,7 +833,7 @@ func (q *pointerQueue) deliverEnterLeaveEvents(p *pointerInfo, events *handlerEv
if e.Kind&h.types != 0 { if e.Kind&h.types != 0 {
e.Position = q.invTransform(h.area, e.Position) e.Position = q.invTransform(h.area, e.Position)
events.Add(k, e) evts = append(evts, taggedEvent{tag: k, event: e})
} }
} }
// Deliver Enter events. // Deliver Enter events.
@@ -830,15 +847,16 @@ func (q *pointerQueue) deliverEnterLeaveEvents(p *pointerInfo, events *handlerEv
if e.Kind&h.types != 0 { if e.Kind&h.types != 0 {
e.Position = q.invTransform(h.area, e.Position) e.Position = q.invTransform(h.area, e.Position)
events.Add(k, e) evts = append(evts, taggedEvent{tag: k, event: e})
} }
} }
p.entered = hits p.entered = hits
return p, evts
} }
func (q *pointerQueue) deliverDragEvent(p *pointerInfo, events *handlerEvents) { func (q *pointerQueue) deliverDragEvent(p pointerInfo, evts []taggedEvent) (pointerInfo, []taggedEvent) {
if p.dataSource != nil { if p.dataSource != nil {
return return p, evts
} }
// Identify the data source. // Identify the data source.
for _, k := range p.entered { for _, k := range p.entered {
@@ -851,16 +869,17 @@ func (q *pointerQueue) deliverDragEvent(p *pointerInfo, events *handlerEvents) {
// Notify all potential targets. // Notify all potential targets.
for k, tgt := range q.handlers { for k, tgt := range q.handlers {
if _, ok := firstMimeMatch(src, tgt); ok { if _, ok := firstMimeMatch(src, tgt); ok {
events.Add(k, transfer.InitiateEvent{}) evts = append(evts, taggedEvent{tag: k, event: transfer.InitiateEvent{}})
} }
} }
break break
} }
return p, evts
} }
func (q *pointerQueue) deliverDropEvent(p *pointerInfo, events *handlerEvents) { func (q *pointerQueue) deliverDropEvent(p pointerInfo, evts []taggedEvent) (pointerInfo, []taggedEvent) {
if p.dataSource == nil { if p.dataSource == nil {
return return p, evts
} }
// Request data from the source. // Request data from the source.
src := q.handlers[p.dataSource] src := q.handlers[p.dataSource]
@@ -868,25 +887,26 @@ func (q *pointerQueue) deliverDropEvent(p *pointerInfo, events *handlerEvents) {
h := q.handlers[k] h := q.handlers[k]
if m, ok := firstMimeMatch(src, h); ok { if m, ok := firstMimeMatch(src, h); ok {
p.dataTarget = k p.dataTarget = k
events.Add(p.dataSource, transfer.RequestEvent{Type: m}) evts = append(evts, taggedEvent{tag: p.dataSource, event: transfer.RequestEvent{Type: m}})
return return p, evts
} }
} }
// No valid target found, abort. // No valid target found, abort.
q.deliverTransferCancelEvent(p, events) return q.deliverTransferCancelEvent(p, evts)
} }
func (q *pointerQueue) deliverTransferCancelEvent(p *pointerInfo, events *handlerEvents) { func (q *pointerQueue) deliverTransferCancelEvent(p pointerInfo, evts []taggedEvent) (pointerInfo, []taggedEvent) {
events.Add(p.dataSource, transfer.CancelEvent{}) evts = append(evts, taggedEvent{tag: p.dataSource, event: transfer.CancelEvent{}})
// Cancel all potential targets. // Cancel all potential targets.
src := q.handlers[p.dataSource] src := q.handlers[p.dataSource]
for k, h := range q.handlers { for k, h := range q.handlers {
if _, ok := firstMimeMatch(src, h); ok { if _, ok := firstMimeMatch(src, h); ok {
events.Add(k, transfer.CancelEvent{}) evts = append(evts, taggedEvent{tag: k, event: transfer.CancelEvent{}})
} }
} }
p.dataSource = nil p.dataSource = nil
p.dataTarget = nil p.dataTarget = nil
return p, evts
} }
// ClipFor clips r to the parents of area. // ClipFor clips r to the parents of area.
+56 -75
View File
@@ -35,7 +35,7 @@ type Router struct {
} }
cqueue clipboardQueue cqueue clipboardQueue
handlers handlerEvents events []taggedEvent
reader ops.Reader reader ops.Reader
@@ -94,9 +94,10 @@ const (
// By convention, the zero value denotes the non-existent ID. // By convention, the zero value denotes the non-existent ID.
type SemanticID uint type SemanticID uint
type handlerEvents struct { // taggedEvent represents an event and its target handler.
handlers map[event.Tag][]event.Event type taggedEvent struct {
hadEvents bool event event.Event
tag event.Tag
} }
// Source returns a Source backed by this Router. // Source returns a Source backed by this Router.
@@ -129,7 +130,7 @@ func (s Source) Events(k event.Tag, filters ...event.Filter) []event.Event {
} }
func (q *Router) Events(k event.Tag, filters ...event.Filter) []event.Event { func (q *Router) Events(k event.Tag, filters ...event.Filter) []event.Event {
var resetEvents []event.Event var evts []event.Event
for _, f := range filters { for _, f := range filters {
switch f := f.(type) { switch f := f.(type) {
case key.Filter: case key.Filter:
@@ -137,12 +138,12 @@ func (q *Router) Events(k event.Tag, filters ...event.Filter) []event.Event {
case key.FocusFilter: case key.FocusFilter:
q.key.queue.focusable(k) q.key.queue.focusable(k)
if reset, ok := q.key.queue.ResetEvent(k); ok { if reset, ok := q.key.queue.ResetEvent(k); ok {
resetEvents = append(resetEvents, reset) evts = append(evts, reset)
} }
case pointer.Filter: case pointer.Filter:
q.pointer.queue.filterTag(k, f) q.pointer.queue.filterTag(k, f)
if reset, ok := q.pointer.queue.ResetEvent(k); ok { if reset, ok := q.pointer.queue.ResetEvent(k); ok {
resetEvents = append(resetEvents, reset) evts = append(evts, reset)
} }
case transfer.SourceFilter: case transfer.SourceFilter:
q.pointer.queue.sourceFilter(k, f) q.pointer.queue.sourceFilter(k, f)
@@ -150,15 +151,26 @@ func (q *Router) Events(k event.Tag, filters ...event.Filter) []event.Event {
q.pointer.queue.targetFilter(k, f) q.pointer.queue.targetFilter(k, f)
} }
} }
events := q.handlers.Events(k, filters...) i := 0
return append(resetEvents, events...) for i < len(q.events) {
e := q.events[i]
if e.tag == k {
q.events = append(q.events[:i], q.events[i+1:]...)
if filtersMatches(filters, e.event) {
evts = append(evts, e.event)
}
} else {
i++
}
}
return evts
} }
// Frame replaces the declared handlers from the supplied // Frame replaces the declared handlers from the supplied
// operation list. The text input state, wakeup time and whether // operation list. The text input state, wakeup time and whether
// there are active profile handlers is also saved. // there are active profile handlers is also saved.
func (q *Router) Frame(frame *op.Ops) { func (q *Router) Frame(frame *op.Ops) {
q.handlers.Clear() q.events = q.events[:0]
q.wakeup = false q.wakeup = false
var ops *ops.Ops var ops *ops.Ops
if frame != nil { if frame != nil {
@@ -166,24 +178,26 @@ func (q *Router) Frame(frame *op.Ops) {
} }
q.reader.Reset(ops) q.reader.Reset(ops)
q.collect() q.collect()
q.executeCommands() evts := q.executeCommands(nil)
q.pointer.queue.Frame(&q.handlers) evts = q.pointer.queue.Frame(evts)
q.key.queue.Frame() q.key.queue.Frame()
q.addEvents(evts)
if q.handlers.HadEvents() { if len(evts) > 0 {
q.wakeup = true q.wakeup = true
q.wakeupTime = time.Time{} q.wakeupTime = time.Time{}
} }
} }
// Queue events and report whether at least one handler had an event queued. // Queue events and report whether at least one event matched a handler.
func (q *Router) Queue(events ...event.Event) bool { func (q *Router) Queue(events ...event.Event) bool {
var evts []taggedEvent
for _, e := range events { for _, e := range events {
switch e := e.(type) { switch e := e.(type) {
case pointer.Event: case pointer.Event:
q.pointer.queue.Push(e, &q.handlers) evts = q.pointer.queue.Push(evts, e)
case key.Event: case key.Event:
q.queueKeyEvent(e) evts = q.queueKeyEvent(evts, e)
case key.SnippetEvent: case key.SnippetEvent:
// Expand existing, overlapping snippet. // Expand existing, overlapping snippet.
if r := q.key.queue.content.Snippet.Range; rangeOverlaps(r, key.Range(e)) { if r := q.key.queue.content.Snippet.Range; rangeOverlaps(r, key.Range(e)) {
@@ -195,45 +209,51 @@ func (q *Router) Queue(events ...event.Event) bool {
} }
} }
if f := q.key.queue.focus; f != nil { if f := q.key.queue.focus; f != nil {
q.handlers.Add(f, e) evts = append(evts, taggedEvent{tag: f, event: e})
} }
case key.EditEvent, key.FocusEvent, key.SelectionEvent: case key.EditEvent, key.FocusEvent, key.SelectionEvent:
if f := q.key.queue.focus; f != nil { if f := q.key.queue.focus; f != nil {
q.handlers.Add(f, e) evts = append(evts, taggedEvent{tag: f, event: e})
} }
case transfer.DataEvent: case transfer.DataEvent:
q.cqueue.Push(e, &q.handlers) evts = q.cqueue.Push(evts, e)
} }
} }
return q.handlers.HadEvents() q.addEvents(evts)
return len(evts) > 0
} }
func (q *Router) queue(f Command) { func (q *Router) queue(f Command) {
q.commands = append(q.commands, f) q.commands = append(q.commands, f)
} }
func (q *Router) executeCommands() { func (q *Router) executeCommands(evts []taggedEvent) []taggedEvent {
for _, req := range q.commands { for _, req := range q.commands {
switch req := req.(type) { switch req := req.(type) {
case key.SelectionCmd: case key.SelectionCmd:
q.key.queue.setSelection(req) q.key.queue.setSelection(req)
case key.FocusCmd: case key.FocusCmd:
q.key.queue.Focus(req.Tag, &q.handlers) evts = q.key.queue.Focus(evts, req.Tag)
case key.SoftKeyboardCmd: case key.SoftKeyboardCmd:
q.key.queue.softKeyboard(req.Show) q.key.queue.softKeyboard(req.Show)
case key.SnippetCmd: case key.SnippetCmd:
q.key.queue.setSnippet(req) q.key.queue.setSnippet(req)
case transfer.OfferCmd: case transfer.OfferCmd:
q.pointer.queue.offerData(req, &q.handlers) evts = q.pointer.queue.offerData(evts, req)
case clipboard.WriteCmd: case clipboard.WriteCmd:
q.cqueue.ProcessWriteClipboard(req) q.cqueue.ProcessWriteClipboard(req)
case clipboard.ReadCmd: case clipboard.ReadCmd:
q.cqueue.ProcessReadClipboard(req.Tag) q.cqueue.ProcessReadClipboard(req.Tag)
case pointer.GrabCmd: case pointer.GrabCmd:
q.pointer.queue.grab(req, &q.handlers) evts = q.pointer.queue.grab(evts, req)
} }
} }
q.commands = nil q.commands = nil
return evts
}
func (q *Router) addEvents(evts []taggedEvent) {
q.events = append(q.events, evts...)
} }
func rangeOverlaps(r1, r2 key.Range) bool { func rangeOverlaps(r1, r2 key.Range) bool {
@@ -250,12 +270,12 @@ func rangeNorm(r key.Range) key.Range {
return r return r
} }
func (q *Router) queueKeyEvent(e key.Event) { func (q *Router) queueKeyEvent(evts []taggedEvent, e key.Event) []taggedEvent {
kq := &q.key.queue kq := &q.key.queue
f := q.key.queue.focus f := q.key.queue.focus
if f != nil && kq.Accepts(f, e) { if f != nil && kq.Accepts(f, e) {
q.handlers.Add(f, e) evts = append(evts, taggedEvent{tag: f, event: e})
return return evts
} }
pq := &q.pointer.queue pq := &q.pointer.queue
idx := len(pq.hitTree) - 1 idx := len(pq.hitTree) - 1
@@ -277,14 +297,17 @@ func (q *Router) queueKeyEvent(e key.Event) {
continue continue
} }
if kq.Accepts(n.tag, e) { if kq.Accepts(n.tag, e) {
q.handlers.Add(n.tag, e) evts = append(evts, taggedEvent{tag: n.tag, event: e})
break break
} }
} }
return evts
} }
func (q *Router) MoveFocus(dir key.FocusDirection) bool { func (q *Router) MoveFocus(dir key.FocusDirection) bool {
return q.key.queue.MoveFocus(dir, &q.handlers) evts := q.key.queue.MoveFocus(nil, dir)
q.addEvents(evts)
return len(evts) > 0
} }
// RevealFocus scrolls the current focus (if any) into viewport // RevealFocus scrolls the current focus (if any) into viewport
@@ -321,11 +344,11 @@ func (q *Router) ScrollFocus(dist image.Point) {
return return
} }
area := q.key.queue.AreaFor(focus) area := q.key.queue.AreaFor(focus)
q.pointer.queue.Deliver(area, pointer.Event{ q.addEvents(q.pointer.queue.Deliver(area, pointer.Event{
Kind: pointer.Scroll, Kind: pointer.Scroll,
Source: pointer.Touch, Source: pointer.Touch,
Scroll: f32internal.FPt(dist), Scroll: f32internal.FPt(dist),
}, &q.handlers) }))
} }
func max(p1, p2 image.Point) image.Point { func max(p1, p2 image.Point) image.Point {
@@ -367,9 +390,9 @@ func (q *Router) ClickFocus() {
} }
area := q.key.queue.AreaFor(focus) area := q.key.queue.AreaFor(focus)
e.Kind = pointer.Press e.Kind = pointer.Press
q.pointer.queue.Deliver(area, e, &q.handlers) q.addEvents(q.pointer.queue.Deliver(area, e))
e.Kind = pointer.Release e.Kind = pointer.Release
q.pointer.queue.Deliver(area, e, &q.handlers) q.addEvents(q.pointer.queue.Deliver(area, e))
} }
// TextInputState returns the input state from the most recent // TextInputState returns the input state from the most recent
@@ -523,42 +546,6 @@ func (q *Router) WakeupTime() (time.Time, bool) {
return q.wakeupTime, q.wakeup return q.wakeupTime, q.wakeup
} }
func (h *handlerEvents) init() {
if h.handlers == nil {
h.handlers = make(map[event.Tag][]event.Event)
}
}
func (h *handlerEvents) Add(k event.Tag, e event.Event) {
h.init()
h.handlers[k] = append(h.handlers[k], e)
h.hadEvents = true
}
func (h *handlerEvents) HadEvents() bool {
u := h.hadEvents
h.hadEvents = false
return u
}
func (h *handlerEvents) Events(k event.Tag, filters ...event.Filter) []event.Event {
var filtered []event.Event
if events, ok := h.handlers[k]; ok {
i := 0
for i < len(events) {
e := events[i]
if filtersMatches(filters, e) {
filtered = append(filtered, e)
events = append(events[:i], events[i+1:]...)
} else {
i++
}
}
h.handlers[k] = events
}
return filtered
}
func filtersMatches(filters []event.Filter, e event.Event) bool { func filtersMatches(filters []event.Filter, e event.Event) bool {
switch e := e.(type) { switch e := e.(type) {
case key.Event: case key.Event:
@@ -604,12 +591,6 @@ func filtersMatches(filters []event.Filter, e event.Event) bool {
return false return false
} }
func (h *handlerEvents) Clear() {
for k := range h.handlers {
delete(h.handlers, k)
}
}
func decodeInvalidateOp(d []byte) op.InvalidateOp { func decodeInvalidateOp(d []byte) op.InvalidateOp {
bo := binary.LittleEndian bo := binary.LittleEndian
if ops.OpType(d[0]) != ops.TypeInvalidate { if ops.OpType(d[0]) != ops.TypeInvalidate {