Skip to content

output: add -o to use only a named output - #523

Open
quinnjr wants to merge 1 commit into
cage-kiosk:masterfrom
quinnjr:feat/output-select
Open

output: add -o to use only a named output#523
quinnjr wants to merge 1 commit into
cage-kiosk:masterfrom
quinnjr:feat/output-select

Conversation

@quinnjr

@quinnjr quinnjr commented Jul 29, 2026

Copy link
Copy Markdown

This PR adds a -o <name> flag that pins Cage to a single output, matched against the wlroots connector name (DP-1, HDMI-A-1, and so on). -m last already restricts Cage to one monitor, but which one you get depends on enumeration order, so there's currently no way to say which screen you actually want. That matters for kiosks and greeters that need to come up on a specific panel.

Excluded outputs get switched off rather than just skipped. The DRM backend hands them over already enabled, and if Cage never renders to one it will sit there scanning out whatever was in its framebuffer when Cage took DRM master, so on a greeter the previous session's last frame stays up next to the login prompt.

If no connected output matches the name, Cage now exits non-zero instead of running with an empty output list. The self-terminate path in output_destroy() is gated on was_nested_output and on an output having been registered first, so it can't catch this case, and the result today is a live compositor rendering nowhere with one INFO line to show for it.

Reaching that new exit turned up an assertion in wlr_output_layout_destroy(), because the listener teardown block only runs on the normal path. I added a teardown: label to unwind the same way. The earlier goto end sites are left alone since they run before those links are initialised.

Tested on the headless backend (WLR_BACKENDS=headless WLR_HEADLESS_OUTPUTS=2) for the matching, non-matching, empty-name, and -o with -m last combinations, and on a real DRM session with two DisplayPort monitors, where the selected output came up as expected and the excluded one went dark. Hotplug is untested.

Cage's existing multi-monitor control (-m extend|last) cannot target a
specific monitor: `last` picks whichever output happens to be enumerated
last, which is not something the user chooses. For kiosk and greeter
setups it is often necessary to pin the session to one known connector.

Add -o <name>, matching the wlroots output name (DP-1, HDMI-A-1, ...).
-o is an admission filter applied before a cg_output is allocated, while
-m is an arrangement policy over outputs already admitted, so -o takes
precedence and an advisory is logged when both are given.

The check sits after the non_desktop branch so DRM leasing of non-desktop
outputs (VR headsets) is unaffected.

Excluded outputs are explicitly disabled rather than merely skipped. An
output may arrive already enabled -- the DRM backend does this, headless
does not -- and leaving one enabled without ever rendering to it means it
keeps scanning out whatever framebuffer it held when cage took DRM
master. On a greeter that leaves the previous session's last frame on
screen next to the login prompt.

Never adding excluded outputs to server->outputs also keeps them out of
the output-management heads, which is what keeps wlr_output->data
non-NULL for every head reachable in output_config_apply().

If no connected output matches, cage exits non-zero instead of running
with an empty output list. Without this a typo produces a live compositor
rendering nowhere, forever, with no error: the existing self-terminate
path in output_destroy() is gated on was_nested_output and on an output
having been registered first, so neither fires. A supervisor such as
greetd reads the exit status, not the log, so failing loudly is what lets
it fall back to a text login.

Reaching that exit revealed that the listener-teardown block only runs on
the normal path, so any goto end after those listeners are registered
trips an assertion in wlr_output_layout_destroy(). Add a teardown: label
so this exit unwinds the same way a normal shutdown does. The earlier
goto end sites are left alone: they run before the links are initialised,
where wl_list_remove would be invalid.
@emersion

Copy link
Copy Markdown
Member

We'd like to move away from CLI flags for output configuration, see #466.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants