ui: process tcell events in a separate go routine from rendering

The UI runs off a 16 ms ticker. If no render is required, and no event
is seen, aerc waits 16 ms before checking for new events or render
requests. This severely limits handling of events from tcell, and is
particularly noticeable on pasting of large quantities of text.

Process tcell events in a separate go routine from the render loop.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Tim Culverhouse 2022-09-12 16:09:19 -05:00 committed by Robin Jarry
parent fad90c2956
commit c947811e9f
2 changed files with 17 additions and 17 deletions

View file

@ -241,6 +241,7 @@ func main() {
setWindowTitle() setWindowTitle()
} }
go ui.Run()
for !ui.ShouldExit() { for !ui.ShouldExit() {
for aerc.Tick() { for aerc.Tick() {
// Continue updating our internal state // Continue updating our internal state

View file

@ -85,23 +85,6 @@ func (state *UI) Close() {
func (state *UI) Tick() bool { func (state *UI) Tick() bool {
more := false more := false
select {
case event := <-state.tcEvents:
if event, ok := event.(*tcell.EventResize); ok {
state.screen.Clear()
width, height := event.Size()
state.ctx = NewContext(width, height, state.screen, state.onPopover)
state.Content.Invalidate()
}
// if we have a popover, and it can handle the event, it does so
if state.popover == nil || !state.popover.Event(event) {
// otherwise, we send the event to the main content
state.Content.Event(event)
}
more = true
default:
}
wasInvalid := atomic.SwapInt32(&state.invalid, 0) wasInvalid := atomic.SwapInt32(&state.invalid, 0)
if wasInvalid != 0 { if wasInvalid != 0 {
if state.popover != nil { if state.popover != nil {
@ -126,3 +109,19 @@ func (state *UI) Tick() bool {
func (state *UI) EnableMouse() { func (state *UI) EnableMouse() {
state.screen.EnableMouse() state.screen.EnableMouse()
} }
func (state *UI) Run() {
for event := range state.tcEvents {
if event, ok := event.(*tcell.EventResize); ok {
state.screen.Clear()
width, height := event.Size()
state.ctx = NewContext(width, height, state.screen, state.onPopover)
state.Content.Invalidate()
}
// if we have a popover, and it can handle the event, it does so
if state.popover == nil || !state.popover.Event(event) {
// otherwise, we send the event to the main content
state.Content.Event(event)
}
}
}