libayatana-appindicator activates XEmbed fallback when xapp-sn-watcher hasn't claimed its bus name at boot — duplicate icon in systray + xapp-status applets
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 45/100
Direzione di ricerca
Inizia ispezionando xapp-sn-watcher.desktop e il percorso di avvio di xapp-sn-watcher, concentrandoti su quando org.kde.StatusNotifierWatcher viene rivendicato sul bus di sessione. Confronta le fasi di inizializzazione e delle applicazioni descritte nell’issue. Il lavoro è completato quando il watcher rivendica il proprio nome prima che i client AppIndicator possano attivare il fallback XEmbed, e i test di avvio a freddo mostrano un’icona invece di duplicati.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
TITLE:
libayatana-appindicator activates XEmbed fallback when xapp-sn-watcher hasn't claimed its bus name at boot — duplicate icon in systray + xapp-status applets
────────────────────────────────────────────────────────────────────────────────
BODY:
Summary
AppIndicator apps show two tray icons at boot — one in xapp-status@cinnamon.org
(small, tooltip works) and one in systray@cinnamon.org (larger, no tooltip).
Single process, registered once on the StatusNotifierWatcher bus, but visible
in two applets simultaneously.
Observed on two independent apps: Diodon 1.13.0 and a local
AyatanaAppIndicator3 Python app. Neither app registers more than once.
This is the same symptom reported and never code-fixed in
cinnamon#8426, cjs#74, and xapp#157. The 2022 hypothesis from @mtwebster in
#157 — "They're probably not showing up in the xapp applet twice, but once
there and once in the old system tray applet" — is correct. I have controlled
reproduction and a confirmed fix.
Environment
- OS: Linux Mint 22.3 Cinnamon 6.6.7
- Kernel: 6.17.0-22-generic
- xapps-common: 3.2.2+zena
- cinnamon-common: 6.6.7+zena
- libayatana-appindicator3-1: 0.5.93-1build3
Visual identification — two applets, not one
The duplicate icons render differently, which identifies which applet each
belongs to:
| Property | Small icon | Large icon |
|---|---|---|
| Size | Panel-native (xapp-status sizing) | Larger (systray sizing) |
| Hover tooltip | ✓ appears (AppIndicator title prop) |
✗ absent (XEmbed has no equivalent) |
| Menu on click | App's own menu | App's own menu (same underlying object) |
| Applet | xapp-status@cinnamon.org |
systray@cinnamon.org |
Confirmed by checking gdbus — the indicator appears once on the
StatusNotifierWatcher bus:
$ gdbus call --session --dest org.kde.StatusNotifierWatcher \
--object-path /StatusNotifierWatcher \
--method org.freedesktop.DBus.Properties.Get \
org.kde.StatusNotifierWatcher RegisteredStatusNotifierItems
(<[':1.72/org/ayatana/NotificationItem/Diodon'
':1.76/org/ayatana/NotificationItem/battery_limit'
...]>,)
The duplication is downstream of the watcher — between the watcher and the
panel applets.
Root cause: boot-time race between xapp-sn-watcher and AppIndicator clients
Both apps and xapp-sn-watcher autostart in the same second at session login:
14:52:48 — xapp-sn-watcher PID 1997
14:52:48 — battery-limit-tray PID 2025
14:52:48 — diodon PID 2038
libayatana-appindicator checks at set_status(ACTIVE) whether
org.kde.StatusNotifierWatcher is owned on the session bus. If the watcher
process is alive but has not yet claimed that name (a race window of a few
hundred milliseconds at cold boot), the library activates a legacy
Gtk.StatusIcon XEmbed fallback. When the watcher comes up moments later,
the library also completes the StatusNotifier registration. Both paths remain
active: one icon in xapp-status, one in systray.
Controlled reproduction confirming the mechanism
I patched my local AppIndicator app to wait until org.kde.StatusNotifierWatcher
is actually owned before calling set_status(ACTIVE):
def wait_for_status_notifier_watcher(timeout_s=30):
bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
deadline = time.monotonic() + timeout_s
while time.monotonic() < deadline:
try:
res = bus.call_sync(
"org.freedesktop.DBus", "/org/freedesktop/DBus",
"org.freedesktop.DBus", "NameHasOwner",
GLib.Variant("(s)", ("org.kde.StatusNotifierWatcher",)),
GLib.VariantType("(b)"), Gio.DBusCallFlags.NONE, 1000, None,
)
if res.unpack()[0]:
return True
except GLib.Error:
pass
time.sleep(0.2)
return False
# called immediately before set_status(ACTIVE)
wait_for_status_notifier_watcher()
self.indicator.set_status(AyatanaAppIndicator3.IndicatorStatus.ACTIVE)
I then ran 5 cold reboots, alternating between the patched and unpatched
versions:
With watcher-wait patch (tested separately before revert):
battery_limit: 1 icon across multiple boots — no duplicate.
After reverting the patch (5 consecutive cold reboots):
| Reboot | Result |
|---|---|
| 1 | battery_limit: 1 icon (race did not trigger) |
| 2 | battery_limit: 2 icons (large systray + small xapp-status) |
| 3 | Diodon: 2 icons (large systray + small xapp-status); battery_limit: 1 |
| 4 | Diodon: 2 icons |
| 5 | 1 icon each (race did not trigger) |
Two things are clear from this data:
- The watcher-wait fix directly prevents the bug — with it in place, no
duplicate appeared across any boot. After reverting, the duplicate appeared
on 3 of 5 reboots across two different apps. - The bug is non-deterministic — whether the race triggers depends on
scheduler timing at each boot. Reboots 1 and 5 show no duplicate even
without the fix. This explains why all three previous issues were closed
without a code fix: if a maintainer tested on a fast machine where the
watcher claims its name in under 100ms, they would never see the bug.
Diodon exhibits the identical symptom but I cannot patch it; it demonstrates
that the bug affects any AppIndicator app that starts in the same boot-time
window as xapp-sn-watcher.
Why the fix belongs in xapp-sn-watcher, not per-app
The app-side fix works but is the wrong place for it. Users cannot patch
apps they don't maintain (Diodon, Transmission, etc.). The clean fix is to
ensure xapp-sn-watcher claims org.kde.StatusNotifierWatcher on the session
bus before any user-session AppIndicator client could race it.
The simplest approach: add an autostart phase hint to
xapp-sn-watcher.desktop so it starts in the initialization phase rather
than the applications phase. Alternatively, libayatana-appindicator could
be patched to de-activate its XEmbed fallback if the watcher claims its name
shortly after activation — but that crosses package boundaries.
This was all compiled with Claude Code.
Happy to test patches or provide D-Bus traces.
- Lingua principale
- C
- Stelle
- 167
- Fork
- 49
- Merge medio
- 5g 15h
- PR unite (30g)
- 2
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di linuxmint/xapp
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 72/100
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 42/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 55/100
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 42/100
Tutte le issue di linuxmint/xapp
Issue simili
-
task
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
vsanthanam/JBird#429 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
-
bug documentation
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
es-ude/OnDeviceTraining#459 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
bilelmoussaoui/gobject-linter#199 · 1 commento ·
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
bradcypert/plum#53 ·