Sweets

IPC

Inspect and control Sweets through its control socket

Sweets exposes a versioned control socket for querying state, running actions, and subscribing to changes. Use the built-in sweets msg client.

Quick start

sweets msg version
sweets msg outputs
sweets msg windows
sweets msg window 42
sweets msg workspace 2 DP-1
sweets msg status
sweets msg --json inputs

Plain output is readable indented JSON. --json prints the compact envelope with its version, request ID, and typed outcome. Errors go to stderr with a non-zero exit status.

sweets msg --help lists the commands the installed binary accepts, and sweets msg version reports the running compositor's capabilities.

Socket and trust

For WAYLAND_DISPLAY=wayland-2 the socket is:

$XDG_RUNTIME_DIR/sweets-wayland-2.sock

Sweets exports the absolute path as SWEETS_SOCKET to programs it launches. The client uses that first, then falls back to deriving the path.

IPC is an owner-only administration interface, not a sandbox boundary. Any local process running as your user can read window metadata and run every action.

The socket is mode 0600, the runtime directory must be owned by you and closed to everyone else, and peer credentials must match the compositor's UID. If IPC cannot be established, Sweets still starts.

Queries

CommandReturns
versionCompositor and IPC versions, capabilities, limits
outputs / output IDConnectors, modes, geometry, power, scale, transform, VRR
workspaces / workspace NUMBER [OUTPUT_ID]Workspaces with output, active state, layout, master position
special-workspaceEvery special workspace: name, visibility, host output, and window IDs
windows / window IDWindow identity, workspace, output, focus, state, icon
window-rule IDThe resolved opening rule, the rules that matched or were excluded, and diagnostics for one window
window-icon ID [SIZE [SCALE]]One icon buffer's pixels, base64-encoded
layersLayer-shell identity, geometry, keyboard policy, opacity and blur
inputs / input IDlibinput devices, capabilities, settings, switches
frames / frame OUTPUT_IDPer-output frame clock and presentation counters
configPath, generation, reload state, last error
statusLock, backend, rendering, explicit-sync health, and the active binding mode
xwaylandXWayland lifecycle, display, and window counts
binds [MODE]Every binding in the active set, or in MODE
batch SELECTOR ...Several singular snapshots at one event boundary
replay-events SEQUENCE FILTER ...Retained events newer than a sequence

Workspace state is ready for a bar or script:

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

Output and input IDs are exact and case-sensitive. Window IDs are stable while the window is mapped. Unknown, removed, or stale targets return not_found.

In per_monitor workspace mode the same number appears once per monitor, so name the output: sweets msg workspace 2 DP-1. An unqualified duplicate returns ambiguous. Special workspaces are deliberately separate from the numbered ones.

binds prints one line per binding. The trigger is spelled the way sweets.bind accepts it, with MOD shown as the real modifier:

set: default (active)
SUPER+Return             spawn foot
SUPER+SHIFT+slash        show_bindings
SUPER+CTRL+x             spawn foot -e htop  System monitor

Release bindings show (release) after the trigger. With --json, each binding also reports on (press or release), allow_when_locked, repeating, and cooldown_ms. Name a mode to list it while another set is active, or default for the default set.

Titles and application IDs can be sensitive. Treat window metadata carefully when forwarding IPC output somewhere else.

Window icons

Each window reports the icon its client set, or null:

{
  "name": "org.gnome.Nautilus",
  "buffers": [{ "size": 32, "scale": 1, "retained": true }]
}

Resolve name through your XDG icon theme. buffers describes the pixel images the client supplied — a window with "name": null and a non-empty buffers has a pixel-only icon.

Fetch those pixels with window-icon:

sweets msg window-icon 42 | base64 -d > icon.rgba
sweets msg window-icon 42 64 1 | base64 -d > icon-64.rgba

Without SIZE you get the largest buffer Sweets can deliver. The payload is size × size × 4 bytes, row-major, R, G, B, premultiplied A. Plain output prints the base64 alone so it pipes into base64 -d; --json adds the size, scale, and format.

Sweets copies icon pixels when the client commits them. A buffer it cannot keep — one wider than 128 pixels, past the 256 KiB per-window budget, or in a format it does not convert — reports "retained": false, and asking for it returns limit_exceeded or unavailable.

A size the window never declared returns not_found; one that exists at several scales returns ambiguous until you name the scale.

X11 icons come from _NET_WM_ICON, which carries pixels only, so they always report "name": null.

Icon, title, and application-ID changes raise the window_metadata event, not window.

Layer surfaces

sweets msg layers is the layer-rule troubleshooting view. It lists live root surfaces in stable-ID order with their namespace and current layer, the requested against the resolved output, arranged geometry, keyboard interactivity, and the resolved opacity and blur policy.

Blur demand describes compositor policy, not whether the renderer later succeeded. Independent popups are not roots and are omitted.

Batches

One batch fetches several unrelated snapshots together:

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

Selectors are --window, --output, --input, --frame, --workspace, and --workspace-at NUMBER OUTPUT_ID. Results keep the requested order, echo the selector, and carry their own success or error, so one stale target does not discard the rest. Duplicates are preserved. Every --frame item shares one time sample.

The result carries the global event sequence taken just before the items were resolved. For a race-free refresh, subscribe first, then batch on a second connection and install the result at that sequence. Buffered events up to it are covered only for state the batch actually refreshed; retry if you already applied a newer event.

A batch holds at most 32 items within a 32-unit budget: workspace and frame selectors cost 1, window and output 4, and input 16. Empty, oversized, and over-budget batches fail before any lookup.

Actions

sweets msg close
sweets msg force-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 workspace-previous
sweets msg move-to-workspace 4
sweets msg special-toggle [NAME]
sweets msg special-move [NAME]
sweets msg toggle-floating
sweets msg toggle-fullscreen
sweets msg toggle-windowed-fullscreen
sweets msg toggle-maximize
sweets msg minimize
sweets msg restore-minimized

Directions are left, right, up, and down.

force-close ends the focused window's application. It fails with unavailable for an XWayland window; see Force close.

workspace-previous returns the monitor you are on to the workspace it showed before. It works whether or not workspace_back_and_forth is enabled, and does nothing on a monitor you have not switched away from yet.

Targeting a window by ID

IDs from sweets msg windows work without focusing the window first:

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

focus-window behaves like taskbar activation: it restores a minimized window and reveals its workspace. The others do not change the selected workspace and leave existing focus on the destination alone.

The set-window-* actions take on or off and are idempotent, which suits declarative scripts. Un-minimizing does not focus — use focus-window when you want both. move-window-to-output-id needs the exact id from sweets msg outputs; moving a window to the output it is already on succeeds and changes nothing.

Layout

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 previous
sweets msg resize horizontal grow
sweets msg resize vertical shrink

Layouts are tile, monocle, centered, grid, columns, deck, dwindle, and scrolling. A cycle direction defaults to next and a reset scope to current. These use the same paths as key bindings, so layout resize rules and an active pointer resize still apply.

Administration

sweets msg reload
sweets msg reset-binding-mode
sweets msg output-power DP-1 off
sweets msg output-power DP-1 on
sweets msg quit

reset-binding-mode returns to the global bindings from a binding mode. It cannot select a mode, so it is only ever a way out.

Everything else about outputs and input stays configuration-owned; IPC exposes no arbitrary mutation or command execution.

Every action returns changed and message. A valid no-op succeeds with changed: false. While the session is locked, every action except quit is rejected with locked.

Events

sweets msg subscribe focus window workspace
sweets msg --json subscribe all
FilterReports
focusFocus changes
windowWindows opening, closing, and moving
window_metadataTitle, application ID, X11 class or instance, and icon changes
workspaceSelection, assignment, layout, and master position
outputMonitor changes
inputInput device changes
configReload results
lockSession lock and unlock
shutdownThe compositor stopping

Events are small routing signals — queries stay authoritative, so use an event to decide what to re-query. An event fires only when the matching query would actually return something different.

Subscribe to window_metadata instead of polling if you display titles or icons. Windows appearing and disappearing come through window.

Normal mode prints an acknowledgment then one compact event per line; JSON mode prints full envelopes. Sequence numbers increase globally and may skip values when you subscribe to only some filters.

Subscribers have bounded queues, and a client that falls behind is disconnected rather than allowed to grow compositor memory. Idle subscribers cause no repaints or polling.

Reconnecting

When a panel reconnects or sees a sequence gap, resume from the last sequence it applied:

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

One acknowledgment subscribes you live at the returned sequence, with no event lost in between. Status replayed carries the matching retained events newer than your cursor — apply them in order, then process live frames from the same socket. Status too_old carries no events but the socket is already subscribed: keep it open, run an authoritative batch on a second connection, install that at its sequence, and continue from there.

A malformed filter or a sequence ahead of the server returns an ordinary error and creates no subscriber.

replay-events is the one-shot equivalent for diagnostics and overlapping handoffs:

sweets msg replay-events 37 workspace window

Sweets retains at most 64 events and 128 KiB, and only while a subscriber is active. An expired cursor returns too_old; refresh with ordinary queries instead. When observation stops, Sweets reserves a sequence gap so unobserved time can never look continuous.

Stability

The protocol is feature-frozen for panels and automation. Correctness fixes, hardening, and better diagnostics continue; a new request, action, or event category needs a deliberate version change.

Version 38 adds the on field to each binding in the binds reply. Version 37 changed two input fields: enabled now reports the libinput send-events mode (enabled, disabled or disabled_on_external_mouse) and scroll_factor is now a { horizontal, vertical } object. Version 36 added the binds query. Version 30 added named special workspaces. special-workspace now returns a list with a name per entry, a window's workspace reads {"special":"NAME"} instead of "special", and special-toggle and special-move take an optional name. Version 29 added the status binding_mode field and the reset-binding-mode action. Version 28 added the window pinned field. Version 27 added the workspace-previous action. Version 26 added the window_metadata event and the window-icon query. Version 25 added the window icon field. Version 24 renamed view to window everywhere — the old spellings are not aliases.

Wire protocol

Each frame is one UTF-8 JSON value terminated by a newline. Every frame carries the protocol version, and Sweets refuses any other with unsupported_version. Run sweets msg version to read the version your compositor speaks.

{"version": 38,"id":7,"request":{"workspace":{"number":3,"output":"DP-2"}}}
{"version": 38,"id":8,"request":{"action":{"move_window_to_output_id":{"window":42,"output":"DP-2"}}}}
{"version": 38,"id":9,"request":{"batch":{"items":[{"type":"window","target":42},{"type":"frame","target":"DP-2"}]}}}
{"version": 38,"id":10,"request":{"resume_events":{"after":37,"filters":["workspace","window"]}}}

Responses echo your request ID:

{"version": 38,"id":10,"outcome":{"status":"success","value":{"type":"resumed","data":{"after":37,"sequence":41,"filters":["workspace","window"],"status":"too_old","events":[]}}}}

Error codes are invalid_frame, invalid_request, unsupported_version, limit_exceeded, locked, not_found, ambiguous, too_old, unavailable, and internal.

Unknown fields and variants, invalid JSON, trailing frames, wrong versions, and oversized collections are all rejected. The protocol deliberately excludes arbitrary command execution, force-kill, clipboard contents, raw input, and security tokens.

Limits

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

Slow, malformed, or disconnected clients are removed without blocking the compositor.

Exit codes

CodeMeaning
0Success, including a reported no-op
2Command usage error
3Socket discovery or connection error
4Transport, protocol, or server error

On this page