aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/aerc.go5
-rw-r--r--lib/ui/interfaces.go4
-rw-r--r--lib/ui/ui.go71
-rw-r--r--main.go21
4 files changed, 35 insertions, 66 deletions
diff --git a/app/aerc.go b/app/aerc.go
index 21430f80..dbde484f 100644
--- a/app/aerc.go
+++ b/app/aerc.go
@@ -38,7 +38,6 @@ type Aerc struct {
pendingKeys []config.KeyStroke
prompts *ui.Stack
tabs *ui.Tabs
- ui *ui.UI
beep func() error
dialog ui.DrawableInteractive
@@ -832,10 +831,6 @@ func (aerc *Aerc) GetPassword(title string, prompt string) (chText chan string,
return
}
-func (aerc *Aerc) Initialize(ui *ui.UI) {
- aerc.ui = ui
-}
-
func (aerc *Aerc) DecryptKeys(keys []openpgp.Key, symmetric bool) (b []byte, err error) {
for _, key := range keys {
ident := key.Entity.PrimaryIdentity()
diff --git a/lib/ui/interfaces.go b/lib/ui/interfaces.go
index 19f0c04f..a8520ff5 100644
--- a/lib/ui/interfaces.go
+++ b/lib/ui/interfaces.go
@@ -22,10 +22,6 @@ type Visible interface {
Show(bool)
}
-type RootDrawable interface {
- Initialize(ui *UI)
-}
-
type Interactive interface {
// Returns true if the event was handled by this component
Event(event tcell.Event) bool
diff --git a/lib/ui/ui.go b/lib/ui/ui.go
index 628946fa..d2506b48 100644
--- a/lib/ui/ui.go
+++ b/lib/ui/ui.go
@@ -6,16 +6,12 @@ import (
"github.com/gdamore/tcell/v2"
)
-const (
- // nominal state, UI is up to date
- CLEAN int32 = iota
- // UI render has been queued in Redraw channel
- DIRTY
-)
+// Use unbuffered channels (always blocking unless somebody can read
+// immediately) We are merely using this as a proxy to tcell screen internal
+// event channel.
+var Events = make(chan tcell.Event)
-// State of the UI. Any value other than 0 means the UI is in a dirty state.
-// This should only be accessed via atomic operations to maintain thread safety
-var uiState int32
+var Quit = make(chan struct{})
var Callbacks = make(chan func(), 50)
@@ -31,28 +27,27 @@ var Redraw = make(chan bool, 1)
// Invalidate marks the entire UI as invalid and request a redraw as soon as
// possible. Invalidate can be called from any goroutine and will never block.
func Invalidate() {
- if atomic.SwapInt32(&uiState, DIRTY) != DIRTY {
+ if atomic.SwapUint32(&state.dirty, 1) != 1 {
Redraw <- true
}
}
-type UI struct {
- Content DrawableInteractive
- Quit chan struct{}
- Events chan tcell.Event
+var state struct {
+ content DrawableInteractive
ctx *Context
screen tcell.Screen
popover *Popover
+ dirty uint32 // == 1 if render has been queued in Redraw channel
}
-func Initialize(content DrawableInteractive) (*UI, error) {
+func Initialize(content DrawableInteractive) error {
screen, err := tcell.NewScreen()
if err != nil {
- return nil, err
+ return err
}
if err = screen.Init(); err != nil {
- return nil, err
+ return err
}
screen.Clear()
@@ -61,16 +56,9 @@ func Initialize(content DrawableInteractive) (*UI, error) {
width, height := screen.Size()
- state := UI{
- Content: content,
- screen: screen,
- // Use unbuffered channels (always blocking unless somebody can
- // read immediately) We are merely using this as a proxy to
- // tcell screen internal event channel.
- Events: make(chan tcell.Event),
- Quit: make(chan struct{}),
- }
- state.ctx = NewContext(width, height, screen, state.onPopover)
+ state.content = content
+ state.screen = screen
+ state.ctx = NewContext(width, height, state.screen, onPopover)
Invalidate()
if beeper, ok := content.(DrawableInteractiveBeeper); ok {
@@ -78,31 +66,28 @@ func Initialize(content DrawableInteractive) (*UI, error) {
}
content.Focus(true)
- if root, ok := content.(RootDrawable); ok {
- root.Initialize(&state)
- }
- go state.screen.ChannelEvents(state.Events, state.Quit)
+ go state.screen.ChannelEvents(Events, Quit)
- return &state, nil
+ return nil
}
-func (state *UI) onPopover(p *Popover) {
+func onPopover(p *Popover) {
state.popover = p
}
-func (state *UI) Exit() {
- close(state.Quit)
+func Exit() {
+ close(Quit)
}
-func (state *UI) Close() {
+func Close() {
state.screen.Fini()
}
-func (state *UI) Render() {
- if atomic.SwapInt32(&uiState, CLEAN) != CLEAN {
+func Render() {
+ if atomic.SwapUint32(&state.dirty, 0) != 0 {
// reset popover for the next Draw
state.popover = nil
- state.Content.Draw(state.ctx)
+ state.content.Draw(state.ctx)
if state.popover != nil {
// if the Draw resulted in a popover, draw it
state.popover.Draw(state.ctx)
@@ -111,20 +96,20 @@ func (state *UI) Render() {
}
}
-func (state *UI) EnableMouse() {
+func EnableMouse() {
state.screen.EnableMouse()
}
-func (state *UI) HandleEvent(event tcell.Event) {
+func HandleEvent(event tcell.Event) {
if event, ok := event.(*tcell.EventResize); ok {
state.screen.Clear()
width, height := event.Size()
- state.ctx = NewContext(width, height, state.screen, state.onPopover)
+ state.ctx = NewContext(width, height, state.screen, onPopover)
Invalidate()
}
// if we have a popover, and it can handle the event, it does so
if state.popover == nil || !state.popover.Event(event) {
// otherwise, we send the event to the main content
- state.Content.Event(event)
+ state.content.Event(event)
}
}
diff --git a/main.go b/main.go
index 8e449aea..fe3a2e7b 100644
--- a/main.go
+++ b/main.go
@@ -27,13 +27,13 @@ import (
"git.sr.ht/~rjarry/aerc/lib/hooks"
"git.sr.ht/~rjarry/aerc/lib/ipc"
"git.sr.ht/~rjarry/aerc/lib/templates"
- libui "git.sr.ht/~rjarry/aerc/lib/ui"
+ "git.sr.ht/~rjarry/aerc/lib/ui"
"git.sr.ht/~rjarry/aerc/log"
"git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/types"
)
-func getCommands(selected libui.Drawable) []*commands.Commands {
+func getCommands(selected ui.Drawable) []*commands.Commands {
switch selected.(type) {
case *app.AccountView:
return []*commands.Commands{
@@ -104,7 +104,7 @@ func expandAbbreviations(cmd []string, sets []*commands.Commands) []string {
}
func execCommand(
- ui *libui.UI, cmd []string,
+ cmd []string,
acct *config.AccountConfig, msg *models.MessageInfo,
) error {
cmds := getCommands(app.SelectedTabContent())
@@ -228,8 +228,6 @@ func main() {
log.Infof("Starting up version %s", log.BuildInfo)
- var ui *libui.UI
-
deferLoop := make(chan struct{})
c := crypto.New()
@@ -239,14 +237,9 @@ func main() {
}
defer c.Close()
- app.Init(c, func(
- cmd []string, acct *config.AccountConfig,
- msg *models.MessageInfo,
- ) error {
- return execCommand(ui, cmd, acct, msg)
- }, getCompletions, &commands.CmdHistory, deferLoop)
+ app.Init(c, execCommand, getCompletions, &commands.CmdHistory, deferLoop)
- ui, err = libui.Initialize(app.Drawable())
+ err = ui.Initialize(app.Drawable())
if err != nil {
panic(err)
}
@@ -310,9 +303,9 @@ loop:
ui.HandleEvent(event)
case msg := <-types.WorkerMessages:
app.HandleMessage(msg)
- case callback := <-libui.Callbacks:
+ case callback := <-ui.Callbacks:
callback()
- case <-libui.Redraw:
+ case <-ui.Redraw:
ui.Render()
case <-ui.Quit:
err = app.CloseBackends()