From 7016c6f86ae09b3e49eab665aa013628db4ee102 Mon Sep 17 00:00:00 2001
From: Tim Culverhouse <tim@timculverhouse.com>
Date: Mon, 17 Oct 2022 15:16:10 -0500
Subject: [PATCH] aercmsg: add AercFuncMsg and QueueFunc

Introduce AercFuncMsg and QueueFunc. These are used in combination to
queue a function to be run in the main goroutine. This can be used to
prevent data races in delayed function calls (ie from debounce
functions).

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
---
 aerc.go      |  2 ++
 lib/ui/ui.go | 10 ++++++++++
 2 files changed, 12 insertions(+)

diff --git a/aerc.go b/aerc.go
index e5801a0..1826567 100644
--- a/aerc.go
+++ b/aerc.go
@@ -247,6 +247,8 @@ func main() {
 		switch event := event.(type) {
 		case tcell.Event:
 			ui.HandleEvent(event)
+		case *libui.AercFuncMsg:
+			event.Func()
 		case types.WorkerMessage:
 			aerc.HandleMessage(event)
 		}
diff --git a/lib/ui/ui.go b/lib/ui/ui.go
index 313f90d..ea181d3 100644
--- a/lib/ui/ui.go
+++ b/lib/ui/ui.go
@@ -13,12 +13,22 @@ const (
 
 var MsgChannel = make(chan AercMsg, 50)
 
+type AercFuncMsg struct {
+	Func func()
+}
+
 // QueueRedraw sends a nil message into the MsgChannel. Nothing will handle this
 // message, but a redraw will occur if the UI is marked as invalid
 func QueueRedraw() {
 	MsgChannel <- nil
 }
 
+// QueueFunc queues a function to be called in the main goroutine. This can be
+// used to prevent race conditions from delayed functions
+func QueueFunc(fn func()) {
+	MsgChannel <- &AercFuncMsg{Func: fn}
+}
+
 // dirty is the dirty state of the UI. Any value other than 0 means the UI is in
 // a dirty state. Dirty should only be accessed via atomic operations to
 // maintain thread safety