thread safety for event loop and redraw loop
This commit is contained in:
parent
8be528e57a
commit
45c636ec33
86
screen.go
86
screen.go
@ -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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user