cchat-gtk/internal/ui/messages/memberlist/eventqueue.go

79 lines
1.5 KiB
Go

package memberlist
import (
"sync"
"github.com/diamondburned/cchat-gtk/internal/gts"
)
type EventQueuer interface {
Activate()
Deactivate()
}
// eventQueue is a rough unbounded event queue. A zero-value instance is valid.
type eventQueue struct {
mutex sync.Mutex
activated bool
// idleQueue contains the incoming callbacks to update events. This is a
// temporary hack to the issue of popovers disappearing when its parent
// widget, that is the list box, changes. This slice should then contain all
// those events to be executed only when the Popover is popped down.
idleQueue []func()
}
func (evq *eventQueue) Add(fn func()) {
evq.mutex.Lock()
defer evq.mutex.Unlock()
if evq.activated {
evq.idleQueue = append(evq.idleQueue, fn)
} else {
gts.ExecLater(fn)
}
}
func (evq *eventQueue) Activate() {
evq.mutex.Lock()
defer evq.mutex.Unlock()
evq.activated = true
}
func (evq *eventQueue) pop() []func() {
evq.mutex.Lock()
defer evq.mutex.Unlock()
popped := evq.idleQueue
evq.idleQueue = nil
evq.activated = false
return popped
}
func (evq *eventQueue) Deactivate() {
var popped = evq.pop()
const chunkSz = 25
// We shouldn't try and run more than a certain amount of callbacks within a
// single loop, as it will freeze up the UI.
for i := 0; i < len(popped); i += chunkSz {
// Calculate the bounds in chunks.
start, end := i, min(i+chunkSz, len(popped))
gts.ExecLater(func() {
for _, fn := range popped[start:end] {
fn()
}
})
}
}
func min(i, j int) int {
if i < j {
return i
}
return j
}