Linux tray contract: TrayIcon over StatusNotifierItem + dbusmenu - #130
Merged
Merged
Conversation
The Linux adapter deliberately omitted tray hosting because desktop support is compositor-dependent; that left downstream hosts without any system-tray surface (Windows has Shell_NotifyIconW), and close-to-tray apps like SyncPilot lose their only persistent entry point. Add an explicit opt-in rivet::system::TrayIcon: org.kde.StatusNotifierItem plus a com.canonical.dbusmenu menu over the session bus (GDBus, already a dependency). TrayIcon::available() and the new 'tray' capability report a reachable watcher, so tray presence remains an application decision; on a watcherless session the constructor fails clearly. Icon, tooltip and the flat menu (labelled items, separators, enabled state) update in place through NewIcon/NewToolTip/LayoutUpdated; left-click Activate reaches an optional activation handler; the item re-registers whenever the watcher reappears, so GNOME Shell restarts and extension reloads do not strand a running process without its icon. Dispatch (property reads, method calls, clicks) lands on the thread-default main context the icon was constructed on — for GTK hosts, the main-loop thread. Verified end to end against the live GNOME StatusNotifierWatcher: registration appears in RegisteredStatusNotifierItems, GetLayout returns the full tree, a delivered click Event fires the menu callback, set_icon flips the icon mid-run; an isolated dbus-run-session without a watcher fails clearly. The integration self-check exercises the tray when the capability is present and skips otherwise.
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.
Closes #118.
What
rivet::system::TrayIcon— the Linux counterpart of the WindowsShell_NotifyIconWadapter (same class name for symmetry): an explicit opt-in that hosts anorg.kde.StatusNotifierItemplus acom.canonical.dbusmenumenu over the session bus through GDBus (already a dependency of every Linux host build).TrayIcon::available()(a GetNameOwner probe onorg.kde.StatusNotifierWatcher) and the new"tray"entry inCapabilities()report a reachable watcher. Without one, the constructor fails clearly — same contract asNotificationson a bus-less session (verified: isolateddbus-run-session→ "tray is unavailable: no StatusNotifierItem watcher is running").TrayMenuItem— labelled items withenabled+ click callback, separators;set_menureplaces and bumps the dbusmenu layout revision (LayoutUpdated). Watcher-facing surface implements the methods clients actually call (GetLayout,GetGroupProperties,GetProperty,Event,EventGroup,AboutToShow,AboutToShowGroup, dbusmenu v3), pinned against the Ubuntu AppIndicator extension's client code.set_icon/set_tooltipemitNewIcon/NewToolTip; ToolTip serializesKDbusToolTipStruct.NameOwnerChangedwatch re-registers the item whenever the watcher reappears, so GNOME Shell restarts and AppIndicator extension reloads do not strand a running process without its icon.Activatereaches an optional activation handler (KDE; the GNOME extension opens the menu instead, matching upstream SNI behavior).docs/system-services.mdand the CHANGELOG updated.Verification (real desktop, not just compile)
-Wall -Wextraclean compile ofsystem_services.cppand syntax-check of the integration self-check.RegisteredStatusNotifierItems(icon visible in the top bar);GetLayoutreturns the full tree (root + items with correct labels/enabled/separator properties);Event"clicked" fires the menu callback on the main loop; a click on a disabled item does not;set_iconmid-run flips the icon and subsequent property reads see the new name.Deliberately out of scope (follow-ups)
set-tray-menu!mirror on a Linux adapter, which Linux: tray / StatusNotifierItem contract (tracking the documented honest gap) #118 also proposes, needs an RVT1 carrier first: no Linux host installs a Racket system adapter today).IconPixmap(themed icon names only),SecondaryActivate/Scrollbehavior (accepted, no-op).Bug-for-bug note: the two
@a{sv}-style format annotations in the GVariant serialization were caught by the live run (bare array positions consumed a pre-builtGVariant*as a builder and aborted under the watcher's first layout fetch) — exactly why the verification is a real session, not a mock.