From 2e3fffe794764afa5f40401aeef45a20f6a87f27 Mon Sep 17 00:00:00 2001 From: Liken Tan <15458805+likendev@users.noreply.github.com> Date: Sat, 3 Oct 2026 12:53:23 +0800 Subject: [PATCH] tray: the Mac's menu bar icon stays lit while the panel is open (#629) Clicking the icon lit it for a moment and put it out again: Wails sends the action on mouse-down, and the button's own tracking takes the highlight off on mouse-up, so it never stayed on while the panel was open, as other apps' items do. Lighting it from the panel's show alone still flickered (lit on press, out on release, lit again). mpOwnClicks (a local event monitor, installed once) now hands a left click on magpie's item to its action and swallows the mouse-down, so the button never tracks it; mpHighlight lights it when the panel shows and puts it out when it hides (events.Mac.WindowShow/WindowHide, hooked in makePanel, so a panel made again after lightweight mode has them too). Right clicks keep Wails' path and its native menu highlight. Linux and Windows get no-ops. go build (darwin app, GOOS=linux -tags nogui, GOOS=windows), go vet ./internal/gui and go test ./internal/gui pass. No automated test: it needs a live status item. To check by hand: a click lights it once and it stays lit; click again, a click elsewhere or Escape puts it out; right click still opens the menu, highlighted. --- internal/gui/lightweight.go | 4 ++++ internal/gui/trayimage_darwin.go | 31 +++++++++++++++++++++++++++++++ internal/gui/trayimage_other.go | 4 ++++ 3 files changed, 39 insertions(+) diff --git a/internal/gui/lightweight.go b/internal/gui/lightweight.go index d318a6eb..1fe2683f 100644 --- a/internal/gui/lightweight.go +++ b/internal/gui/lightweight.go @@ -108,6 +108,10 @@ func (h *host) makePanel() *application.WebviewWindow { if h.tray != nil { h.tray.AttachWindow(w).WindowOffset(6) } + // the icon stays lit while the panel is open (the Mac's) + trayOwnClicks() + w.OnWindowEvent(events.Mac.WindowShow, func(*application.WindowEvent) { trayHighlight(true) }) + w.OnWindowEvent(events.Mac.WindowHide, func(*application.WindowEvent) { trayHighlight(false) }) return w } diff --git a/internal/gui/trayimage_darwin.go b/internal/gui/trayimage_darwin.go index 9bbb1e49..61a4c69f 100644 --- a/internal/gui/trayimage_darwin.go +++ b/internal/gui/trayimage_darwin.go @@ -320,6 +320,31 @@ static void mpHide(void) { }); } +// mpHighlight lights the item while its panel is open, as the system's own +// items do. +static void mpHighlight(int on) { + dispatch_async(dispatch_get_main_queue(), ^{ + [mpButton() highlight:on != 0]; + }); +} + +// mpOwnClicks hands a left click on the item to its action before the +// button sees it: the button's own tracking would light it on mouse-down +// and put it out on mouse-up, a flicker before mpHighlight's. +static void mpOwnClicks(void) { + static dispatch_once_t once; + dispatch_once(&once, ^{ + dispatch_async(dispatch_get_main_queue(), ^{ + [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown handler:^NSEvent *(NSEvent *e) { + NSStatusBarButton *b = mpButton(); + if (b == nil || e.window != b.window) return e; + [NSApp sendAction:b.action to:b.target from:b]; + return nil; + }]; + }); + }); +} + // mpPNG draws the image as the menu bar would at scale, light or dark, on // the bar's colour when bg is set: for tests and previews. static void *mpPNG(mpTrayCell *cells, int n, const void *bird, int len, CGFloat h, CGFloat scale, int dark, int bg, int *outLen, int *pxW, int *pxH) { @@ -431,6 +456,12 @@ func trayImageFrame(bird []byte) bool { // trayImageHide takes the cells down; the icon set next is the bird alone. func trayImageHide() { C.mpHide() } +// trayHighlight lights the tray icon, or puts it out. +func trayHighlight(on bool) { C.mpHighlight(cBool(on)) } + +// trayOwnClicks keeps the button's own highlight out of a click (mpOwnClicks). +func trayOwnClicks() { C.mpOwnClicks() } + // trayImagePNG is the image as the menu bar h points high draws it at // scale (2 for a Retina screen), light or dark, on the bar's colour when // bg; with its size in pixels. diff --git a/internal/gui/trayimage_other.go b/internal/gui/trayimage_other.go index 4f23a070..41c4bf2f 100644 --- a/internal/gui/trayimage_other.go +++ b/internal/gui/trayimage_other.go @@ -10,3 +10,7 @@ func trayImageShow([]trayCell, []byte) bool { return false } func trayImageFrame([]byte) bool { return false } func trayImageHide() {} + +func trayHighlight(bool) {} + +func trayOwnClicks() {}