Evan Lowry a76858e646
client/systray: refresh in place; drop full rebuild on every event
Observed on a minimalist Wayland setup w/ ashell: every IPN-bus event
called systray.ResetMenu() and re-added the full menu. The resulting
LayoutUpdated signal storm let libdbusmenu hosts race into half-built
menus and cache empty submenus.

The menu is now built once and only rebuilt when its structural shape
changes.

Three further bugs surfaced while I was A/B testing these changes, that
I included fixes for:

  - The initial icon is set before systray.Run so the StatusNotifierItem
    exports a non-empty image; this crashed ashell (added resilience
    upstream at MalpenZibo/ashell#693) zero-size pixmap.
  - Mullvad VPN and multi-city country rows are now plain submenu items
    rather than checkboxes-with-children, which some hosts treated as
    selectable leaves -- clicking the parent dismissed the menu instead
    of expanding it (#17879)
  - Exit-node selection is driven off prefs.ExitNodeID rather than
    status.ExitNodeStatus.ID, so a configured-but-unreachable exit node
    renders as "exit node offline" instead of as a plain connected tray.

Fixes #15528
Fixes #17879

Signed-off-by: Evan Lowry <evan@tailscale.com>
2026-04-26 13:51:25 -03:00
..