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

@ -9,10 +9,14 @@ import (
)
type Screen struct {
scr tcell.Screen
buf *ViewBuffer
stopCh chan error
Root View
scr tcell.Screen
buf *ViewBuffer
stopCh chan error
redrawCh chan struct{}
// Root is the root view which is currently shown on screen
Root View
// KeyPressed is called every time a key or key-combination is pressed.
KeyPressed func(event *KeyEvent) (consumed bool)
@ -28,32 +32,18 @@ func NewScreen(root View) (*Screen, error) {
}
s := &Screen{
Root: root,
scr: scr,
stopCh: make(chan error, 1),
Root: root,
scr: scr,
stopCh: make(chan error, 1),
redrawCh: make(chan struct{}, 1),
}
go s.eventloop()
go s.drawloop()
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 {
err := s.scr.Init()
if err != nil {
@ -99,13 +89,45 @@ func convertMouseEvent(original *tcell.EventMouse) *MouseEvent {
}
func (s *Screen) Redraw() {
w, h := s.scr.Size()
if s.buf == nil || s.buf.Width() != w || s.buf.Height() != h {
s.buf = buf2d.NewBuffer(w, h, DefaultRune)
}
rw, rh := s.Root.Layout()
s.Root.Draw(truncateBuffer(s.buf, rw, rh))
drawBuffer(s.scr, s.buf)
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()
if s.buf == nil || s.buf.Width() != w || s.buf.Height() != h {
s.buf = buf2d.NewBuffer(w, h, DefaultRune)
}
rw, rh := s.Root.Layout()
s.Root.Draw(truncateBuffer(s.buf, rw, rh))
drawBuffer(s.scr, s.buf)
}
}
func (s *Screen) stopOnPanic() {
if err := recover(); err != nil {
s.StopWithError(fmt.Errorf("%v", err))
}
}