thread safety for event loop and redraw loop

This commit is contained in:
Timon Ringwald 2022-04-04 14:47:15 +02:00
parent 8be528e57a
commit 45c636ec33

View File

@ -11,7 +11,11 @@ import (
type Screen struct { type Screen struct {
scr tcell.Screen scr tcell.Screen
buf *ViewBuffer buf *ViewBuffer
stopCh chan error stopCh chan error
redrawCh chan struct{}
// Root is the root view which is currently shown on screen
Root View Root View
// KeyPressed is called every time a key or key-combination is pressed. // KeyPressed is called every time a key or key-combination is pressed.
@ -31,29 +35,15 @@ func NewScreen(root View) (*Screen, error) {
Root: root, Root: root,
scr: scr, scr: scr,
stopCh: make(chan error, 1), stopCh: make(chan error, 1),
redrawCh: make(chan struct{}, 1),
} }
go s.eventloop() go s.eventloop()
go s.drawloop()
return s, nil return s, nil
} }
func (s *Screen) eventloop() {
for evt := s.scr.PollEvent(); evt != nil; evt = s.scr.PollEvent() {
switch event := evt.(type) {
case *tcell.EventResize:
go s.Redraw()
case *tcell.EventKey:
go s.onKeyPressed(event)
case *tcell.EventMouse:
go s.onMouseClicked(convertMouseEvent(event))
default:
s.StopWithError(errors.New(fmt.Sprintf("%#v", event)))
}
}
s.StopWithError(errors.New("unknown error occured"))
}
func (s *Screen) Start() error { func (s *Screen) Start() error {
err := s.scr.Init() err := s.scr.Init()
if err != nil { if err != nil {
@ -99,6 +89,31 @@ func convertMouseEvent(original *tcell.EventMouse) *MouseEvent {
} }
func (s *Screen) Redraw() { func (s *Screen) Redraw() {
s.redrawCh <- struct{}{}
}
func (s *Screen) eventloop() {
defer s.stopOnPanic()
for evt := s.scr.PollEvent(); evt != nil; evt = s.scr.PollEvent() {
switch event := evt.(type) {
case *tcell.EventResize:
go s.Redraw()
case *tcell.EventKey:
go s.onKeyPressed(event)
case *tcell.EventMouse:
go s.onMouseClicked(convertMouseEvent(event))
default:
s.StopWithError(errors.New(fmt.Sprintf("%#v", event)))
}
}
s.StopWithError(errors.New("unknown error occured"))
}
func (s *Screen) drawloop() {
defer s.stopOnPanic()
for range s.redrawCh {
w, h := s.scr.Size() w, h := s.scr.Size()
if s.buf == nil || s.buf.Width() != w || s.buf.Height() != h { if s.buf == nil || s.buf.Width() != w || s.buf.Height() != h {
@ -109,3 +124,10 @@ func (s *Screen) Redraw() {
s.Root.Draw(truncateBuffer(s.buf, rw, rh)) s.Root.Draw(truncateBuffer(s.buf, rw, rh))
drawBuffer(s.scr, s.buf) drawBuffer(s.scr, s.buf)
} }
}
func (s *Screen) stopOnPanic() {
if err := recover(); err != nil {
s.StopWithError(fmt.Errorf("%v", err))
}
}