Merge branch 'add-synchronization-channels' of https://github.com/3cb/tview into 3cb-add-synchronization-channels

pull/177/head
Oliver 6 years ago
commit d830c42f6b

@ -46,11 +46,20 @@ type Application struct {
// Halts the event loop during suspended mode. // Halts the event loop during suspended mode.
suspendMutex sync.Mutex suspendMutex sync.Mutex
// Used to send screen events from separate goroutine to main event loop
events chan tcell.Event
// Used to send primitive updates from separate goroutines to the main event loop
updates chan func()
} }
// NewApplication creates and returns a new application. // NewApplication creates and returns a new application.
func NewApplication() *Application { func NewApplication() *Application {
return &Application{} return &Application{
events: make(chan tcell.Event, 100),
updates: make(chan func(), 100),
}
} }
// SetInputCapture sets a function which captures all key events before they are // SetInputCapture sets a function which captures all key events before they are
@ -136,7 +145,8 @@ func (a *Application) Run() error {
a.Unlock() a.Unlock()
a.Draw() a.Draw()
// Start event loop. // Separate loop to wait for screen events
go func() {
for { for {
// Do not poll events during suspend mode // Do not poll events during suspend mode
a.suspendMutex.Lock() a.suspendMutex.Lock()
@ -145,15 +155,25 @@ func (a *Application) Run() error {
a.RUnlock() a.RUnlock()
if screen == nil { if screen == nil {
a.suspendMutex.Unlock() a.suspendMutex.Unlock()
// send signal to stop main event loop
a.QueueEvent(nil)
break break
} }
// Wait for next event. // Wait for next event.
event := a.screen.PollEvent() a.QueueEvent(screen.PollEvent())
a.suspendMutex.Unlock() a.suspendMutex.Unlock()
}
}()
// Start event loop.
loop:
for {
select {
case event := <-a.events:
if event == nil { if event == nil {
// The screen was finalized. Exit the loop. // The screen was finalized. Exit the loop.
break break loop
} }
switch event := event.(type) { switch event := event.(type) {
@ -166,7 +186,7 @@ func (a *Application) Run() error {
if a.inputCapture != nil { if a.inputCapture != nil {
event = a.inputCapture(event) event = a.inputCapture(event)
if event == nil { if event == nil {
break // Don't forward event. break loop // Don't forward event.
} }
} }
@ -191,6 +211,12 @@ func (a *Application) Run() error {
screen.Clear() screen.Clear()
a.Draw() a.Draw()
} }
case updater := <-a.updates:
updater()
a.Draw()
}
} }
return nil return nil
@ -404,3 +430,15 @@ func (a *Application) GetFocus() Primitive {
defer a.RUnlock() defer a.RUnlock()
return a.focus return a.focus
} }
// QueueUpdate is used to synchronize changes to primitives by carrying an update function from separate goroutine to the Application event loop via channel
func (a *Application) QueueUpdate(f func()) *Application {
a.updates <- f
return a
}
// QueueEvent takes an Event instance and sends it to the Application event loop via channel
func (a *Application) QueueEvent(e tcell.Event) *Application {
a.events <- e
return a
}

Loading…
Cancel
Save