Summary
Fixes #552. Follow-up to #548: apply #548 first to reproduce, otherwise the broker rotation rejection fails first.
With #548 applied, an exclusive-layout restore still aborted:
Linux private display: saved output DP-2 did not activate as the topology restore guard; preserving the current private scanout.and the physical outputs stayed disabled after the stream.
KWin keeps output priorities contiguous. While the retiring private output (Virtual-1) is still live, it holds priority 1, so each restored physical output comes back one slot lower than its saved priority. snapshot_matches() required an exact priority match during the guard and pre-retirement activation checks, so those checks could never pass.
Reproduced on KDE Plasma Wayland by replaying the host's guard and restore kscreen-doctor arguments while Virtual-1 was the only enabled output:
| Output | Saved priority | Reported while Virtual-1 is live |
|---|---|---|
| DP-2 (guard) | 1 | 2 |
| DP-1 | 2 | 3 |
Mode, scale, position, rotation and HDR all matched. After Virtual-1 was disconnected, KWin renumbered the outputs to DP-2=1 and DP-1=2.
The live test on #548 restored correctly because Remote Monitor composed the physical outputs together with Virtual-1 in that session, so they kept their own priority slots. This failure needs Virtual-1 to be the only enabled output.
Change
Saved priorities are now enforced only in the final check (final=true), which runs after the private connector is disconnected. The existing post-disconnect restore pass still reapplies priorities if KWin does not renumber them itself.
Reproduce
- Apply #548.
- KDE Plasma Wayland,
virtual_display_layout = exclusive, at least one physical output. - Stream, then disconnect. Without this PR the log shows
did not activate as the topology restore guardand the physical outputs stay off.
To see only the KWin behaviour (no Moonlight needed): with output A disabled and output B enabled, run kscreen-doctor output.A.enable output.A.priority.1. kscreen-doctor -j then reports A at priority 2.
Test plan
- New unit test
ActivationToleratesPriorityHeldByRetiringOutput -
test_component_linux_private_display_restore_policy: 23/23 pass - Host rebuilt and deployed on CachyOS / KDE Wayland (AMD + NVIDIA,
virtual_display_layout = exclusive); the restart retired the private connector and restored DP-1 and DP-2 with their saved priorities - Full Moonlight stream → disconnect → restore cycle with #548 applied (manual testing shortly)
🤖 Generated with Claude Code
Activity
2This pull request is a draft
Merging is unavailable until it is marked ready for review.
Thanks for the detailed reproduction and the restore-policy test. Development integration targets
canary; could you update this original PR's base tocanary, update the branch, and resolve the conflicts? The rotation allowlist from #548 is present oncanary, so please preserve it while reconciling the restore path. Please also verify that the updated code still enforces the saved priorities after the private connector is retired, including the post-disconnect reapply path; the new test exercises the policy predicate but not that full sequence.