Systemd Service (Development Documentation)
Overview of gSlapper's systemd service integration for wallpaper restoration on login.
Overview
gSlapper includes systemd service integration for automatic wallpaper restoration on login. This is optional - gSlapper works perfectly fine without systemd.
Implementation Details
Architecture
Two-Component Design:
- Main Program (
gslapperbinary) - Runs wallpaper display - Helper Process (
gslapper-holder) - Gatekeeper for stoplist checking
Why Helper Process?
- Separates stoplist monitoring from main event loop
- Allows graceful lifecycle transitions
- Manages process restarts (like mpvpaper's approach)
Service Modes
User Service Mode (--systemd)
Behavior:
- Sends
sd_notify(READY=1)when wallpaper is displayed - Saves state on
SIGHUP(reload signal) - Exits cleanly on
SIGTERM(systemd shutdown)
Activation:
#ifdef HAVE_SYSTEMD
#include <systemd/sd-daemon.h>
// Notify systemd when ready
sd_notify(0, "READY=1\nSTATUS=Wallpapers loaded and playing");
// Notify systemd on shutdown
sd_notify(0, "STOPPING=1\nSTATUS=Shutting down");
#endifManual Mode (default)
Behavior:
- Runs until
SIGINT(Ctrl+C) orSIGTERM - Saves state on exit (if not disabled with
--no-save-state) - No systemd notifications
State Management in Systemd Service
State Saving Triggers
- Automatic on Exit: When service stops (SIGTERM, SIGHUP)
- Explicit Save: Via IPC
save-statecommand or--save-stateflag - SIGHUP Reload: Service reload triggers state save + restart
State File Format
Location: ~/.local/state/gslapper/state-<output>.txt
Format (Simple key=value, not JSON):
version=1
output=DP-1
path=/home/user/Videos/wallpaper.mp4
is_image=false
options=loop panscan=0.8
position=123.45
paused=0State File Operations
// From state.c
char *get_state_file_path(const char *output_name);
int save_state_file(const char *path, const struct wallpaper_state *state);
int load_state_file(const char *path, struct wallpaper_state *state);
void free_wallpaper_state(struct wallpaper_state *state);Safety Features:
- Atomic writes: Write to
.tmpfile, then rename - File locking:
flock()prevents concurrent writes - Permissions: State files set to
0600(user-only) - Backups: Automatic backup before overwriting
Service File Configuration
Single Service (All Monitors)
File: /usr/lib/systemd/user/gslapper.service
[Unit]
Description=gSlapper Wallpaper Service
Documentation=https://nomadcxx.github.io/gSlapper/
After=graphical-session.target
Wants=graphical-session.target
[Service]
Type=notify
ExecStart=/usr/bin/gslapper --systemd --restore '*'
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
EnvironmentFile=%h/.config/gslapper/environment
Environment=XDG_RUNTIME_DIR=%t
MemoryMax=512M
CPUQuota=50%
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=default.targetKey Directives:
Type=notify- Waits forsd_notify(READY=1)before considering service startedExecStart- Uses--systemd --restoreflagsExecReload- SendsSIGHUPfor state save + restartEnvironmentFile- LoadsWAYLAND_DISPLAYfrom user configEnvironment=XDG_RUNTIME_DIR=%t- Sets Wayland runtime directoryMemoryMax,CPUQuota- Resource limits for safety
Per-Monitor Template
File: /usr/lib/systemd/user/gslapper@.service
[Unit]
Description=gSlapper Wallpaper Service for %i
Documentation=https://nomadcxx.github.io/gSlapper/
After=graphical-session.target
Wants=graphical-session.target
[Service]
Type=notify
ExecStart=/usr/bin/gslapper --systemd --restore %i
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
EnvironmentFile=%h/.config/gslapper/environment
Environment=XDG_RUNTIME_DIR=%t
MemoryMax=512M
CPUQuota=50%
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=default.targetUsage:
# Enable per monitor
systemctl --user enable --now gslapper@DP-1.service
systemctl --user enable --now gslapper@DP-2.service
# Each instance has separate state file:
# ~/.local/state/gslapper/state-DP-1.txt
# ~/.local/state/gslapper/state-DP-2.txtBuild System Integration
Optional systemd Dependency
meson.build:
# Optional systemd support
systemd_dep = dependency('libsystemd', required: false)
if systemd_dep.found()
add_project_arguments('-DHAVE_SYSTEMD', language: 'c')
message('Systemd support enabled')
else
message('Systemd support disabled (libsystemd not found)')
endifCompilation Flags:
HAVE_SYSTEMD- Defined when libsystemd is found- Code wraps systemd calls in
#ifdef HAVE_SYSTEMD
Service File Installation
PKGBUILD:
package() {
# ... existing install commands ...
# Install systemd user service files
install -Dm644 gslapper.service \
"${pkgdir}/usr/lib/systemd/user/gslapper.service"
install -Dm644 gslapper@.service \
"${pkgdir}/usr/lib/systemd/user/gslapper@.service"
}Environment Variables
Required Environment
WAYLAND_DISPLAY (Required):
- Wayland display socket (e.g.,
wayland-0,wayland-1) - Must be set for gSlapper to connect to compositor
Configuration:
# Create environment file
mkdir -p ~/.config/gslapper
echo "WAYLAND_DISPLAY=$WAYLAND_DISPLAY" > ~/.config/gslapper/environmentOptional Environment
XDG_RUNTIME_DIR (Automatically set by systemd):
- User runtime directory (e.g.,
/run/user/1000) - Used for Wayland socket access
- Set automatically by systemd service (
Environment=XDG_RUNTIME_DIR=%t)
XDG_STATE_HOME (Optional):
- Override default state directory
- If set:
$XDG_STATE_HOME/gslapper/ - If not set:
$HOME/.local/state/gslapper/
Service Lifecycle
Startup Sequence
- Service Start (systemd)
- Load Environment - Read
~/.config/gslapper/environment - Load State - Read from
~/.local/state/gslapper/state-*.txt - Initialize Wayland - Connect to compositor
- Initialize GStreamer - Set up pipeline for video/image
- Display Wallpaper - Render to layer surface
- Notify Ready -
sd_notify(READY=1) - Service Active (systemd considers service started)
Reload Sequence (SIGHUP)
- Receive Signal - Systemd sends
SIGHUP - Save Current State - Write position, pause state, options
- Stop GStreamer - Clean shutdown of pipeline
- Reload State - Load saved state from file
- Restart Pipeline - Initialize GStreamer with saved config
- Resume Playback - Continue from saved position
- Service Active (systemd continues service)
Shutdown Sequence (SIGTERM)
- Receive Signal - Systemd sends
SIGTERM - Notify Stopping -
sd_notify(STOPPING=1) - Save Current State - Write final state
- Stop GStreamer - Clean shutdown
- Cleanup Wayland - Destroy surfaces, close display
- Exit - Process terminates
- Service Stopped (systemd marks service as stopped)
Multi-Service Deployment
Single Service (Same Wallpaper All Monitors)
When to use:
- Same wallpaper on all monitors
- Simplified setup
- Single state file
Configuration:
# Enable single service
systemctl --user enable --now gslapper.service
# State file:
# ~/.local/state/gslapper/state.txt (for '*' output)Multiple Services (Different Wallpaper Per Monitor)
When to use:
- Different wallpapers on each monitor
- Independent control per monitor
- Per-monitor state management
Configuration:
# Disable single service if running
systemctl --user disable gslapper.service
# Enable per-monitor services
systemctl --user enable --now gslapper@DP-1.service
systemctl --user enable --now gslapper@DP-2.service
systemctl --user enable --now gslapper@DP-3.service
# Each has its own state file:
# ~/.local/state/gslapper/state-DP-1.txt
# ~/.local/state/gslapper/state-DP-2.txt
# ~/.local/state/gslapper/state-DP-3.txtState Files:
- Each instance reads/writes its own state file
- No conflicts between instances
- Independent video positions per monitor
Troubleshooting (Development)
Service Fails to Start
Check logs:
journalctl --user -u gslapper.service -n 50Common issues:
-
Missing
WAYLAND_DISPLAY:Error: Unable to connect to compositorFix: Verify
~/.config/gslapper/environmentcontains correct value -
No state file (when using
--restore):Warning: State file not found, starting freshFix: Not an error, service will start with no wallpaper
-
File not found (path in state file):
Error: File does not exist: /path/to/wallpaper.mp4Fix: Update wallpaper path or fix state file
Service Starts But No Wallpaper
Debug steps:
# Check service status
systemctl --user status gslapper.service
# View full logs
journalctl --user -u gslapper.service -f
# Check state file
cat ~/.local/state/gslapper/state-*.txt
# Verify file exists
test -f /path/to/wallpaper.mp4 && echo "OK" || echo "Missing"State Not Persisting
Check:
# Verify state directory exists and is writable
ls -la ~/.local/state/gslapper/
# Check state file permissions
stat ~/.local/state/gslapper/state-*.txt
# Manual test
gslapper --save-state
# Should save to state filesystemd Support Disabled
If building without libsystemd:
Systemd support disabled (libsystemd not found)Result:
--systemdflag still works but nosd_notify()calls- Service will still work but
Type=notifywon't wait for READY - Consider using
Type=simpleinstead
Comparison with swww
swww-daemon Architecture
Single Process:
swww-daemonruns continuously- Manages all outputs in one process
- Automatic cache restoration on startup
- No explicit state file (uses shared memory)
Service File:
[Service]
Type=simple
ExecStart=/usr/bin/swww-daemon
Restart=on-failuregSlapper Architecture
One Process Per Wallpaper (or One Process for All):
- Each service instance manages one output
- Explicit state file persistence
- State restoration via
--restoreflag - More detailed state (video position, pause state, options)
Service File:
[Service]
Type=notify
ExecStart=/usr/bin/gslapper --systemd --restore <output>
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failureKey Differences
| Aspect | swww | gSlapper |
|---|---|---|
| Process Model | Single daemon | One process per wallpaper (optional) |
| State Storage | In-memory cache | File-based (text) |
| Restoration | Automatic on daemon start | Explicit --restore flag |
| Systemd Type | simple | notify (wait for ready) |
| Reload Support | No | Yes (SIGHUP) |
| State Detail | Cache of images | Full config + video position |
Future Enhancements
Planned (tracked in GitHub issues):
- Playlist Support - Rotate through multiple wallpapers
- Scheduled Wallpapers - Change based on time of day
- State Encryption - Optional encryption for sensitive paths
- Multiple State Profiles - Switch between wallpaper configurations
See Also
- Systemd Service Setup (User Guide) - End-user setup guide
- State Management (Implementation) - State file API
- API Reference - Full API documentation
- Architecture - Overall system architecture
- GitHub Issues - Future enhancements
