garbg
Wallpaper Daemon
A multi-source wallpaper daemon with intelligent caching, animated image support, and slideshow capabilities. Load backgrounds from local files, HTTP endpoints, GitHub repositories, or S3-compatible storage with automatic scaling and multi-monitor support.
Features
- Local files and directories with recursive scanning
- HTTP/HTTPS remote image fetching
- GitHub repository integration with API support
- S3-compatible cloud storage (AWS, MinIO)
- LRU disk cache with blake3 hashing
- Animated GIF, WebP, and APNG playback
- Optional video wallpapers via ffmpeg
- Five scaling modes: fill, fit, stretch, center, tile
- Per-monitor wallpaper configuration
- Slideshow mode with shuffle and intervals
- Double-buffered animation rendering
- Systemd user service integration
Supported Formats
* Video formats require the video feature (ffmpeg-next)
Quick Start Guide
Get up and running with garbg in just a few steps. This guide covers installation, basic usage, and essential commands.
1. Installation
Install garbg using the unified installer or build from source:
2. Set Your First Wallpaper
Set a wallpaper directly from the command line:
3. Start a Slideshow
Rotate through wallpapers from a directory:
4. Start the Daemon
For persistent wallpapers and advanced features, run the daemon:
5. Essential Commands
| Command | Description |
|---|---|
| garbg set <source> | Set wallpaper from any source |
| garbg next | Next wallpaper in playlist |
| garbg prev | Previous wallpaper |
| garbg pause | Pause animations/slideshow |
| garbg resume | Resume playback |
| garbg status | Show current status |
| garbg reload | Reload configuration |
| garbg list <source> | List images from source |
Configuration Reference
garbg uses TOML for configuration. The config file is located at ~/.config/garbg/config.toml.
Minimal Configuration
# Minimal garbg configuration
[general]
mode = "fill" # Scaling mode
[default]
source = "~/Pictures/Wallpapers"
[default.slideshow]
enabled = true
interval = "10m"
shuffle = true Full Configuration Example
# ═══════════════════════════════════════════
# garbg configuration
# ═══════════════════════════════════════════
[general]
mode = "fill" # Default scaling: fill, fit, stretch, center, tile
# ═══════════════════════════════════════════
# Animation Settings
# ═══════════════════════════════════════════
[animation]
enabled = true # Enable animated GIF/WebP/APNG playback
max_fps = 60 # Maximum frame rate (0 = unlimited)
pause_on_idle = true # Pause animations when screen locked
# ═══════════════════════════════════════════
# Cache Settings
# ═══════════════════════════════════════════
[cache]
directory = "" # Custom cache dir (default: ~/.cache/garbg)
max_size_mb = 1024 # Maximum cache size in MB
max_age_days = 30 # Delete cached items older than this
# ═══════════════════════════════════════════
# Default Wallpaper Source
# ═══════════════════════════════════════════
[default]
source = "~/Pictures/Wallpapers"
mode = "fill"
[default.slideshow]
enabled = true
interval = "10m" # Duration: "30s", "5m", "1h"
shuffle = true # Randomize order
# ═══════════════════════════════════════════
# Per-Monitor Configuration
# ═══════════════════════════════════════════
[[monitors]]
name = "DP-1"
source = "~/Pictures/primary-monitor"
mode = "fill"
[monitors.slideshow]
enabled = true
interval = "15m"
shuffle = true
[[monitors]]
name = "HDMI-1"
source = "~/Pictures/secondary-monitor"
mode = "fit"
# ═══════════════════════════════════════════
# Per-Workspace Configuration
# ═══════════════════════════════════════════
[[workspaces]]
id = 1
source = "~/Pictures/workspace1.png"
mode = "fill"
[[workspaces]]
id = 2
source = "github://username/repo/wallpapers"
mode = "fill"
# ═══════════════════════════════════════════
# Remote Source Examples
# ═══════════════════════════════════════════
# HTTP source (uncomment to use)
# [default]
# source = "https://example.com/wallpapers/"
# mode = "fill"
# GitHub source
# [default]
# source = "github://owner/repo/path/to/wallpapers"
# mode = "fill"
# S3 source (requires --features s3)
# [default]
# source = "s3://bucket-name/prefix"
# mode = "fill" Configuration Options Reference
| Option | Type | Default | Description |
|---|---|---|---|
| general.mode | string | fill | Default scaling mode |
| animation.enabled | bool | true | Enable animated playback |
| animation.max_fps | int | 60 | Max frame rate (0=unlimited) |
| animation.pause_on_idle | bool | true | Pause when screen locked |
| cache.directory | string | ~/.cache/garbg | Cache directory path |
| cache.max_size_mb | int | 1024 | Max cache size in MB |
| cache.max_age_days | int | 30 | Max age for cached items |
| default.source | string | "" | Default wallpaper source URI |
| slideshow.enabled | bool | false | Enable slideshow rotation |
| slideshow.interval | duration | 5m | Time between rotations |
| slideshow.shuffle | bool | true | Randomize playlist order |
Overview
garbg is a wallpaper daemon for X11 written in Rust. It supports multiple image sources, animated wallpapers, slideshow mode, and per-monitor configuration with an intelligent caching system.
Architecture
- Async Runtime: Tokio for non-blocking I/O and concurrent operations
- Image Processing: image crate for decoding, Lanczos3 for high-quality scaling
- X11 Backend: x11rb with RandR extension for multi-monitor support
- Caching: LRU disk cache with blake3 hashing and ETag support
- IPC: JSON over Unix domain sockets
File Locations
| ~/.config/garbg/config.toml | Configuration file |
| ~/.cache/garbg/ | Cache directory |
| ~/.cache/garbg/state.json | Playlist state file |
| ~/.cache/garbg/index.json | Cache index file |
| $XDG_RUNTIME_DIR/garbg.sock | IPC socket |
| $XDG_RUNTIME_DIR/garbg.pid | PID file (daemon mode) |
Wallpaper Sources
garbg supports multiple source types for loading wallpapers. Each source type has its own URI format.
| Source | URI Format |
|---|---|
| Local file | /path/to/image.png, ~/Pictures/bg.jpg |
| Local directory | ~/Pictures/Wallpapers |
| HTTP/HTTPS | https://example.com/image.png |
| HTTP directory | https://example.com/images/ |
| GitHub | github://owner/repo/path |
| S3 | s3://bucket/prefix |
Local Files
Load wallpapers from local filesystem paths. Supports single files and directories.
# Single file
garbg set ~/Pictures/wallpaper.png
garbg set /home/user/Pictures/bg.jpg
# Directory (lists all images)
garbg set ~/Pictures/Wallpapers
# With shuffle for directory
garbg set ~/Pictures/Wallpapers -r
# Shell expansion supported
garbg set ~/Pictures/*.png Directory Behavior
- Recursively scans subdirectories
- Filters by supported image extensions
- Sorted alphabetically by default
- Use
-rflag to shuffle
HTTP/HTTPS Sources
Fetch wallpapers from remote HTTP/HTTPS URLs. Supports direct image URLs and directory indexes.
# Direct image URL
garbg set https://example.com/wallpaper.png
# Apache/nginx directory index
garbg set https://example.com/wallpapers/
# With slideshow
garbg set https://example.com/wallpapers/ -r --interval 10m Features
- Automatic caching with ETag support
- Directory index parsing (Apache/nginx autoindex)
- User-Agent:
garbg/0.1 - Follows redirects
Tip: Remote images are cached locally. Clear the cache with rm -rf ~/.cache/garbg/* if images seem stale.
GitHub Sources
Load wallpapers directly from GitHub repositories using the GitHub API.
# GitHub URI format
garbg set github://owner/repo/path/to/wallpapers
# Single file
garbg set github://username/dotfiles/wallpapers/bg.png
# Directory listing
garbg set github://awesome-wallpapers/collection/nature -r
# Web URL is auto-converted
garbg set https://github.com/owner/repo/tree/main/wallpapers Rate Limiting
GitHub API has rate limits for unauthenticated requests. Set a personal access token for higher limits:
S3 Storage
Load wallpapers from S3-compatible storage (AWS S3, MinIO, etc.). Requires the s3 feature.
# Build with S3 support
cargo build --release --features s3
# S3 URI format
garbg set s3://bucket-name/prefix/
# Custom endpoint (MinIO, etc.)
garbg set s3://custom-endpoint.com/bucket/prefix Authentication
Configure credentials via standard AWS SDK environment variables:
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_REGION="us-east-1"
# Or use AWS profiles
export AWS_PROFILE="my-profile" Scaling Modes
Five scaling modes are available for fitting images to your screen.
| Mode | Behavior |
|---|---|
| fill | Scale to cover entire screen, crop excess (default) |
| fit | Scale to fit within screen, letterbox if needed |
| stretch | Stretch to exact screen size (ignores aspect ratio) |
| center | Display at original size, centered (no scaling) |
| tile | Tile image to fill screen (no scaling) |
# Command line usage
garbg set ~/bg.png -m fill
garbg set ~/bg.png -m fit
garbg set ~/bg.png --mode stretch
garbg set ~/bg.png --span # Span across all monitors
# Per-monitor via CLI
garbg set ~/bg.png -o DP-1 -m fit
garbg set ~/bg2.png -o HDMI-1 -m fill
# Config file
[general]
mode = "fill"
# Per-monitor override
[[monitors]]
name = "DP-1"
mode = "fit" Animation
garbg supports animated wallpapers using GIF, WebP, and APNG formats, with optional video support.
Animation Features
- Double-buffered rendering for smooth playback
- Pre-scaled frames cached in memory
- Configurable max FPS cap
- Adaptive frame skipping when system falls behind
- Pause on idle/lock support
# Play animated wallpaper
garbg set ~/animated.gif --animate
garbg set ~/animated.webp -a
# With FPS limit
garbg set ~/animated.gif --animate --max-fps 30
# Config settings
[animation]
enabled = true
max_fps = 60
pause_on_idle = true Animated GIF
Full support for animated GIF playback with proper frame timing.
- Frame timing extracted from GIF metadata
- Zero-delay frames default to 100ms (10 FPS)
- Infinite looping support
- Transparency handling
Animated WebP
Support for animated WebP images with automatic animation detection.
- Automatic detection of animated vs static WebP
- Frame timing from WebP metadata
- Better compression than GIF
Video Support
Optional video wallpaper support via ffmpeg. Requires building with the video feature.
# Build with video support (default)
cargo build --release
# Build without video support
cargo build --release --no-default-features
# Supported codecs
# - H.264
# - VP9
# - VP8
# - AV1 Supported Containers
- MP4 (H.264 codec)
- WebM (VP9, VP8)
- MKV (Matroska)
- AVI
Note: Audio is always muted for video wallpapers.
Slideshow Mode
Automatically rotate through wallpapers at configurable intervals.
# Command line slideshow
garbg set ~/Pictures -r --interval 5m
garbg set ~/Pictures --interval 30s --random
# Duration format (humantime)
# "30s" - 30 seconds
# "5m" - 5 minutes
# "1h" - 1 hour
# "1h30m" - 1 hour 30 minutes
# Config file
[default.slideshow]
enabled = true
interval = "10m"
shuffle = true Slideshow Controls
Shuffle Behavior
- Images shuffled when playlist created with
-rflag - Re-shuffle applied on wrap-around (after last image)
- Playlist state persists across daemon restarts
Multi-Monitor
Configure different wallpapers for each monitor using RandR monitor names.
# Set wallpaper for specific monitor
garbg set-monitor DP-1 ~/bg1.png
garbg set-monitor HDMI-1 ~/bg2.png -m fit
# Query monitors
garbg query monitors
# Config file per-monitor
[[monitors]]
name = "DP-1"
source = "~/Pictures/primary"
mode = "fill"
[monitors.slideshow]
enabled = true
interval = "15m"
[[monitors]]
name = "HDMI-1"
source = "~/Pictures/secondary"
mode = "fit" Finding Monitor Names
Caching System
garbg uses an intelligent LRU disk cache for remote images with blake3 hashing.
Cache Features
- LRU eviction when size limit exceeded
- blake3 hashing of URIs for cache keys
- Subdirectory sharding for performance
- ETag support for conditional HTTP requests
- Automatic expiry based on max_age_days
# Cache configuration
[cache]
directory = "~/.cache/garbg" # Default location
max_size_mb = 1024 # 1 GB max
max_age_days = 30 # Expire after 30 days Cache Management
Daemon Mode
Run garbg as a daemon for persistent wallpapers and advanced features.
Daemon Features
- Persistent playlist state across restarts
- IPC command handling
- Per-monitor wallpapers
- Animation playback
- Slideshow with auto-rotation
- Event subscription system
- PID file management
# Start daemon
garbg daemon # Foreground
garbg daemon -d # Daemonize (background)
garbg daemon -c /path/config # Custom config path
# Signal handling
# SIGHUP → Reload configuration
# SIGTERM → Graceful shutdown
# SIGINT → Graceful shutdown Systemd Service
[Unit]
Description=garbg wallpaper daemon
After=graphical-session.target
PartOf=graphical-session.target
[Service]
Type=simple
ExecStart=/usr/local/bin/garbg daemon
Restart=on-failure
RestartSec=3
[Install]
WantedBy=graphical-session.target Common Workflows
Practical examples of using garbg with gar and other gardesk components.
Startup with gar
Start garbg automatically when gar launches:
-- Start garbg daemon on session startup
gar.exec_once("garbg daemon")
-- Set initial wallpaper
gar.exec_once("garbg set ~/Pictures/Wallpapers -r --interval 15m") Keybindings for Wallpaper Control
-- Wallpaper navigation
gar.bind("mod+bracketright", function()
gar.exec("garbg next")
end)
gar.bind("mod+bracketleft", function()
gar.exec("garbg prev")
end)
-- Random wallpaper
gar.bind("mod+shift+w", function()
gar.exec("garbg random")
end)
-- Pause/resume slideshow
gar.bind("mod+ctrl+w", function()
gar.exec("garbg toggle")
end) Per-Workspace Wallpapers
Configure different wallpapers for each workspace:
[[workspaces]]
id = 1
source = "~/Pictures/work.png"
mode = "fill"
[[workspaces]]
id = 2
source = "~/Pictures/browser.png"
mode = "fill"
[[workspaces]]
id = 9
source = "~/Pictures/music.png"
mode = "fill" Note: Per-workspace wallpapers require the gar window manager to be running. garbg connects to gar's IPC socket to receive workspace change events via EWMH properties.
GitHub Wallpaper Collection
Use a GitHub repository as your wallpaper source:
Multi-Monitor Different Slideshows
# Primary monitor - landscape photos
[[monitors]]
name = "DP-1"
source = "~/Pictures/landscapes"
mode = "fill"
[monitors.slideshow]
enabled = true
interval = "10m"
shuffle = true
# Secondary monitor - static wallpaper
[[monitors]]
name = "HDMI-1"
source = "~/Pictures/secondary-static.png"
mode = "fit" Time-Based Wallpapers
Use cron to change wallpapers based on time of day:
# Morning wallpaper (6 AM)
0 6 * * * DISPLAY=:0 garbg set ~/Pictures/morning.png
# Afternoon wallpaper (12 PM)
0 12 * * * DISPLAY=:0 garbg set ~/Pictures/afternoon.png
# Evening wallpaper (6 PM)
0 18 * * * DISPLAY=:0 garbg set ~/Pictures/evening.png
# Night wallpaper (10 PM)
0 22 * * * DISPLAY=:0 garbg set ~/Pictures/night.png Animated Desktop
Set an animated GIF or WebP as your wallpaper:
IPC Protocol
garbg exposes a Unix domain socket for inter-process communication. Use CLI commands or send JSON directly.
Socket Location
Command Reference
| Command | Description |
|---|---|
| Set | Set wallpaper from source |
| SetWorkspace | Set wallpaper for specific workspace |
| SetMonitor | Set wallpaper for specific monitor |
| Next | Advance to next wallpaper |
| Prev | Go to previous wallpaper |
| Random | Jump to random wallpaper |
| Reload | Reload configuration |
| Pause | Pause animations/slideshow |
| Resume | Resume playback |
| Toggle | Toggle pause state |
| Status | Get current status |
| List | List images from source |
| ClearCache | Clear disk cache |
| QueryMonitors | Query connected monitors |
| QueryCurrent | Query current wallpaper info |
| Subscribe | Subscribe to events |
| Unsubscribe | Unsubscribe from events |
JSON Protocol
Send JSON objects over the socket for scripting:
// Set wallpaper
{"Set": {"source": "~/Pictures/bg.png", "mode": "Fill", "shuffle": false, "animate": false, "max_fps": 60}}
// Navigate playlist
{"Next": {"monitor": null}}
{"Prev": {"monitor": null}}
// Control playback
{"Pause": null}
{"Resume": null}
{"Toggle": null}
// Query state
{"Status": null}
{"QueryMonitors": null}
{"QueryCurrent": null}
// List source
{"List": {"source": "~/Pictures"}} // Success
{"success": true, "data": null}
// Success with data
{"success": true, "data": {
"source": "~/Pictures",
"current_index": 5,
"total": 42,
"paused": false
}}
// Error
{"success": false, "error": "Daemon not running"} Event Types
| Event | Description |
|---|---|
| WallpaperChanged | Wallpaper changed on a monitor |
| SourceUpdated | Source playlist updated |
| AnimationState | Animation paused/resumed |
| SlideshowAdvanced | Slideshow moved to next image |
| Error | Error occurred |
Scripting Example
#!/bin/bash
# Get current wallpaper info
SOCK="${XDG_RUNTIME_DIR:-/tmp}/garbg.sock"
echo '{"QueryCurrent": null}' | nc -U "$SOCK" | jq -r '.data.source' Troubleshooting
Wallpaper not appearing
Verify DISPLAY is set and X11 is running:
Daemon not running
Check if daemon is running and socket exists:
Images not loading from remote source
Check network and cache:
GitHub rate limited
Set a personal access token for higher limits:
Create a token at github.com/settings/tokens (no scopes needed for public repos).
Animation stuttering
Reduce FPS or check system resources:
Try smaller GIFs or reduce screen resolution for better performance.
Video wallpapers not working
Ensure garbg was built with video support:
Configuration not loading
Validate TOML syntax:
Multi-monitor not working
Check monitor names match exactly:
Monitor names in config must match xrandr output exactly (e.g., "DP-1", "HDMI-1").
Enable debug logging
Get detailed output for debugging: