Services Overview
Services are the backend layer of ashell. They manage communication with system APIs and produce events that modules consume. Services have no UI.
Available Services
| Service | Location | Backend | Protocol | Required Package |
|---|---|---|---|---|
| Compositor | services/compositor/ | Hyprland / Niri / MangoWC / generic Wayland | IPC socket / mmsg / Wayland protocols | Hyprland, Niri, MangoWC, or any Wayland compositor (generic fallback) |
| Audio | services/audio.rs | PulseAudio | libpulse C library | PulseAudio or PipeWire-Pulse |
| Brightness | crates/ashell-services/src/brightness/ (iced glue in services/brightness.rs) | sysfs + logind | File I/O + D-Bus | systemd-logind |
| Bluetooth | crates/ashell-services/src/bluetooth/ (iced glue in services/bluetooth.rs) | BlueZ | D-Bus | bluez |
| Network | services/network/ | NetworkManager / IWD | D-Bus | networkmanager or iwd |
| MPRIS | services/mpris/ | Media players | D-Bus | MPRIS-compatible player |
| Tray | services/tray/ | StatusNotifierItem | D-Bus | — |
| UPower | crates/ashell-services/src/upower/ (iced glue in services/upower.rs) | UPower daemon | D-Bus | upower |
| Notifications | services/notifications/ | Notification server | D-Bus | — |
| Privacy | crates/ashell-services/src/privacy.rs (iced glue in services/privacy.rs) | PipeWire + /dev/video0 | PipeWire registry + inotify | pipewire |
| Idle Inhibitor | crates/ashell-services/src/idle_inhibitor.rs (iced glue in services/idle_inhibitor.rs) | Wayland idle-inhibit-unstable-v1 | Wayland protocol | — |
| Logind | crates/ashell-services/src/logind.rs (iced glue in services/logind.rs) | systemd-logind | D-Bus | systemd-logind |
| Throttle | crates/ashell-services/src/throttle.rs | (utility) | Stream adapter | — |
| XDG Icons | crates/ashell-services/src/xdg_icons.rs (iced glue in services/xdg_icons.rs) | (utility) | XDG icon theme | — |
Shared Icon Resolution
xdg_icons is a shared helper (not an event-producing service) used by the
tray and the workspaces module to turn an identifier into a displayable icon.
Given a name, the ashell-services crate resolves the path of an image or SVG
file via the XDG icon theme, then a .desktop index (by StartupWMClass and
file name), then a fuzzy/prefix match against the installed icon set.
Notifications use only the theme lookup, theme_icon_path.
It returns an IconFile, the path tagged as Image or Svg. The glue in
services/xdg_icons.rs turns it into an XdgIcon (Image, Svg, or a
NerdFont glyph fallback).
Each consumer keeps its own concern on top of this core: the tray handles raw
D-Bus pixmaps and looks names up in the item’s own IconThemePath first
(get_icon_from_theme_path, not cached, since apps rewrite those directories),
while the workspaces module lowercases the window class before lookup. Theme
lookups are memoized in a process-wide cache, and the underlying indexes are
built lazily; warm_cache_async pre-builds them off the UI thread when a
consumer is active.
Services vs. Modules
| Aspect | Module | Service |
|---|---|---|
| Has UI | Yes (view()) | No |
| Interacts with system | No (consumes services) | Yes |
Has Message type | Yes | Has UpdateEvent + ServiceEvent |
| Defined by | Convention | ReadOnlyService / Service trait |
| Runs on | Main thread (iced event loop) | Async (tokio) or dedicated thread |
Service Communication Pattern
Service (async/background)
│
▼ ServiceEvent<S>
Module subscription
│
▼ Module::Message
App::update()
│
▼ Service::command() (for bidirectional services)
Service (executes command, returns result)
Threading Model
- Main thread: iced event loop + rendering
- Tokio runtime: Most services (D-Bus watchers, timers, IPC)
- Dedicated OS thread: PulseAudio mainloop (libpulse requires its own event loop)
- Communication:
tokio::sync::mpscchannels between threads, icedchannel()for subscriptions