io/input: deliver all observed events before deferring the rest

Even when a command defers event delivery to the next frame, the already
observed events must still be delivered in the current frame. This
matters for pointer events that hit more than one event handler.

Fixes: https://todo.sr.ht/~eliasnaur/gio/594
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2024-06-20 15:21:35 +02:00
parent 706940ff9b
commit 8fb6d3da2b
2 changed files with 48 additions and 20 deletions
+27
View File
@@ -1086,6 +1086,33 @@ func TestPassCursor(t *testing.T) {
} }
} }
func TestPartialEvent(t *testing.T) {
var ops op.Ops
var r Router
rect := clip.Rect(image.Rect(0, 0, 100, 100))
background := rect.Push(&ops)
event.Op(&ops, 1)
background.Pop()
overlayPass := pointer.PassOp{}.Push(&ops)
overlay := rect.Push(&ops)
event.Op(&ops, 2)
overlay.Pop()
overlayPass.Pop()
assertEventSequence(t, events(&r, -1, pointer.Filter{Target: 1, Kinds: pointer.Press}))
assertEventSequence(t, events(&r, -1, pointer.Filter{Target: 2, Kinds: pointer.Press}))
r.Frame(&ops)
r.Queue(pointer.Event{
Kind: pointer.Press,
})
assertEventSequence(t, events(&r, -1, pointer.Filter{Target: 1, Kinds: pointer.Press}, key.FocusFilter{Target: 1}),
key.FocusEvent{}, pointer.Event{Kind: pointer.Press, Source: pointer.Mouse, Priority: pointer.Shared})
r.Source().Execute(key.FocusCmd{Tag: 1})
assertEventSequence(t, events(&r, -1, pointer.Filter{Target: 2, Kinds: pointer.Press}),
pointer.Event{Kind: pointer.Press, Source: pointer.Mouse, Priority: pointer.Foremost})
}
// offer satisfies io.ReadCloser for use in data transfers. // offer satisfies io.ReadCloser for use in data transfers.
type offer struct { type offer struct {
data string data string
+21 -20
View File
@@ -274,28 +274,29 @@ func (q *Router) Event(filters ...event.Filter) (event.Event, bool) {
} }
} }
} }
if !q.deferring { for i := range q.changes {
for i := range q.changes { if q.deferring && i > 0 {
change := &q.changes[i] break
for j, evt := range change.events { }
match := false change := &q.changes[i]
switch e := evt.event.(type) { for j, evt := range change.events {
case key.Event: match := false
match = q.key.scratchFilter.Matches(change.state.keyState.focus, e, false) switch e := evt.event.(type) {
default: case key.Event:
for _, tf := range q.scratchFilters { match = q.key.scratchFilter.Matches(change.state.keyState.focus, e, false)
if evt.tag == tf.tag && tf.filter.Matches(evt.event) { default:
match = true for _, tf := range q.scratchFilters {
break if evt.tag == tf.tag && tf.filter.Matches(evt.event) {
} match = true
break
} }
} }
if match { }
change.events = append(change.events[:j], change.events[j+1:]...) if match {
// Fast forward state to last matched. change.events = append(change.events[:j], change.events[j+1:]...)
q.collapseState(i) // Fast forward state to last matched.
return evt.event, true q.collapseState(i)
} return evt.event, true
} }
} }
} }