Fix tray icon missing when KeePassXC starts before the StatusNotifierWatcher - #13708
Open
tassiovirginio wants to merge 1 commit into
Open
tassiovirginio wants to merge 1 commit into
tassiovirginio wants to merge 1 commit into
Conversation
Qt 5.15 decides once per process whether a D-Bus system tray is available (static cache in QGenericUnixTheme::isDBusTrayAvailable). If KeePassXC starts before the StatusNotifierWatcher (e.g. right after login, before the shell is up), the first QSystemTrayIcon is created with no platform tray icon, never exports /StatusNotifierItem and a plain show()/retry can never recover: recreating the icon still hits the poisoned per-process cache. Fix by deferring creation of the tray icon until a watcher is present on the session bus, and keep retrying (5s timer) plus a QDBusServiceWatcher on org.kde.StatusNotifierWatcher that re-triggers registration as soon as a host appears (first boot race or tray host restart mid-session). Registration is verified against the watcher's RegisteredStatusNotifierItems by resolving the owning process of each item, accepting org.kde/org.freedesktop.StatusNotifierItem-<pid>-<n> and the dedicated QDBusMenuConnection unique name.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When KeePassXC starts before the StatusNotifierWatcher (system tray host) is available — e.g. right after login, before the shell is up, or after a tray-host restart — the tray icon never appears, and it never recovers even after the watcher shows up seconds later. The only way out was restarting the app.
This was reproducible on Wayland (niri + quickshell
dms.service) and affects any SNI host that starts after KeePassXC.Root cause (Qt 5.15)
Qt's generic Unix theme decides once per process whether a D-Bus tray is available:
If the first
QSystemTrayIconof the process is created while the watcher is absent,createPlatformSystemTrayIcon()returnsnullptr: the icon never gets a realQDBusTrayIcon,/StatusNotifierItemis never exported, and recreating the icon later still hits the poisoned static cache — so no amount ofshow()/recreate retries can ever register.Fix
org.kde.StatusNotifierWatcheris present on the session bus, so Qt evaluates its one-shot cache with the watcher up and a realQDBusTrayIcon(with/StatusNotifierItem+/MenuBar) is born.QDBusServiceWatcher::serviceRegisteredonorg.kde.StatusNotifierWatcherto re-trigger registration as soon as a host appears (first-boot race and mid-session host restart both covered).RegisteredStatusNotifierItemsand resolving the owning PID of each item — acceptsorg.kde.StatusNotifierItem-<pid>-<n>,org.freedesktop.StatusNotifierItem-<pid>-<n>and the dedicatedQDBusMenuConnectionunique name (e.g.:1.853/StatusNotifierItem).Q_OS_UNIX && !Q_OS_MACOS && !QT_NO_DBUS; no change on Windows/macOS. Tray menu is now owned viaQPointerso icon re-creation stays leak-free.Testing
Validated live on the session bus with
busctlwhile the real instance keeps running:Id="KeePassXC", registered, stable (no churn)Before the fix, the watcher-down case never exported
/StatusNotifierItemeven after minutes; after the fix it registers without restarting the app.