mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-02 04:51:29 +02:00
client/ui: retry XEmbed-tray probe before claiming SNI watcher
The XEmbed tray (panel) can come up after the autostarted UI on minimal WMs, so the single startup probe added in #6320 could miss a tray that appears a second or two later, leaving the icon silently absent. Re-probe for a ~10s grace period in a goroutine, claiming the watcher as soon as a tray shows up; back off cleanly if none ever appears (headless/Wayland).
This commit is contained in:
@@ -18,6 +18,7 @@ package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -27,6 +28,16 @@ const (
|
||||
watcherName = "org.kde.StatusNotifierWatcher"
|
||||
watcherPath = "/StatusNotifierWatcher"
|
||||
watcherIface = "org.kde.StatusNotifierWatcher"
|
||||
|
||||
// watcherProbeInterval / watcherProbeTimeout bound how long we keep
|
||||
// re-probing for an XEmbed tray before giving up. The UI is commonly
|
||||
// autostarted *before* the panel/tray on minimal WMs, so a single probe
|
||||
// at startup would miss a tray that comes up a second or two later and
|
||||
// the icon would silently never appear. ~10s of polling covers a slow
|
||||
// panel launch while staying short enough that a headless / pure-Wayland
|
||||
// session (no XEmbed tray ever) winds down quickly.
|
||||
watcherProbeInterval = 500 * time.Millisecond
|
||||
watcherProbeTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
type statusNotifierWatcher struct {
|
||||
@@ -113,12 +124,34 @@ func (w *statusNotifierWatcher) tryStartXembedHost(busName string, objPath dbus.
|
||||
// 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.
|
||||
//
|
||||
// The XEmbed tray may come up *after* the UI (the panel and the autostarted
|
||||
// app race at login), so we re-probe for a short grace period instead of
|
||||
// deciding once at startup. The probing runs in a goroutine so it never
|
||||
// blocks the caller's startup path.
|
||||
func startStatusNotifierWatcher() {
|
||||
if !xembedTrayAvailable() {
|
||||
log.Debugf("StatusNotifierWatcher: no XEmbed tray present, leaving the watcher to the desktop")
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
deadline := time.Now().Add(watcherProbeTimeout)
|
||||
for {
|
||||
if xembedTrayAvailable() {
|
||||
claimStatusNotifierWatcher()
|
||||
return
|
||||
}
|
||||
if time.Now().After(deadline) {
|
||||
log.Debugf("StatusNotifierWatcher: no XEmbed tray appeared within %s, leaving the watcher to the desktop", watcherProbeTimeout)
|
||||
return
|
||||
}
|
||||
time.Sleep(watcherProbeInterval)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// claimStatusNotifierWatcher opens a private session-bus connection and takes
|
||||
// ownership of org.kde.StatusNotifierWatcher, exporting the in-process stub
|
||||
// watcher. The caller has already confirmed an XEmbed tray is present, so we
|
||||
// genuinely have an item to bridge. The GetNameOwner / DoNotQueue guards still
|
||||
// back off if a real watcher already holds the name.
|
||||
func claimStatusNotifierWatcher() {
|
||||
conn, err := dbus.SessionBusPrivate()
|
||||
if err != nil {
|
||||
log.Debugf("StatusNotifierWatcher: cannot open private session bus: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user