Skip to content

On Linux with no StatusNotifier host (GNOME without AppIndicator, or no session bus) the tray runs invisibly with no message, despite the documented console fallback #71

Open

Description

@matt-edmondson

What's wrong

README's "Load-bearing behaviour" section says the console fallback covers "a DISPLAY pointing at nothing, a missing libX11, or no status-notifier host", and the comment on TrayAppBuilder.RecoverFromTrayFailure (TrayApp/TrayAppBuilder.cs, around L651-655) says the same. But when no org.kde.StatusNotifierWatcher is on the bus, Avalonia's DBusTrayIconImpl doesn't throw. It waits for one to appear. So StartWithClassicDesktopLifetime runs normally, HasStarted becomes true, and the tool sits there with no icon, no menu and no output. The only way out is Ctrl+C or kill. The same thing happens when there is no D-Bus session bus at all, where an icon can never appear.

Scenario

Run a TrayApp tool on stock GNOME (no AppIndicator extension), or from an X or ssh -X session with no DBUS_SESSION_BUS_ADDRESS. DesktopSession.IsAvailable returns true because DISPLAY is set, so the tool takes the tray path. OnStart runs (for NoSleep, that takes the inhibitor), nothing appears anywhere, and nothing is printed. --status meanwhile reports Tray icon: available (DISPLAY or WAYLAND_DISPLAY is set).

Reproduced at 3ef4d9e with the demo under Xvfb and TRAYAPP_DEBUG=1:

dbus-run-session -- sh -c 'xvfb-run -a dotnet ktsu.TrayApp.Demo.dll & sleep 12; ps ...'
# still alive after 12 s, stdout/stderr empty, tray.json written (OnStart ran)

env -u DBUS_SESSION_BUS_ADDRESS xvfb-run -a dotnet ktsu.TrayApp.Demo.dll
# silent until killed by timeout (exit 124), no fallback message

As a control, starting a watcher 8 s after the tool still registers the item (org.kde.StatusNotifierItem-<pid>-0). A host that arrives late is a real case, for example a login autostart racing the panel, so falling back to the console immediately would be wrong.

Suggested fix and acceptance criteria

  • On Linux, check the session bus before or just after starting the tray: is org.kde.StatusNotifierWatcher owned, and is IsStatusNotifierHostRegistered true? Tmds.DBus.Protocol is already in the dependency graph through Avalonia.FreeDesktop, but KTSU0006 means it needs a direct reference.
  • No session bus at all (no address and no $XDG_RUNTIME_DIR/bus): treat this like the other "no tray possible" cases. Print the existing "could not show a tray icon … Staying in the terminal instead." message and use the console runner, or have DesktopSession.IsAvailable return false.
  • Bus present but no watcher or host: write a stderr notice such as <tool>: no system tray (StatusNotifier host) is running; the icon will appear when one starts. Use --no-tray to run in the terminal. Optionally fall back after a grace period, but not immediately, so autostart keeps working.
  • --status / DesktopSession.Explanation tells apart "DISPLAY set, StatusNotifier host registered" and "DISPLAY set but no StatusNotifier host / no session bus".
  • The README row and the RecoverFromTrayFailure comment stop claiming that a missing host leads to a fallback.

Activity

  1. matt-edmondson commented on Nov 2, 2026

    @matt-edmondson
    ContributorAuthor

    Triage

    • Category: Bug
    • Priority: High. Stock GNOME is the most common Linux desktop, and on it a TrayApp tool runs with no icon, no menu and no output. The only way out is Ctrl+C or kill. OnStart still runs, so a tool such as NoSleep holds its inhibitor where the user can't see it. --status also reports that the tray is available, and the README promises a fallback. Together these make the problem hard to diagnose.
    • Area / suggested assignment: Linux desktop detection in DesktopSession.IsAvailable/Explanation and TrayAppBuilder.RecoverFromTrayFailure, plus the README's "Load-bearing behaviour" row. This needs a direct Tmds.DBus.Protocol reference, because KTSU0006 flags the transitive one.
    • Duplicates / in progress: No duplicate found, and no open PR covers this. Open PRs Leave a gap after the longest option in --help [patch] #58–Report an out-of-range number for an option as a usage error [patch] #70 cover option parsing, toggles and shutdown, not tray-host detection.
    • Next step: Handle the no-session-bus case first. It is unambiguous: fall back to the console runner with the existing message. Then add the stderr notice for a bus with no watcher or host, without an immediate fallback, so a late-starting panel still works. Update --status and the README in the same change.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions