Capability and fallback
Capability querying
Section titled “Capability querying”Linux desktops are heavily fragmented, and Wayland strictly restricts some capabilities outright. Code that assumes a feature exists fails on the next machine.
UDA’s contract: every feature reports its support level, so the application branches before calling.
SupportLevel tri-state
Section titled “SupportLevel tri-state”SupportLevel is defined in uda_core::capability with three variants:
| Variant | Meaning | What your app should do |
|---|---|---|
SupportLevel::Full |
fully supported | use it normally |
SupportLevel::Partial |
available in a degraded form (a limited set of monitors, modes or formats) | use it, but do not promise the missing part to the user |
SupportLevel::None |
not available | hide the entry, or explain why |
Partial carries no reason string. When a backend needs to say why, it returns a typed UdaError at call time instead — the diagnostic text travels with the error, not with the capability level.
Capability bit flags
Section titled “Capability bit flags”Underneath, capabilities are a set of bitflags, one bit per feature:
use uda_core::capability::Capability;
let caps = manager.capabilities()?;
if caps.contains(Capability::SET_WALLPAPER) { // show the "change wallpaper" button}A Rust trait’s capabilities() returns a Capability; the C-ABI exposes the same information as plain integer bits (see session capability bits for that module’s table).
The four-tier chain
Section titled “The four-tier chain”Every OS desktop action on Linux strictly follows:
Tier 1 XDG Desktop Portal is org.freedesktop.portal.* available? ↓ noTier 2 Native DE IPC read $XDG_CURRENT_DESKTOP, call GNOME/KDE D-Bus methods, or Hyprland/Sway sockets ↓ noTier 3 CLI tools probe PATH for swww / hyprpaper / feh / nitrogen / xfconf-query ↓ noTier 4 Typed error UdaError::Unsupported("...")When all three service tiers fail there is no panic and no bare io::Error — the caller gets a UdaError::Unsupported carrying a diagnosis.
The actual chain for wallpaper, which does not use the portal:
| Desktop | Mechanism |
|---|---|
| GNOME 42+ | the gsettings CLI, writing picture-uri and picture-uri-dark as a pair |
| KDE Plasma | D-Bus org.kde.plasmashell → /PlasmaShell → evaluateScript |
| Hyprland | the hyprpaper CLI, falling back to swww |
| Sway | the swww CLI |
| Generic X11 | the feh CLI, falling back to nitrogen |
Querying from a host application
Section titled “Querying from a host application”use uda_core::capability::SupportLevel;use uda_core::tray::{TrayFeature, TrayManager};
let manager = uda_platform_linux::LinuxTrayManager::new();
// Cheap, always answers.let level = manager.support_level(TrayFeature::Tooltip);
match level { SupportLevel::Full => { /* draw the tooltip field */ } SupportLevel::Partial => { warn!("tooltip is degraded on this backend") } SupportLevel::None => { /* hide it */ }}support_level answers from the capability set the backend published at registration, so the value always describes this icon’s environment. Before a backend publishes, the answer stays SupportLevel::None — the honest default when no tray mechanism could be reached.
For features that are not tray-related, the same information is exposed per module: the notification backend has capabilities(), the session backend reports one bit per action, and the Python / Node.js SDKs surface the session bits directly.
Rule: Partial is reserved
Section titled “Rule: Partial is reserved”A backend publishes Partial only when it can genuinely deliver a degraded behaviour — Linux double-click synthesis, or a tooltip longer than the soft cap. An absent flag is a plain None, never a guess. This keeps “advertised” equivalent to “deliverable”.
See also
Section titled “See also”- Fallback engine — how each tier probes and decides
- Platform support — the per-desktop matrix
- Troubleshooting — what to do when something reports
Unsupported
