Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

## Unreleased

- Add the Linux tray contract: `rivet::system::TrayIcon` hosts an
org.kde.StatusNotifierItem with a com.canonical.dbusmenu menu over the
session bus (GDBus), the pairing every desktop watcher serves (GNOME via
the AppIndicator extension, KDE natively). The opt-in stays an application
decision — `TrayIcon::available()` and the `tray` capability report a
reachable watcher; the icon, tooltip, and flat menu update in place, and
the watcher is re-registered automatically when GNOME Shell or the
extension reloads. Verified end to end against the real desktop watcher
(registration, property reads, menu layout, click dispatch) plus the
graceful no-watcher path in an isolated D-Bus session.
- Add optional human-readable `publisher` project metadata and use it for the
Windows MSI `Manufacturer`/Apps & Features Publisher value. Legacy projects
fall back to `display-name` instead of exposing a reverse-DNS identifier.
Expand Down
5 changes: 3 additions & 2 deletions docs/system-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ macOS asks the user for notification and login-item consent as required by the O
- an abstract-namespace Unix socket for the single-instance lease; secondaries forward their activation arguments to the primary over that socket;
- `ActivationArguments()` from `/proc/self/cmdline` for URL-scheme and file-association payloads registered by installers;
- `org.freedesktop.Notifications` over the session bus (GDBus), with stable notification ids for tagged replacements;
- `TrayIcon` — org.kde.StatusNotifierItem plus a com.canonical.dbusmenu menu, through the session bus (GDBus). This is an explicit opt-in, not an adapter default: desktop hosting is compositor-dependent (GNOME hosts it only through the AppIndicator extension, KDE natively), so the application checks `TrayIcon::available()` (or the `tray` capability) and decides. The icon, tooltip, and flat menu (labelled items, separators, enabled state) update in place; the watcher is re-registered whenever it reappears, so GNOME Shell restarts and extension reloads do not strand a running process without its icon. Methods and menu callbacks run on the thread-default main context the icon was constructed on — for GTK hosts, the main-loop thread;
- XDG autostart entries under `$XDG_CONFIG_HOME/autostart`;
- the Secret Service provider (GNOME Keyring, KWallet bridge) through libsecret for binary secrets; the capability is compiled in when libsecret is present and reported at runtime only when a provider is reachable;
- `sigaction` fatal-signal hooks that append a preformatted note (signal number plus restart arguments) to a file under the XDG state directory.

`rivet::system::Capabilities()` reports what the running session actually provides; a missing session bus, Secret Service provider, or libsecret build fails clearly at call time instead of silently degrading. The tray contract is deliberately absent: StatusNotifierItem hosting is compositor-dependent (GNOME hosts it only through an extension), so tray presence must be an explicit application decision rather than an adapter default.
`rivet::system::Capabilities()` reports what the running session actually provides; a missing session bus, Secret Service provider, or libsecret build fails clearly at call time instead of silently degrading.

The Linux integration binary self-checks the adapter (`RivetIntegration --system`): lease acquisition and activation forwarding, autostart entries, and the crash hook always run; notification and secure-storage checks skip themselves when the session lacks those services.
The Linux integration binary self-checks the adapter (`RivetIntegration --system`): lease acquisition and activation forwarding, autostart entries, and the crash hook always run; notification, tray, and secure-storage checks skip themselves when the session lacks those services.

## Settings, logs, and crashes

Expand Down
19 changes: 19 additions & 0 deletions platform/linux/Integration/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,25 @@ int run_system_self_check(std::vector<std::string> const& arguments) {
progress("skipping notifications (no session bus or notification host)");
}

if (has_capability(capabilities, "tray")) {
progress("checking the StatusNotifierItem tray");
require(rivet::system::TrayIcon::available(),
"the tray capability must imply an available StatusNotifierItem watcher");
rivet::system::TrayIcon tray("org.rivet.integration.test",
"Rivet Linux integration",
"network-transmit-receive");
std::vector<rivet::system::TrayMenuItem> items;
items.emplace_back("Open", [] {});
items.emplace_back(rivet::system::TrayMenuItem::Type::separator);
items.emplace_back("Disabled", [] {}, false);
tray.set_menu(std::move(items));
tray.set_tooltip("Rivet Linux integration", "tray self-check");
// Registration went to the watcher; a desktop session answers the
// layout/property fetches from the main loop this thread must run.
} else {
progress("skipping tray (no session bus or StatusNotifierItem watcher)");
}

if (has_capability(capabilities, "secure-storage")) {
progress("checking Secret Service secure storage");
std::string const service = "org.rivet.integration.test";
Expand Down
Loading
Loading