Skip to content

Commit

Permalink
add: [plugins] support macros/records (#42)
Browse files Browse the repository at this point in the history
Now, it's possible to use plugins inside macros.

Signed-off-by: Inkeliz <[email protected]>
  • Loading branch information
inkeliz authored Jun 8, 2023
1 parent 2fdf6de commit 701cb59
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 14 deletions.
55 changes: 44 additions & 11 deletions plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package plugin
import (
"reflect"
"sync"
"sync/atomic"
"unsafe"

"gioui.org/app"
Expand All @@ -17,23 +18,27 @@ type Plugin struct {
window *app.Window
queue event.Queue

eventsMutex sync.Mutex
eventsCustom map[event.Tag][]event.Event
eventsPool []event.Event

redirectEvent map[reflect.Type][]int
redirectOp map[reflect.Type][]int

visited map[uintptr]struct{}

plugins []Handler
invalidated bool
invalidated atomic.Bool
}

func newHandler(w *app.Window) *Plugin {
h := &Plugin{
window: w,
eventsCustom: make(map[event.Tag][]event.Event, 128),
plugins: make([]Handler, len(registeredPlugins)),
redirectOp: map[reflect.Type][]int{},
redirectEvent: map[reflect.Type][]int{},
redirectOp: make(map[reflect.Type][]int, 128),
redirectEvent: make(map[reflect.Type][]int, 128),
visited: make(map[uintptr]struct{}, 2048),
}
for index, pf := range registeredPlugins {
h.plugins[index] = pf(w, h)
Expand All @@ -57,6 +62,9 @@ func newHandler(w *app.Window) *Plugin {
}

func (l *Plugin) SendEvent(tag event.Tag, data event.Event) {
l.eventsMutex.Lock()
defer l.eventsMutex.Unlock()

if l.eventsCustom == nil {
l.eventsCustom = make(map[event.Tag][]event.Event, 128)
}
Expand All @@ -65,12 +73,15 @@ func (l *Plugin) SendEvent(tag event.Tag, data event.Event) {
}
l.eventsCustom[tag] = append(l.eventsCustom[tag], data)

if !l.invalidated {
if l.invalidated.Load() {
l.window.Invalidate()
}
}

func (l *Plugin) Events(t event.Tag) []event.Event {
l.eventsMutex.Lock()
defer l.eventsMutex.Unlock()

evtsGio := l.queue.Events(t)
evtsCustom, _ := l.eventsCustom[t]

Expand Down Expand Up @@ -102,6 +113,29 @@ type unsafeOps struct {
multipOp bool
}

var (
internalOps = op.Ops{}.Internal
typeOps = reflect.TypeOf(&internalOps)
)

func (l *Plugin) processFrameEvent(o *unsafeOps) {
if _, ok := l.visited[uintptr(unsafe.Pointer(o))]; ok {
return
}
l.visited[uintptr(unsafe.Pointer(o))] = struct{}{}

for i := range o.refs {
if reflect.TypeOf(o.refs[i]) == typeOps {
o2 := *(**unsafeOps)(unsafe.Add(unsafe.Pointer(&o.refs[i]), unsafe.Sizeof(uintptr(0))))
l.processFrameEvent(o2)
} else {
for _, index := range l.redirectOp[reflect.TypeOf(o.refs[i])] {
l.plugins[index].ListenOps(o.refs[i])
}
}
}
}

func Install(w *app.Window, evt event.Event) {
var h *Plugin
li, ok := handlers.Load(w)
Expand All @@ -119,26 +153,25 @@ func Install(w *app.Window, evt event.Event) {
switch evt.(type) {
case system.FrameEvent:
ref := *(**system.FrameEvent)(unsafe.Add(unsafe.Pointer(&evt), unsafe.Sizeof(uintptr(0))))
h.invalidated = false
h.invalidated.Store(false)

q := ref.Queue
h.queue = q
ref.Queue = h

f := ref.Frame
ref.Frame = func(frame *op.Ops) {
ops := (*unsafeOps)(unsafe.Pointer(&frame.Internal))
f(frame)

for _, r := range ops.refs {
for _, index := range h.redirectOp[reflect.TypeOf(r)] {
h.plugins[index].ListenOps(r)
}
}
h.processFrameEvent((*unsafeOps)(unsafe.Pointer(&frame.Internal)))

for _, index := range h.redirectEvent[reflect.TypeOf(EndFrameEvent{})] {
h.plugins[index].ListenEvents(EndFrameEvent{})
}

for i := range h.visited {
delete(h.visited, i)
}
}
}
}
Expand Down
13 changes: 10 additions & 3 deletions plugin/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,16 @@ type handlerFunc struct {
listenEvents func(evt event.Event)
}

func (p *handlerFunc) TypeOp() []reflect.Type { return p.typeOp }
func (p *handlerFunc) TypeEvent() []reflect.Type { return p.typeEvent }
func (p *handlerFunc) ListenOps(op interface{}) { p.listenOps(op) }
// TypeOp implements Handler interface.
func (p *handlerFunc) TypeOp() []reflect.Type { return p.typeOp }

// TypeEvent implements Handler interface.
func (p *handlerFunc) TypeEvent() []reflect.Type { return p.typeEvent }

// ListenOps implements Handler interface.
func (p *handlerFunc) ListenOps(op interface{}) { p.listenOps(op) }

// ListenEvents implements Handler interface.
func (p *handlerFunc) ListenEvents(evt event.Event) { p.listenEvents(evt) }

// NewHandlerFunc returns a Handler that calls the given functions.
Expand Down

0 comments on commit 701cb59

Please sign in to comment.