From 1b445b9bd5da848409151cf2f72e63c31dd3aa55 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Thu, 1 Oct 2020 06:53:05 +1000 Subject: [PATCH] add mutex to views array --- gui.go | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/gui.go b/gui.go index 3f89951..99cbf00 100644 --- a/gui.go +++ b/gui.go @@ -48,6 +48,14 @@ type tabClickBinding struct { handler tabClickHandler } +type GuiMutexes struct { + // tickingMutex ensures we don't have two loops ticking. The point of 'ticking' + // is to refresh the gui rapidly so that loader characters can be animated. + tickingMutex sync.Mutex + + ViewsMutex sync.Mutex +} + // Gui represents the whole User Interface, including the views, layouts // and keybindings. type Gui struct { @@ -92,9 +100,7 @@ type Gui struct { // view edges SupportOverlaps bool - // tickingMutex ensures we don't have two loops ticking. The point of 'ticking' - // is to refresh the gui rapidly so that loader characters can be animated. - tickingMutex sync.Mutex + Mutexes GuiMutexes OnSearchEscape func() error // these keys must either be of type Key of rune @@ -192,11 +198,16 @@ func (g *Gui) SetView(name string, x0, y0, x1, y1 int, overlaps byte) (*View, er return v, nil } + g.Mutexes.ViewsMutex.Lock() + v := newView(name, x0, y0, x1, y1, g.outputMode) v.BgColor, v.FgColor = g.BgColor, g.FgColor v.SelBgColor, v.SelFgColor = g.SelBgColor, g.SelFgColor v.Overlaps = overlaps g.views = append(g.views, v) + + g.Mutexes.ViewsMutex.Unlock() + return v, errors.Wrap(ErrUnknownView, 0) } @@ -213,6 +224,9 @@ func (g *Gui) SetViewBeneath(name string, aboveViewName string, height int) (*Vi // SetViewOnTop sets the given view on top of the existing ones. func (g *Gui) SetViewOnTop(name string) (*View, error) { + g.Mutexes.ViewsMutex.Lock() + defer g.Mutexes.ViewsMutex.Unlock() + for i, v := range g.views { if v.name == name { s := append(g.views[:i], g.views[i+1:]...) @@ -225,6 +239,9 @@ func (g *Gui) SetViewOnTop(name string) (*View, error) { // SetViewOnBottom sets the given view on bottom of the existing ones. func (g *Gui) SetViewOnBottom(name string) (*View, error) { + g.Mutexes.ViewsMutex.Lock() + defer g.Mutexes.ViewsMutex.Unlock() + for i, v := range g.views { if v.name == name { s := append(g.views[:i], g.views[i+1:]...) @@ -243,6 +260,9 @@ func (g *Gui) Views() []*View { // View returns a pointer to the view with the given name, or error // ErrUnknownView if a view with that name does not exist. func (g *Gui) View(name string) (*View, error) { + g.Mutexes.ViewsMutex.Lock() + defer g.Mutexes.ViewsMutex.Unlock() + for _, v := range g.views { if v.name == name { return v, nil @@ -254,6 +274,9 @@ func (g *Gui) View(name string) (*View, error) { // ViewByPosition returns a pointer to a view matching the given position, or // error ErrUnknownView if a view in that position does not exist. func (g *Gui) ViewByPosition(x, y int) (*View, error) { + g.Mutexes.ViewsMutex.Lock() + defer g.Mutexes.ViewsMutex.Unlock() + // traverse views in reverse order checking top views first for i := len(g.views); i > 0; i-- { v := g.views[i-1] @@ -271,6 +294,9 @@ func (g *Gui) ViewByPosition(x, y int) (*View, error) { // ViewPosition returns the coordinates of the view with the given name, or // error ErrUnknownView if a view with that name does not exist. func (g *Gui) ViewPosition(name string) (x0, y0, x1, y1 int, err error) { + g.Mutexes.ViewsMutex.Lock() + defer g.Mutexes.ViewsMutex.Unlock() + for _, v := range g.views { if v.name == name { return v.x0, v.y0, v.x1, v.y1, nil @@ -281,6 +307,9 @@ func (g *Gui) ViewPosition(name string) (x0, y0, x1, y1 int, err error) { // DeleteView deletes a view by name. func (g *Gui) DeleteView(name string) error { + g.Mutexes.ViewsMutex.Lock() + defer g.Mutexes.ViewsMutex.Unlock() + for i, v := range g.views { if v.name == name { g.views = append(g.views[:i], g.views[i+1:]...) @@ -292,6 +321,9 @@ func (g *Gui) DeleteView(name string) error { // SetCurrentView gives the focus to a given view. func (g *Gui) SetCurrentView(name string) (*View, error) { + g.Mutexes.ViewsMutex.Lock() + defer g.Mutexes.ViewsMutex.Unlock() + for _, v := range g.views { if v.name == name { g.currentView = v @@ -914,8 +946,8 @@ func (g *Gui) execKeybinding(v *View, kb *keybinding) (bool, error) { func (g *Gui) StartTicking() { go func() { - g.tickingMutex.Lock() - defer g.tickingMutex.Unlock() + g.Mutexes.tickingMutex.Lock() + defer g.Mutexes.tickingMutex.Unlock() ticker := time.NewTicker(time.Millisecond * 50) defer ticker.Stop() outer: