mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-07 02:15:34 +00:00
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:
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user