The Service Layer
Quickshell provides built-in services accessible as QML imports. Each service is a C++ class registered with the QML engine. Services are singletons — one instance shared across all QML files.
Service Architecture
graph TD
subgraph "Your QML Components"
MPW[MprisWidget]
UPW[BatteryWidget]
NT[NotificationPopup]
ST[SystemTray]
PW[VolumeSlider]
end
subgraph "Quickshell Service Layer"
MP[Mpris<br/>MprisWatcher + Players]
UP[UPower<br/>display device + devices]
NT2[Notifications<br/>Server + Notification]
SNI[StatusNotifier<br/>SystemTray + Items]
PW2[PipeWire<br/>Core + Devices + Nodes]
PK[PolKit<br/>Authentication Agent]
end
subgraph "Data Sources"
DB[D-Bus System / Session Bus]
PWPROTO[PipeWire<br/>Protocol]
end
MPW --> MP
UPW --> UP
NT --> NT2
ST --> SNI
PW --> PW2
MP --> DB
UP --> DB
NT2 --> DB
SNI --> DB
PK --> DB
PW2 --> PWPROTOMpris — Media Player Control
Directory: src/services/mpris/
The MPRIS service communicates with media players via D-Bus. It consists of two main classes:
- MprisWatcher (
watcher.hpp/cpp) — discovers and tracks D-Bus names matchingorg.mpris.MediaPlayer2.* - MprisPlayer (
player.hpp/cpp) — represents a single player, exposes metadata and playback state
The QML entry point is Mpris (a QML_SINGLETON), which exposes an ObjectModel<MprisPlayer> via the players property.
Registration pattern (from watcher.hpp):
class MprisQml: public QObject {
Q_OBJECT;
QML_NAMED_ELEMENT(Mpris);
QML_SINGLETON;
Q_PROPERTY(UntypedObjectModel* players READ players CONSTANT);
};
// QML usage:
// import Quickshell.Services.Mpris
// Mpris.players[0].titleUPower — Power Devices
Directory: src/services/upower/
Communicates with the org.freedesktop.UPower D-Bus service to monitor batteries and power sources:
- UPower (
core.hpp/cpp) — main singleton accessing the UPower daemon - UPowerDevice (
device.hpp/cpp) — individual battery or power supply - PowerProfiles (
powerprofiles.hpp/cpp) — power profile management
Exposes displayDevice (the primary battery), devices (all devices via ObjectModel), and onBattery (boolean power source indicator).
class UPower: public QObject {
Q_OBJECT;
public:
UPowerDevice* displayDevice();
ObjectModel<UPowerDevice>* devices();
QBindable<bool> bindableOnBattery() const;
};Notifications — Desktop Notifications
Directory: src/services/notifications/
Implements the org.freedesktop.Notifications D-Bus specification:
- NotificationServer (
server.hpp/cpp) — D-Bus object that receives notification requests - Notification (
notification.hpp/cpp) — data class with title, body, urgency, actions, etc. - DBusImage (
dbusimage.hpp/cpp) — image data (icon) handling from D-Bus
StatusNotifier — System Tray
Directory: src/services/status_notifier/
Implements the KDE StatusNotifierItem protocol (system tray):
- StatusNotifierHost (
host.hpp/cpp) — registers as the watcher on D-Bus - StatusNotifierItem (
item.hpp/cpp) — individual tray item with icon, menu, tooltip - SystemTray QML singleton (
qml.hpp/cpp) — exposes items as anObjectModel
// host.hpp
class StatusNotifierHost: public QObject {
Q_OBJECT;
public:
QList<StatusNotifierItem*> items() const;
static StatusNotifierHost* instance();
signals:
void itemReady(StatusNotifierItem* item);
void itemUnregistered(StatusNotifierItem* item);
};PipeWire — Audio Devices
Directory: src/services/pipewire/
Manages audio devices and streams via the PipeWire protocol:
- PipeWireCore (
core.hpp/cpp) — main connection to the PipeWire daemon - PWDevice (
device.hpp/cpp) — audio device (sink/source) - PWNode (
node.hpp/cpp) — audio node/port - PWLink (
link.hpp/cpp) — audio route/link - PWPeak (
peak.hpp/cpp) — audio peak detection
This is the most complex service, requiring direct protocol communication with PipeWire.
PolKit — Authentication Agent
Directory: src/services/polkit/
Implements a PolicyKit authentication agent:
- AgentImpl (
agentimpl.hpp/cpp) — D-Bus listener for auth requests - Session (
session.hpp/cpp) — handles individual authentication sessions - Identity (
identity.hpp/cpp) — user identity representation
PAM and Greetd
Directories: src/services/pam/, src/services/greetd/
- PAM — provides authentication conversations via PAM modules; uses a helper subprocess for privilege separation
- Greetd — connects to the greetd login daemon for session management
Adding a New Built-in Service
To add a new service to Quickshell's codebase:
- Create
src/services/yourservice/with your.hpp,.cpp,qml.hpp,qml.cppfiles - Define a QObject subclass with
Q_PROPERTYfor exposed data - Create a QML singleton adapter (like
MprisQml) usingQML_NAMED_ELEMENT+QML_SINGLETON - Wire up instance access via a static
instance()method on the service class - Add to
src/services/CMakeLists.txtand implement the service plugin
Registration pattern (modern, with QML_ELEMENT):
class YourServiceQml: public QObject {
Q_OBJECT;
QML_NAMED_ELEMENT(YourService);
QML_SINGLETON;
public:
// Expose data via Q_PROPERTY or Q_INVOKABLE methods
};
// QML usage:
// import Quickshell.Services.YourService
// YourService.somePropertyThe service module must be added to the build system via CMake's add_subdirectory() in src/services/CMakeLists.txt.
Exercises
- Services are D-Bus or PipeWire-based; most are event-driven, not polled
- Each service has a C++ backend plus a QML singleton adapter (e.g. MprisQml)
- ObjectModel<T> is the standard pattern for exposing lists of items to QML
- Adding a new service requires a module directory, QML_ELEMENT registration, and CMake integration