diff --git a/client/ui/tray.go b/client/ui/tray.go index a6dc094ff..07d162327 100644 --- a/client/ui/tray.go +++ b/client/ui/tray.go @@ -189,15 +189,19 @@ func NewTray(app *application.App, window *application.WebviewWindow, svc TraySe t.tray.SetTooltip(t.loc.T("tray.tooltip")) t.menu = t.buildMenu() t.tray.SetMenu(t.menu) - // Left-click on the tray icon opens the menu on every platform. The - // window is reached through the explicit "Open NetBird" entry. This - // matches macOS NSStatusItem convention (click → menu), the Linux - // StatusNotifierItem spec, and the legacy Fyne client. On Linux, - // AttachWindow plus Wails3's applySmartDefaults would also pop the - // window alongside the menu on environments like GNOME Shell with the - // AppIndicator extension, so we intentionally skip both AttachWindow - // and OnClick here. Right-click still opens the menu through Wails' - // default rightClickHandler fallback. + // Left-click on the tray icon opens the menu, and the window is reached + // through the explicit "Open NetBird" entry. This matches macOS + // NSStatusItem convention (click → menu), the Linux StatusNotifierItem + // spec, and the legacy Fyne client. macOS and Linux give us click→menu + // natively, so bindTrayClick is a no-op there (binding OnClick→OpenMenu + // on macOS would freeze the tray — see tray_click_other.go). Windows has + // no native left-click handler, so bindTrayClick wires one explicitly + // (see tray_click_windows.go). On Linux we deliberately skip AttachWindow: + // it plus Wails3's applySmartDefaults would pop the window alongside the + // menu on environments like GNOME Shell with the AppIndicator extension. + // Right-click opens the menu through Wails' default rightClickHandler on + // every platform. + bindTrayClick(t) app.Event.On(services.EventStatusSnapshot, t.onStatusEvent) app.Event.On(services.EventDaemonNotification, t.onSystemEvent) diff --git a/client/ui/tray_click_other.go b/client/ui/tray_click_other.go new file mode 100644 index 000000000..231986a47 --- /dev/null +++ b/client/ui/tray_click_other.go @@ -0,0 +1,13 @@ +//go:build !windows && !android && !ios && !freebsd && !js + +package main + +// bindTrayClick is a no-op on macOS and Linux. On macOS the native +// NSStatusItem auto-shows the menu on left-click; on Linux the +// StatusNotifierItem host paints the menu independently. Binding an +// OnClick→OpenMenu handler is both unnecessary there and actively harmful on +// macOS, where OpenMenu routes through NSStatusItem's blocking [button +// mouseDown:] on the serial main GCD queue and freezes the tray and webview +// until the menu closes (commit c77e5cef8). Windows opts in via the sibling +// tray_click_windows.go file. +func bindTrayClick(*Tray) {} diff --git a/client/ui/tray_click_windows.go b/client/ui/tray_click_windows.go new file mode 100644 index 000000000..8dece769a --- /dev/null +++ b/client/ui/tray_click_windows.go @@ -0,0 +1,22 @@ +//go:build windows + +package main + +// bindTrayClick wires the tray icon's left-click to open the menu on Windows. +// +// Unlike macOS (NSStatusItem auto-shows the menu on left-click) and Linux +// (the StatusNotifierItem host paints the menu itself), Wails v3's Windows +// systray installs a default left-click handler that only logs "Left Button +// Clicked" and does nothing visible — only right-click opens the menu via the +// default rightClickHandler (see systemtray_windows.go run()). Left-clicking +// the icon therefore appears dead to the user. We bind OnClick to OpenMenu so +// left- and right-click behave identically, matching the platform-native +// click→menu behaviour we get for free on macOS/Linux. +// +// The macOS freeze that motivated reverting an earlier OnClick→OpenMenu wiring +// (commit c77e5cef8: NSStatusItem's blocking [button mouseDown:] starves the +// serial main GCD queue) does not apply here — the Windows openMenu() path is +// the same menu.ShowAt() that right-click already uses without issue. +func bindTrayClick(t *Tray) { + t.tray.OnClick(func() { t.tray.OpenMenu() }) +}