# Linux tray support (StatusNotifierWatcher + XEmbed) Minimal WMs (Fluxbox, OpenBox, i3, dwm, vanilla GNOME without the AppIndicator extension) don't ship a `StatusNotifierWatcher`, so tray icons using libayatana-appindicator / freedesktop StatusNotifier silently fail. `main.go` calls `startStatusNotifierWatcher()` *before* `NewTray` so the Wails systray's `RegisterStatusNotifierItem` call hits the in-process watcher we control. - `tray_watcher_linux.go` — owns `org.kde.StatusNotifierWatcher` on the session bus if no other process has it. Safe to call unconditionally. - `xembed_host_linux.go` + `xembed_tray_linux.{c,h}` — when an XEmbed tray (`_NET_SYSTEM_TRAY_S0`) is available, also start an in-process XEmbed host that bridges the SNI icon into the XEmbed tray. Reads `IconPixmap` over D-Bus, draws via cairo+X11, polls for clicks, fetches `com.canonical.dbusmenu.GetLayout` for the popup menu, fires `com.canonical.dbusmenu.Event` on click. **X error handling.** Xlib's default protocol-error handler calls `exit()`, so a single async X error from a tray race (tray manager window dying between `xembed_find_tray` and `xembed_dock`; `XMoveWindow` on a popup the WM already destroyed) would take the whole UI process down. `xembed_install_error_handlers()` (`xembed_tray_linux.c`) installs process-global logging no-op handlers via `XSetErrorHandler`/`XSetIOErrorHandler`; it's idempotent and called from the Go side after every `XOpenDisplay` (`newXembedHost`, `xembedTrayAvailable`). Because the handler slot is process-global, GTK's GDK init can clobber it (whoever installs last wins) — so the popup code's raw Xlib calls **on GDK's Display** (`x11_move_window`, the submenu `XTranslateCoordinates`) are additionally wrapped in GDK's own `gdk_x11_display_error_trap_push`/`_pop_ignored`, which is independent of the global handler. (Those GDK X11 backend calls warn `-Wdeprecated-declarations` in GTK4, like the existing `gdk_x11_surface_get_xid`/`gdk_x11_display_get_xdisplay` calls — expected, still functional.) Build is gated on `linux && !386`; the 386 build (no cgo) and non-Linux builds use the `tray_watcher_other.go` no-op.