Fix watcher registration on wayland (#6320)

* Fix hover label on linux

* Fix watcher registration on wayland
This commit is contained in:
Pascal Fischer
2026-06-01 21:48:39 +02:00
committed by GitHub
parent 61da51ed2e
commit 8d05fe07bf
2 changed files with 39 additions and 2 deletions

View File

@@ -98,9 +98,27 @@ func (w *statusNotifierWatcher) tryStartXembedHost(busName string, objPath dbus.
}
// startStatusNotifierWatcher claims org.kde.StatusNotifierWatcher on the
// session bus if it is not already provided by another process.
// Safe to call unconditionally — it does nothing when a real watcher is present.
// session bus, but ONLY as a bridge to an XEmbed system tray on minimal WMs.
//
// The in-process watcher is a stub: its RegisterStatusNotifierItem only
// tracks items so it can mirror them into an XEmbed tray icon — it does
// NOT relay them to any other StatusNotifierHost. So if we claim the name
// on a desktop that has a real watcher/host (e.g. Hyprland + Waybar), every
// other tray app (Slack, etc.) registers into our dead-end watcher and its
// icon never reaches the real host. We won that name purely by starting
// first; a GetNameOwner check doesn't help against a login-order race.
//
// The correct discriminator is whether an XEmbed tray actually exists. If
// one does, we are the bridge of last resort and should claim the watcher.
// If not (pure Wayland, or any environment already running a real watcher),
// we have nothing to bridge and must stay off the bus entirely so the real
// watcher owns the name. Safe to call unconditionally.
func startStatusNotifierWatcher() {
if !xembedTrayAvailable() {
log.Debugf("StatusNotifierWatcher: no XEmbed tray present, leaving the watcher to the desktop")
return
}
conn, err := dbus.SessionBusPrivate()
if err != nil {
log.Debugf("StatusNotifierWatcher: cannot open private session bus: %v", err)

View File

@@ -88,6 +88,25 @@ func goMenuItemClicked(id C.int) {
}
// newXembedHost creates an XEmbed tray icon for the given SNI item.
// xembedTrayAvailable reports whether an XEmbed system tray manager
// (_NET_SYSTEM_TRAY_S0) currently owns its selection on the default screen.
// It is a cheap, side-effect-free probe — it only queries the selection
// owner, creating no windows. Used to decide whether the in-process
// StatusNotifierWatcher is needed at all: the watcher exists solely to
// bridge SNI items into an XEmbed tray on minimal WMs, so when no XEmbed
// tray is present (e.g. Wayland compositors with a real SNI host like
// Waybar) we must not claim org.kde.StatusNotifierWatcher and shadow the
// real one. Returns false when there is no X display (pure Wayland).
func xembedTrayAvailable() bool {
dpy := C.XOpenDisplay(nil)
if dpy == nil {
return false
}
defer C.XCloseDisplay(dpy)
screen := C.xembed_default_screen(dpy)
return C.xembed_find_tray(dpy, screen) != 0
}
// Returns an error if no XEmbed tray manager is available (graceful fallback).
func newXembedHost(conn *dbus.Conn, busName string, objPath dbus.ObjectPath) (*xembedHost, error) {
dpy := C.XOpenDisplay(nil)