about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBen Burwell <ben@benburwell.com>2019-07-29 10:50:02 -0400
committerDrew DeVault <sir@cmpwn.com>2019-07-29 15:01:49 -0400
commit152f8c9519ac1b7b35c3789b03f3d1cc3b1e8881 (patch)
tree0c8693aa2651955d0e12f090f5469c7183e190d3
parent2804f000017c0ef6bcaf8d571627fa08784f48ac (diff)
downloadaerc-152f8c9519ac1b7b35c3789b03f3d1cc3b1e8881.tar.gz
Ring bell when new messages arrive 0.2.0
Add a "new-message-bell" option to the UI section of aerc.conf. A new
hook into the message store allows the msglist widget to detect new
messages being added to the displayed list. When new messages are
delivered, and the new-message-bell option is enabled (as it is by
default), the terminal will beep.
-rw-r--r--config/aerc.conf.in6
-rw-r--r--config/config.go2
-rw-r--r--doc/aerc-config.5.scd5
-rw-r--r--lib/msgstore.go15
-rw-r--r--lib/ui/interfaces.go9
-rw-r--r--lib/ui/ui.go3
-rw-r--r--widgets/account.go4
-rw-r--r--widgets/aerc.go15
-rw-r--r--widgets/tabhost.go1
9 files changed, 56 insertions, 4 deletions
diff --git a/config/aerc.conf.in b/config/aerc.conf.in
index 55dfa13..4d0f9fd 100644
--- a/config/aerc.conf.in
+++ b/config/aerc.conf.in
@@ -37,6 +37,12 @@ empty-dirlist=(no folders)
 # Default: false
 mouse-enabled=false
 
+#
+# Ring the bell when new messages are received
+#
+# Default: yes
+new-message-bell=true
+
 [viewer]
 #
 # Specifies the pager to use when displaying emails. Note that some filters
diff --git a/config/config.go b/config/config.go
index 8ba705c..bfcbecf 100644
--- a/config/config.go
+++ b/config/config.go
@@ -32,6 +32,7 @@ type UIConfig struct {
 	EmptyMessage      string   `ini:"empty-message"`
 	EmptyDirlist      string   `ini:"empty-dirlist"`
 	MouseEnabled      bool     `ini:"mouse-enabled"`
+	NewMessageBell    bool     `ini:"new-message-bell"`
 }
 
 const (
@@ -344,6 +345,7 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
 			EmptyMessage:      "(no messages)",
 			EmptyDirlist:      "(no folders)",
 			MouseEnabled:      false,
+			NewMessageBell:    true,
 		},
 
 		Viewer: ViewerConfig{
diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index 7282311..a57f760 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -105,6 +105,11 @@ These options are configured in the *[ui]* section of aerc.conf.
 
 	Default: false
 
+*new-message-bell*
+	Ring the bell when a new message is received.
+
+	Default: true
+
 ## VIEWER
 
 These options are configured in the *[viewer]* section of aerc.conf.
diff --git a/lib/msgstore.go b/lib/msgstore.go
index 48a105e..b346129 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -33,12 +33,14 @@ type MessageStore struct {
 	pendingHeaders map[uint32]interface{}
 	worker         *types.Worker
 
-	triggerNewEmail func(*models.MessageInfo)
+	triggerNewEmail        func(*models.MessageInfo)
+	triggerDirectoryChange func()
 }
 
 func NewMessageStore(worker *types.Worker,
 	dirInfo *models.DirectoryInfo,
-	triggerNewEmail func(*models.MessageInfo)) *MessageStore {
+	triggerNewEmail func(*models.MessageInfo),
+	triggerDirectoryChange func()) *MessageStore {
 
 	return &MessageStore{
 		Deleted: make(map[uint32]interface{}),
@@ -52,7 +54,8 @@ func NewMessageStore(worker *types.Worker,
 		pendingHeaders: make(map[uint32]interface{}),
 		worker:         worker,
 
-		triggerNewEmail: triggerNewEmail,
+		triggerNewEmail:        triggerNewEmail,
+		triggerDirectoryChange: triggerDirectoryChange,
 	}
 }
 
@@ -147,6 +150,7 @@ func merge(to *models.MessageInfo, from *models.MessageInfo) {
 
 func (store *MessageStore) Update(msg types.WorkerMessage) {
 	update := false
+	directoryChange := false
 	switch msg := msg.(type) {
 	case *types.DirectoryInfo:
 		store.DirInfo = *msg.Info
@@ -159,6 +163,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
 				newMap[uid] = msg
 			} else {
 				newMap[uid] = nil
+				directoryChange = true
 			}
 		}
 		store.Messages = newMap
@@ -225,6 +230,10 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
 	if update {
 		store.update()
 	}
+
+	if directoryChange && store.triggerDirectoryChange != nil {
+		store.triggerDirectoryChange()
+	}
 }
 
 func (store *MessageStore) OnUpdate(fn func(store *MessageStore)) {
diff --git a/lib/ui/interfaces.go b/lib/ui/interfaces.go
index 9008ea7..2f63424 100644
--- a/lib/ui/interfaces.go
+++ b/lib/ui/interfaces.go
@@ -23,6 +23,10 @@ type Interactive interface {
 	Focus(focus bool)
 }
 
+type Beeper interface {
+	OnBeep(func() error)
+}
+
 type Simulator interface {
 	// Queues up the given input events for simulation
 	Simulate(events []tcell.Event)
@@ -33,6 +37,11 @@ type DrawableInteractive interface {
 	Interactive
 }
 
+type DrawableInteractiveBeeper interface {
+	DrawableInteractive
+	Beeper
+}
+
 // A drawable which contains other drawables
 type Container interface {
 	Drawable
diff --git a/lib/ui/ui.go b/lib/ui/ui.go
index 13b640b..4c3dd34 100644
--- a/lib/ui/ui.go
+++ b/lib/ui/ui.go
@@ -19,7 +19,7 @@ type UI struct {
 }
 
 func Initialize(conf *config.AercConfig,
-	content DrawableInteractive) (*UI, error) {
+	content DrawableInteractiveBeeper) (*UI, error) {
 
 	screen, err := tcell.NewScreen()
 	if err != nil {
@@ -57,6 +57,7 @@ func Initialize(conf *config.AercConfig,
 	content.OnInvalidate(func(_ Drawable) {
 		atomic.StoreInt32(&state.invalid, 1)
 	})
+	content.OnBeep(screen.Beep)
 	content.Focus(true)
 
 	return &state, nil
diff --git a/widgets/account.go b/widgets/account.go
index 86ec00c..de81ab8 100644
--- a/widgets/account.go
+++ b/widgets/account.go
@@ -205,6 +205,10 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {
 				func(msg *models.MessageInfo) {
 					acct.conf.Triggers.ExecNewEmail(acct.acct,
 						acct.conf, msg)
+				}, func() {
+					if acct.conf.Ui.NewMessageBell {
+						acct.host.Beep()
+					}
 				})
 			acct.dirlist.SetMsgStore(msg.Info.Name, store)
 			store.OnUpdate(func(_ *lib.MessageStore) {
diff --git a/widgets/aerc.go b/widgets/aerc.go
index 90b56c8..23dac3e 100644
--- a/widgets/aerc.go
+++ b/widgets/aerc.go
@@ -30,6 +30,7 @@ type Aerc struct {
 	statusline  *StatusLine
 	pendingKeys []config.KeyStroke
 	tabs        *libui.Tabs
+	beep        func() error
 }
 
 func NewAerc(conf *config.AercConfig, logger *log.Logger,
@@ -84,6 +85,20 @@ func NewAerc(conf *config.AercConfig, logger *log.Logger,
 	return aerc
 }
 
+func (aerc *Aerc) OnBeep(f func() error) {
+	aerc.beep = f
+}
+
+func (aerc *Aerc) Beep() {
+	if aerc.beep == nil {
+		aerc.logger.Printf("should beep, but no beeper")
+		return
+	}
+	if err := aerc.beep(); err != nil {
+		aerc.logger.Printf("tried to beep, but could not: %v", err)
+	}
+}
+
 func (aerc *Aerc) Tick() bool {
 	more := false
 	for _, acct := range aerc.accounts {
diff --git a/widgets/tabhost.go b/widgets/tabhost.go
index 7c502cb..2c33cf8 100644
--- a/widgets/tabhost.go
+++ b/widgets/tabhost.go
@@ -8,4 +8,5 @@ type TabHost interface {
 	BeginExCommand()
 	SetStatus(status string) *StatusMessage
 	PushStatus(text string, expiry time.Duration) *StatusMessage
+	Beep()
 }