Sweets

IPC

Inspect and control Sweets through its typed, owner-only IPC.

Sweets exposes a bounded, versioned control socket for querying state, dispatching typed actions, and subscribing to state-change notifications. Use the integrated sweets msg client; it exits before compositor initialization.

Quick start

sweets msg version
sweets msg outputs
sweets msg output DP-1
sweets msg workspaces
sweets msg workspace 2 DP-1
sweets msg windows
sweets msg window 42
sweets msg layers
sweets msg batch --window 42 --input event7 --frame DP-1 --workspace-at 2 DP-1
sweets msg replay-events 37 workspace window
sweets msg resume-events 37 workspace window
sweets msg input event7
sweets msg frame DP-1
sweets msg status
sweets msg --json inputs

Without --json, successful values are printed as readable indented JSON. With --json, Sweets prints the compact response envelope, including its version, request ID, and typed outcome. Server errors are printed to stderr and return a non-zero exit status.

Run sweets msg --help for the command list accepted by the installed binary. The version query also reports the running compositor's query, action, event, and stream-mode capabilities.

Discovery and trust

For WAYLAND_DISPLAY=wayland-2, the compositor listens on:

$XDG_RUNTIME_DIR/sweets-wayland-2.sock

Sweets exports the absolute socket path as SWEETS_SOCKET to launched children and the activation environment. The client uses that value first and otherwise derives the standard path from XDG_RUNTIME_DIR and WAYLAND_DISPLAY.

IPC is an owner-only administration interface, not a sandbox boundary. A local process running as the compositor user can inspect window metadata and request every advertised action.

Before publishing IPC, Sweets verifies that the runtime directory is absolute, real, owned by the compositor user, and inaccessible to group and other users. The socket is mode 0600, and Linux peer credentials must match the compositor's effective UID. An unsafe runtime directory or mismatched peer is rejected. Startup continues if IPC cannot be established.

Queries

CommandResult
versioncompositor and IPC versions, capabilities, frame, replay, and batch limits
outputsconnector identity, modes, geometry, power, scale, transform, VRR, and gamma state
output OUTPUT_IDone output in the same snapshot shape
workspacesnumbered workspace instances, output, active state, layout, and master position
workspace NUMBER [OUTPUT_ID]one enabled numbered workspace in the same snapshot shape
batch SELECTOR ...ordered window/output/workspace/input/frame snapshots, typed per-item outcomes, and an event sequence boundary
replay-events SEQUENCE all|FILTER [FILTER ...]bounded retained events newer than a global sequence, or typed too_old
special-workspaceprivate-workspace visibility, host output, and window IDs
windowsmapped window identity, workspace/output, focus, state, and urgency
window WINDOW_IDone mapped window in the same snapshot shape
window-rule WINDOW_IDimmutable resolved opening rule and diagnostics for one mapped window
layerslive layer-shell identity, output/geometry, keyboard policy, and resolved opacity/blur state including an optional alpha threshold
inputstyped libinput devices, capabilities, settings, and switches
input INPUT_IDone input device in the same snapshot shape
framesper-output frame clock and presentation counters
frame OUTPUT_IDone output frame clock in the same snapshot shape
configpath, source, generation, reload state, and last error
statuslock, backend, rendering, and explicit-sync health
xwaylandXWayland lifecycle, retry health, display, and window counts

Workspace state is directly suitable for bars and scripts:

{
  "id": 2,
  "output": "DP-1",
  "active": true,
  "layout": "grid",
  "master_position": "left"
}

In per_monitor workspace mode, the same number may appear once per output; the output field distinguishes those independent instances. Use that exact, case-sensitive ID with workspace NUMBER OUTPUT_ID. An unqualified duplicate number returns ambiguous. Missing targets return not_found. The private special workspace is intentionally separate from numbered workspaces.

Titles, application IDs, connector names, and other strings are bounded. Treat window metadata as potentially sensitive when forwarding IPC output elsewhere. Singular queries avoid collecting full output, workspace, window, input, or frame lists. Input and output IDs are exact and case-sensitive, and window IDs are stable for the mapped lifetime. Unknown, removed, disconnected, or stale targets return not_found.

sweets msg layers is the layer-rule troubleshooting view. It lists live root surfaces in stable-ID order and reports their exact namespace and current background, bottom, top, or overlay layer. The snapshot distinguishes the requested output from the currently resolved output, includes arranged global geometry and keyboard interactivity, and exposes resolved appearance: opacity, inherit/force/veto blur policy, effective blur mode, rule-mode override, global blur enablement, retained client blur demand, and current effect demand. Effect demand describes compositor policy, not whether a renderer allocation later succeeded. Independent XDG popups are omitted.

Use one bounded batch when a panel needs several unrelated singular snapshots:

sweets msg batch --window 42 --output DP-1 --input event7 --frame DP-1 --workspace 2

Selectors are fixed-arity flags: --window WINDOW_ID, --output OUTPUT_ID, --input INPUT_ID, --frame OUTPUT_ID, --workspace NUMBER, and --workspace-at NUMBER OUTPUT_ID. Results preserve the requested order, echo the selector, and carry their own typed success or error. A stale window, removed input, unknown output, or ambiguous unqualified workspace does not discard successful siblings. Duplicates are preserved for deterministic correlation. Every frame item in one batch uses one shared monotonic-time sample. The outer result includes the global event sequence synchronized immediately before the items are resolved.

For race-free refresh, establish a subscription first, then issue the batch on a second connection. Install the batch at its returned sequence. Buffered events through that value are covered only for state the batch fully refreshed; other events still require their normal query. Reject or retry a batch if you already applied a newer event. Changes after the batch receive larger sequences. Without an active subscriber, the value is only the current event position, not a continuously sampled mutation counter.

Use atomic resume when a panel reconnects or detects a sequence gap. Supply the last global sequence the panel applied:

sweets msg resume-events 37 workspace window
sweets msg --json resume-events 37 all

One successful acknowledgment establishes the live stream at its returned sequence. Status replayed includes retained matching events newer than the requested cursor; apply them in order, install the boundary, then process later event frames from the same socket. Status too_old contains no replay events but the socket is already subscribed at the returned boundary. Keep it open, issue an authoritative batch on a second connection, install that snapshot at its sequence, and then process buffered events above the covered boundary.

No event can be assigned between resume acknowledgment and live ownership. Malformed filters and sequences ahead of the server return an ordinary error without creating a subscriber. If the previous final subscriber disappeared, Sweets reserves a sequence gap and resume returns too_old, preventing unobserved time from appearing continuous.

The bounded one-shot query remains available for diagnostics and overlapping handoffs:

sweets msg replay-events 37 workspace window
sweets msg --json replay-events 37 all

Its response echoes the requested sequence and unique filters, includes the synchronized current sequence, and returns matching events in original global order. Events are strictly newer than the requested sequence and no newer than the response boundary.

Sweets retains at most 64 events and 128 KiB of encoded event data, and only while at least one subscriber keeps observation active. If the cursor expired or the last subscriber disappeared, replay returns typed too_old; refresh authoritative state with singular or batch queries instead. Sweets reserves a sequence gap when observation stops, so it never presents unobserved time as a continuous event history.

A batch contains at most 32 items and has a 32-unit response budget. Workspace and frame selectors cost one unit, window and output selectors cost four, and input selectors cost 16. This permits up to 32 workspace/frame snapshots, eight window/output snapshots, or two maximum input snapshots, including mixtures, while keeping response work and memory bounded. Empty, over-count, and over-budget batches fail before target lookup.

Window and workspace actions

Directional actions accept left, right, up, or down:

sweets msg close
sweets msg focus left
sweets msg focus-output right
sweets msg move down
sweets msg move-to-output left
sweets msg switch-workspace 3
sweets msg move-to-workspace 4
sweets msg special-toggle
sweets msg special-move
sweets msg toggle-floating
sweets msg toggle-fullscreen
sweets msg toggle-maximize
sweets msg minimize
sweets msg restore-minimized

Stable IDs from sweets msg windows can target a window without first focusing it:

sweets msg focus-window 42
sweets msg close-window 42
sweets msg move-window-to-workspace 42 3
sweets msg set-window-floating 42 on
sweets msg set-window-floating 42 off
sweets msg set-window-minimized 42 on
sweets msg set-window-maximized 42 on
sweets msg set-window-fullscreen 42 on
sweets msg move-window-to-output 42 right
sweets msg move-window-to-output-id 42 DP-2

Targeted focus behaves like taskbar activation: it restores a minimized window and reveals its numbered or special workspace. Targeted movement does not switch the selected workspace and preserves an existing destination focus. Floating assignment is idempotent, making it suitable for declarative scripts. Unknown, unmapped, and stale IDs return not_found without changing state. Minimize, maximize, and fullscreen also accept on or off and are idempotent. Unminimizing does not activate a window; use focus-window when restore and focus is intended. Output movement resolves direction from the target window's current output and preserves the selected output and existing destination focus. Use move-window-to-output-id with the exact, case-sensitive id reported by sweets msg outputs. Unknown or disconnected output IDs return not_found. Moving a window to its current output is a successful no-op.

Layout actions

Layout names are tile, monocle, centered, grid, columns, deck, and dwindle.

sweets msg layout grid
sweets msg cycle-layout
sweets msg cycle-layout previous
sweets msg reset-layout
sweets msg reset-layout all
sweets msg cycle-master-position
sweets msg cycle-master-position previous
sweets msg resize horizontal grow
sweets msg resize vertical shrink

Omitted cycle directions default to next; omitted reset scope defaults to current. Layout operations call the same policy and held-presentation paths as configured bindings. They do not bypass active pointer-resize ownership or layout-specific resize rules.

Administration actions

sweets msg reload
sweets msg output-power DP-1 off
sweets msg output-power DP-1 on
sweets msg quit

Output power is applied through the backend owner. Other output and input settings remain configuration-owned; IPC does not expose arbitrary mutation or command execution.

Every action returns a typed result with changed and message. A valid no-op is successful with changed: false. While the secure session lock is active, all state-changing actions except clean quit are rejected with locked.

Events

Subscribe to one or more unique filters, or use all:

sweets msg subscribe focus window workspace
sweets msg --json subscribe all
sweets msg resume-events 37 workspace window
sweets msg --json resume-events 37 all

Available filters are focus, window, workspace, output, input, config, lock, and shutdown. Workspace events cover selection, assignment, layout, and master-position changes. Queries remain authoritative: notifications are small routing signals intended to trigger a follow-up query.

Normal mode prints a readable acknowledgment followed by one compact event per line. JSON mode prints complete acknowledgment and event envelopes. Sequence numbers increase globally and may contain gaps when a subscriber selects only some filters. The integrated client validates that resumed events match the requested filters, increase within the acknowledgment boundary, and precede every later live frame.

Subscribers have bounded output queues. A client that falls behind is evicted, so it cannot grow compositor memory or block the event loop. Idle subscribers do not cause repaint or polling loops.

Stability

Protocol v24 is the feature-frozen panel and automation surface. Version 24 uses window consistently across queries, IDs, snapshots, batch selectors, targeted actions, special-workspace membership, event filters, and event payloads. The removed view spellings are not aliases. Sweets will continue to fix correctness issues, harden validation, and improve diagnostics. New requests, actions, event categories, or authority boundaries require a concrete consumer need and a deliberate protocol-version change rather than speculative expansion.

Wire protocol v23

The shared sweets-ipc Rust crate owns the wire schema and has no Smithay or live compositor-state dependency. Each frame is one UTF-8 JSON value terminated by a newline.

{"version":23,"id":7,"request":{"workspace":{"number":3,"output":"DP-2"}}}
{"version":23,"id":8,"request":{"action":{"move_window_to_output_id":{"window":42,"output":"DP-2"}}}}
{"version":23,"id":9,"request":{"batch":{"items":[{"type":"window","target":42},{"type":"input","target":"event7"},{"type":"frame","target":"DP-2"},{"type":"workspace","target":{"number":3,"output":"DP-2"}}]}}}
{"version":23,"id":10,"request":{"replay_events":{"after":37,"filters":["workspace","window"]}}}
{"version":23,"id":11,"request":{"resume_events":{"after":37,"filters":["workspace","window"]}}}
{"version":23,"id":11,"outcome":{"status":"success","value":{"type":"resumed","data":{"after":37,"sequence":41,"filters":["workspace","window"],"status":"too_old","events":[]}}}}

Success and failure echo the caller-chosen request ID. Error codes are invalid_frame, invalid_request, unsupported_version, limit_exceeded, locked, not_found, ambiguous, too_old, unavailable, and internal.

The protocol rejects unknown fields and variants, invalid UTF-8 or JSON, trailing frames, wrong versions, invalid workspace numbers, and oversized collections. It deliberately excludes arbitrary command execution, force-kill, clipboard contents, raw input, security tokens, and configured command arguments.

Resource limits

ResourceLimit
Concurrent clients32
Request frame64 KiB
Response frame256 KiB
Event frame64 KiB
Subscriber queue64 KiB
Partial request lifetime10 seconds
String field512 bytes
Batch items32
Batch response cost32 units
Retained replay events64
Retained encoded event bytes128 KiB
Outputs32
Modes per output64
Workspaces576
Windows256
Layer-shell roots64
Input devices64

The nonblocking calloop transport performs bounded work per wake. Slow, malformed, disconnected, or non-reading clients are removed without blocking or panicking the compositor.

Exit codes

CodeMeaning
0success, including a reported no-op
2command usage error
3socket discovery or connection error
4transport, protocol, serialization, or typed server error

On this page