Skip to content

Screen Mirroring

Aqueous can mirror one output to another on the same backend/device. The source keeps its resolution, scale, workspace, and refresh rate. The destination fits the complete source image into its own resolution with black bars where needed, including windows, panels, popups, effects, and the cursor.

Back up outputs.toml. Run aqueousctl outputs --json and replace the connector names and modes below with your own. Both outputs must share a backend/device. Add the relationship to ~/.config/aqueous/outputs.toml:

[[output]]
name = "DP-1"
enabled = true
mode = "2560x1440@240"
transform = "normal"
hdr = false
mirror_of = ""
[[output]]
name = "HDMI-A-1"
enabled = true
mode = "1920x1080@60"
mirror_of = "DP-1"
adaptive_sync = false
hdr = false
transform = "normal"

Both displays must use SDR and normal orientation. The source can keep adaptive sync; the destination uses fixed refresh and disallows tearing. Refresh rates do not need to be integer multiples. Aqueous copies frames at destination demand, skips intermediate source updates, and retains the latest complete image when the source is idle.

Set compatible SDR modes and normal orientation first. With [display].apply_on_reload = true, save and press Super+R. Check that the destination shows the source and reports mirror_status: "active". Position and scale are retained for a return to extended mode.

File edits have no protected confirmation timer. Physical mirroring previews remain blocked; see Display previews.

Explicitly clear the relationship in the file that sets it:

[[output]]
name = "HDMI-A-1"
mirror_of = ""
position = [2560, 0]

Save and reload, then check mirror_status: "extended" and move the pointer onto the destination. On failure, check mirror_error and restore your backup. Adjust position for the source’s logical size after scaling. An omitted mirror_of inherits policy; an empty string clears it. A value in outputs.toml takes precedence over wm.toml. Named output profiles accept the same field.

Terminal window
aqueousctl outputs --json

With the embedded output service available, each output can report mirror_of, mirror_status, and mirror_error. Status is starting, active, waiting_for_source, suspended, error, or extended.

The existing output service accepts mirror_of in a set request to $XDG_RUNTIME_DIR/aqueous/outputd.sock:

{
"op": "set",
"changes": [
{ "name": "HDMI-A-1", "mirror_of": "DP-1", "adaptive_sync": false }
]
}

Use compatible SDR and orientation settings first. Apply responses describe staged changes; the compositor’s output transaction performs the backend commit. Inspect the resulting status to confirm the mirror is active.

A mirror has no independent workspace or pointer area. Existing windows migrate using output-removal policy. Returning to extended mode recreates its workspace space without automatically moving those windows back. Mirrors cannot be layer-shell or input-device mapping targets.

A disconnected or powered-off source leaves the mirror black until a usable source returns. The mirror is also black during session locking and while locked. Cached desktop images are discarded on locking, source changes, and resizing; unlocking waits for fresh source content.

The first version supports one pair, SDR, normal transforms, and a shared backend/device. Self references, chains, extra pairs, and incompatible settings are rejected. Vulkan requires timeline synchronization support; the diagnostic Pixman build is also supported. HDR mirroring, rotation, cross-device transfer, delay, audio, and wireless transport are outside this version.

© 2026 Seafoam LabsShelly Chel