From 0cd544061ebea258ebcf162a8edc96c6e34cc65b Mon Sep 17 00:00:00 2001 From: Mariano Abad Date: Tue, 21 Jul 2026 02:43:10 -0300 Subject: [PATCH] drm: do not restart-loop a demoted display PipeWire cannot serve DRM and PipeWire do not share a display-index space: DRM enumerates one entry per connector while the portal often exposes a single whole-desktop stream at index 0. When a per-display DRM capture was demoted to PipeWire for a non-primary DRM index, cap_map.get(&display_idx) was None and the bail Err made ServiceTmpl::run retry get_capturer every 1s forever (a multi-monitor restart loop, latent until a display demotes). Degrade to the whole-desktop stream (index 0) PipeWire does provide instead of spinning. Healthy DRM displays return before this and are unaffected. --- src/server/wayland.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/server/wayland.rs b/src/server/wayland.rs index 748ffaaa9..fe9e96db5 100644 --- a/src/server/wayland.rs +++ b/src/server/wayland.rs @@ -377,8 +377,20 @@ pub(super) fn get_capturer_for_display( } } let cap_map = CAP_DISPLAY_INFO.read().unwrap(); - if let Some(addr) = cap_map.get(&display_idx) { - let cap_display_info: *const CapDisplayInfo = *addr as _; + // DRM and PipeWire do NOT share a display-index space: DRM enumerates one entry per connector + // (0..N), while the portal/PipeWire ScreenCast commonly enumerates a SINGLE whole-desktop stream + // (index 0). So when a per-display DRM capture is demoted to PipeWire for a non-primary DRM index + // that PipeWire cannot serve, `cap_map.get(&display_idx)` is None. Bailing here returned an Err + // that ServiceTmpl::run retries every MAX_ERROR_TIMEOUT (1s) forever — the multi-monitor restart + // loop. Degrade to the whole-desktop stream (index 0) that PipeWire does provide instead: the + // user sees that monitor's content within the desktop stream rather than a 1s spin. Healthy DRM + // displays never reach here (they return above). + let addr = cap_map + .get(&display_idx) + .or_else(|| cap_map.get(&0)) + .copied(); + if let Some(addr) = addr { + let cap_display_info: *const CapDisplayInfo = addr as _; unsafe { let cap_display_info = &*cap_display_info; let rect = cap_display_info.rects[cap_display_info.current];