From e1bf362675b05a77405264680fc00ce7e4ddc48c Mon Sep 17 00:00:00 2001 From: Zoltan Papp Date: Tue, 12 May 2026 21:46:05 +0200 Subject: [PATCH] [client/ui] Refresh tray menu after status-indicator bitmap change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wails v3 alpha's setMenuItemBitmap on darwin calls NSMenuItem.setImage from whichever thread invokes SetBitmap — unlike the sibling setters for label/disabled/hidden/checked, which dispatch_sync onto the main queue. The off-thread AppKit call doesn't redraw, so the coloured status dot stayed stale until the user closed and reopened the menu. Force a tray.SetMenu rebuild after updating the bitmap; the rebuild runs processMenu inside InvokeSync, which applies the bitmap to a fresh NSMenuItem on the main thread and macOS picks it up immediately. --- client/ui/tray.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/client/ui/tray.go b/client/ui/tray.go index 539a945b7..d68d00d03 100644 --- a/client/ui/tray.go +++ b/client/ui/tray.go @@ -571,11 +571,22 @@ func (t *Tray) rebuildExitNodes(nodes []string) { // palette: green for Connected, yellow for Connecting, blue for the // login states, red for hard errors, grey for the idle/disconnected // pair and a darker grey when the daemon socket is unreachable. +// +// Wails v3 alpha's setMenuItemBitmap calls NSMenuItem.setImage from +// whichever thread invoked SetBitmap — unlike setMenuItemLabel/Disabled/ +// Hidden/Checked which dispatch_sync onto the main queue. The off-thread +// AppKit call leaves the visible dot stale until the next time the menu +// is reopened (close+reopen workaround). Rebuilding via tray.SetMenu +// reruns processMenu inside InvokeSync, so the bitmap is applied to a +// fresh NSMenuItem on the main thread and macOS picks it up. func (t *Tray) applyStatusIndicator(status string) { if t.statusItem == nil { return } t.statusItem.SetBitmap(statusIndicatorBitmap(status)) + if t.menu != nil { + t.tray.SetMenu(t.menu) + } } func statusIndicatorBitmap(status string) []byte {