summaryrefslogtreecommitdiff
path: root/lib/ui/ui.go
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2019-05-19 09:50:14 +0000
committerDrew DeVault <sir@cmpwn.com>2019-05-19 11:51:18 -0400
commit7c6325977b55385bc65f0a08f4da8ed6dfede52a (patch)
tree0aac968a8ade4204e57463ec68de7048eaf04668 /lib/ui/ui.go
parenta15ea01cfb0a303355b2e6bb31e85ece0d048ac2 (diff)
downloadaerc-7c6325977b55385bc65f0a08f4da8ed6dfede52a.zip
lib/ui/ui: use atomic instead of channel
This makes it so an atomic `invalid` value is used instead of an unbuffered channel. When many invalidations kick in, a lot of values were sent to the channel. (Since OnInvalidate's callback can be run in any goroutine, we need to be careful about races here.)
Diffstat (limited to 'lib/ui/ui.go')
-rw-r--r--lib/ui/ui.go47
1 files changed, 21 insertions, 26 deletions
diff --git a/lib/ui/ui.go b/lib/ui/ui.go
index 91a26da..f04d3d8 100644
--- a/lib/ui/ui.go
+++ b/lib/ui/ui.go
@@ -14,8 +14,8 @@ type UI struct {
ctx *Context
screen tcell.Screen
- tcEvents chan tcell.Event
- invalidations chan interface{}
+ tcEvents chan tcell.Event
+ invalid int32 // access via atomic
}
func Initialize(conf *config.AercConfig,
@@ -40,24 +40,22 @@ func Initialize(conf *config.AercConfig,
ctx: NewContext(width, height, screen),
screen: screen,
- tcEvents: make(chan tcell.Event, 10),
- invalidations: make(chan interface{}),
+ tcEvents: make(chan tcell.Event, 10),
}
+
state.exit.Store(false)
- go (func() {
+ go func() {
for !state.ShouldExit() {
state.tcEvents <- screen.PollEvent()
}
- })()
- go (func() {
- state.invalidations <- nil
- })()
+ }()
+
+ state.invalid = 1
content.OnInvalidate(func(_ Drawable) {
- go (func() {
- state.invalidations <- nil
- })()
+ atomic.StoreInt32(&state.invalid, 1)
})
content.Focus(true)
+
return &state, nil
}
@@ -74,6 +72,8 @@ func (state *UI) Close() {
}
func (state *UI) Tick() bool {
+ more := false
+
select {
case event := <-state.tcEvents:
switch event := event.(type) {
@@ -84,21 +84,16 @@ func (state *UI) Tick() bool {
state.Content.Invalidate()
}
state.Content.Event(event)
- case <-state.invalidations:
- for {
- // Flush any other pending invalidations
- select {
- case <-state.invalidations:
- break
- default:
- goto done
- }
- }
- done:
+ more = true
+ default:
+ }
+
+ wasInvalid := atomic.SwapInt32(&state.invalid, 0)
+ if wasInvalid != 0 {
state.Content.Draw(state.ctx)
state.screen.Show()
- default:
- return false
+ more = true
}
- return true
+
+ return more
}