From 1653d59d6bf9df034e47b52074b697344079d376 Mon Sep 17 00:00:00 2001 From: Trevor Slocum Date: Sat, 24 Apr 2021 23:08:49 -0700 Subject: [PATCH] Restructure event loop to only poll screen between updates Relates to #58. --- CHANGELOG | 3 +++ application.go | 63 +++++++++++++++++++++++++------------------------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a17023d..c10412f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +v1.5.5 (WIP) +- Restructure event loop to only poll screen between updates + v1.5.4 (2020-04-03) - Add TextView.GetBufferSize - Fix strikethrough support diff --git a/application.go b/application.go index aa9c17b..de2cec5 100644 --- a/application.go +++ b/application.go @@ -304,7 +304,7 @@ func (a *Application) Run() error { a.Unlock() a.draw() - // Separate loop to wait for screen events. + // Separate loop to wait for screen replacement events. var wg sync.WaitGroup wg.Add(1) go func() { @@ -319,14 +319,6 @@ func (a *Application) Run() error { break } - // Wait for next event and queue it. - event := screen.PollEvent() - if event != nil { - // Regular event. Queue. - a.QueueEvent(event) - continue - } - // A screen was finalized (event is nil). Wait for a new screen. screen = <-a.screenReplacement if screen == nil { @@ -436,32 +428,38 @@ func (a *Application) Run() error { } } - // Start event loop. -EventLoop: + semaphore := &sync.Mutex{} + + go func() { + for update := range a.updates { + semaphore.Lock() + update() + semaphore.Unlock() + } + }() + + // Start screen event loop. for { - // Handle events before executing updates - select { - case event := <-a.events: - if event == nil { - break EventLoop - } - handle(event) - continue - default: + a.Lock() + screen := a.screen + a.Unlock() + + if screen == nil { + break } - select { - case event := <-a.events: - if event == nil { - break EventLoop - } - handle(event) - case update := <-a.updates: - update() + // Wait for next event. + event := screen.PollEvent() + if event == nil { + break } + + semaphore.Lock() + handle(event) + semaphore.Unlock() } - // Wait for the event loop to finish. + // Wait for the screen replacement event loop to finish. wg.Wait() a.screen = nil @@ -590,13 +588,12 @@ func (a *Application) Stop() { // terminal UI mode was not exited, and "f" was not called. func (a *Application) Suspend(f func()) bool { a.Lock() - defer a.Unlock() - if a.screen == nil { + a.Unlock() return false // Screen has not yet been initialized. } - err := a.screen.Suspend() + a.Unlock() if err != nil { panic(err) } @@ -604,7 +601,9 @@ func (a *Application) Suspend(f func()) bool { // Wait for "f" to return. f() + a.Lock() err = a.screen.Resume() + a.Unlock() if err != nil { panic(err) }