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 { type Screen struct {
scr tcell.Screen scr tcell.Screen
buf *ViewBuffer buf *ViewBuffer
stopCh chan error
Root View 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 is called every time a key or key-combination is pressed.
KeyPressed func(event *KeyEvent) (consumed bool) KeyPressed func(event *KeyEvent) (consumed bool)
@ -28,32 +32,18 @@ func NewScreen(root View) (*Screen, error) {
} }
s := &Screen{ s := &Screen{
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,13 +89,45 @@ func convertMouseEvent(original *tcell.EventMouse) *MouseEvent {
} }
func (s *Screen) Redraw() { func (s *Screen) Redraw() {
w, h := s.scr.Size() s.redrawCh <- struct{}{}
}
if s.buf == nil || s.buf.Width() != w || s.buf.Height() != h {
s.buf = buf2d.NewBuffer(w, h, DefaultRune) func (s *Screen) eventloop() {
} defer s.stopOnPanic()
rw, rh := s.Root.Layout() for evt := s.scr.PollEvent(); evt != nil; evt = s.scr.PollEvent() {
s.Root.Draw(truncateBuffer(s.buf, rw, rh)) switch event := evt.(type) {
drawBuffer(s.scr, s.buf) 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))
}
} }