Skip to content

Events & SSE

Everything that happens in the daemon — wallpaper changes, playlist activity, imports, config edits — is published on an internal event bus and streamed to clients over Server-Sent Events at GET /events. Subscribe once, react forever; no polling.

Implementation: daemon/internal/server/sse.go (broker) and daemon/internal/events/types.go (event types).


Connecting

bash
# Everything
curl -N --unix-socket "${XDG_RUNTIME_DIR}/waypaper-engine.sock" http://localhost/events

# Only what you care about
curl -N --unix-socket "${XDG_RUNTIME_DIR}/waypaper-engine.sock" \
  "http://localhost/events?types=wallpaper_changed,playlist_started"

Or skip curl entirely — the CLI wraps the stream and prints each event as a JSON line, which pipes nicely into jq:

bash
waypaper-daemon events
waypaper-daemon events --types wallpaper_changed,playlist_started

Filtering: ?types= takes a comma-separated list of event types. Omit it (or pass *) to receive everything.


Wire format

Standard SSE: an event: line with the type, a data: line with a JSON payload, blank-line separated. Every payload includes a timestamp field (injected by the broker).

event: wallpaper_changed
data: {"monitor":"DP-1", ..., "timestamp":"2026-07-09T23:00:00Z"}

: keepalive

NOTE

The : keepalive comment is sent every 30 seconds so dead connections get detected. SSE-aware clients ignore comment lines automatically; if you parse by hand, skip lines starting with :.


Event types

From daemon/internal/events/types.go — this table tracks the code, not the other way around.

Wallpaper

TypeWhen
wallpaper_changedA wallpaper was applied on any monitor (manual, random, or playlist).
wallpaper_apply_failedA backend failed to apply a wallpaper.
wallpaper_restore_failedOne or more monitors could not restore their persisted wallpaper on daemon startup.

Playlists

TypeWhen
playlist_startedA playlist began running.
playlist_stoppedA playlist stopped.
playlist_pausedA playlist was paused.
playlist_resumedA paused playlist resumed.
playlist_image_changedA running playlist advanced to another image.
playlist_skipped_incompatibleItems incompatible with the active backend were skipped.
playlist_no_compatible_itemThe whole playlist was exhausted with nothing the active backend can display.

Import & processing

Emitted during batch image import.

TypeWhen
processing_startedA batch import began.
image_processedOne image finished processing (thumbnails, palette, ...).
image_errorOne image failed to process.
processing_completeThe batch finished.
processing_cancelledThe batch was cancelled.
TypeWhen
monitor_connectedAn output appeared.
monitor_disconnectedAn output went away.
config_changedConfig was updated (any writer: UI, CLI, PATCH /config).
gallery_changedAny gallery collection changed. The payload's domain field says which: images, folders, playlists, or history. Treat it as a "re-fetch that collection" signal.
image_orphan_purgedAll database references to a deleted image were removed.

Backend lifecycle

TypeWhen
backend_unavailableA long-lived renderer backend (e.g. wal-qt) could not be reached after retries.

Recipes

React to every wallpaper change (e.g. re-theme your terminal):

bash
waypaper-daemon events --types wallpaper_changed | while read -r line; do
  echo "wallpaper changed: $line"
  # your pywal/matugen/whatever hook here
done

NOTE

The daemon binds a Unix socket, not TCP — a browser EventSource can't reach it directly. Use curl -N --unix-socket, the CLI, or any HTTP client that speaks Unix sockets.

Exact payload shapes per event live in the API contract.

Released under the project license. Docs track tagged releases on GitHub Pages.