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.
This commit is contained in:
Liken Tan authored and GitHub committed 2026-10-03 12:53:23 +08:00
1 parent ec3c64c140
commit 2e3fffe794
3 files changed
+39

No files matched your search

+4
View File
@@ -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
}
+31
View File
@@ -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.
+4
View File
@@ -10,3 +10,7 @@ func trayImageShow([]trayCell, []byte) bool { return false }
func trayImageFrame([]byte) bool { return false }
func trayImageHide() {}
func trayHighlight(bool) {}
func trayOwnClicks() {}