mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-08 05:20:59 +03:00
drm: keep the demoted-display list consistent instead of stretching PipeWire (review 4.5)
A DRM display demoted to PipeWire has no geometry-consistent per-connector stream on a multi-monitor host -- the portal exposes a single whole-desktop stream. The fallthrough served that whole-desktop frame while the list still advertised the demoted connector geometry, so the client stretched the frame and offset all input by the connector origin (the primary-index-0 demotion reaches this even after the get_capturer_for_display exact-index fix). Dropping the display from the list is not an option: its position IS the capturer index, so a drop would shift every later display and desync get_capturer_info. So instead: get_display_infos advertises a multi-monitor demoted display OFFLINE at its stable index, and get_capturer_for_display serves the PipeWire fallback only when its rect matches the advertised geometry, else bails. A single-display host still falls through (whole-desktop == that display). All new logic is drm-gated.
This commit is contained in:
@@ -635,7 +635,27 @@ pub(super) fn get_display_infos() -> Option<Vec<DisplayInfo>> {
|
||||
ProbeState::Available(list) => list.clone(),
|
||||
_ => return None,
|
||||
};
|
||||
Some(augment_with_wayland_geometry(&list))
|
||||
let multi = list.len() > 1;
|
||||
let mut infos = augment_with_wayland_geometry(&list);
|
||||
// review 4.5: on a multi-monitor host a display demoted to PipeWire has no geometry-consistent
|
||||
// per-connector stream to fall through to -- the portal exposes a single whole-desktop stream, so
|
||||
// serving it for one connector would stretch the frame and offset all input. Advertise such a
|
||||
// display OFFLINE while keeping its list position, so the index space stays aligned with
|
||||
// get_capturer_info() (dropping it would shift every later index) and the client re-enumerates
|
||||
// against a consistent list instead of driving a display the server then refuses. A single-display
|
||||
// host is left online: there the whole-desktop stream IS that display, so the PipeWire fallback is
|
||||
// geometry-consistent and get_capturer_for_display serves it.
|
||||
if multi {
|
||||
let failures = DRM_DISPLAY_FAILURES.lock().unwrap();
|
||||
for (idx, info) in infos.iter_mut().enumerate() {
|
||||
if let Some((count, since)) = failures.get(&(idx as i32)).copied() {
|
||||
if count >= DRM_GRAB_MAX_FAILURES && since.elapsed() < DEMOTE_COOLDOWN {
|
||||
info.online = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(infos)
|
||||
}
|
||||
|
||||
/// Index (into the cached DRM display list) of the compositor's PRIMARY output. DRM connector order
|
||||
|
||||
@@ -383,6 +383,40 @@ pub(super) fn get_capturer_for_display(
|
||||
unsafe {
|
||||
let cap_display_info = &*cap_display_info;
|
||||
let rect = cap_display_info.rects[cap_display_info.current];
|
||||
// review 4.5: reaching here with DRM active means get_capturer_info bailed (a demoted
|
||||
// display) and we fell through to PipeWire. Serve this stream ONLY if its rect matches the
|
||||
// geometry we advertised for this index. The portal typically exposes one whole-desktop
|
||||
// stream, so on a multi-monitor host that rect is the FULL desktop while the advertised DRM
|
||||
// geometry is a single connector -> serving it would stretch the frame and offset all
|
||||
// input. Bail instead; get_display_infos advertised the display offline, so the client
|
||||
// re-enumerates against a consistent list. A single-display host matches (whole-desktop ==
|
||||
// that display) and is served normally. On a pure-PipeWire host is_available() is false and
|
||||
// this guard is skipped, preserving upstream behavior exactly.
|
||||
#[cfg(feature = "drm")]
|
||||
if super::drm_capturer::is_available() {
|
||||
if let Some(advertised) = super::drm_capturer::get_display_infos()
|
||||
.and_then(|l| l.get(display_idx).cloned())
|
||||
{
|
||||
let consistent = advertised.x == rect.0 .0
|
||||
&& advertised.y == rect.0 .1
|
||||
&& advertised.width as usize == rect.1
|
||||
&& advertised.height as usize == rect.2;
|
||||
if !consistent {
|
||||
bail!(
|
||||
"drm display {} demoted with no geometry-consistent PipeWire stream (advertised {}x{}+{}+{} vs stream {}x{}+{}+{}); advertised offline",
|
||||
display_idx,
|
||||
advertised.width,
|
||||
advertised.height,
|
||||
advertised.x,
|
||||
advertised.y,
|
||||
rect.1,
|
||||
rect.2,
|
||||
rect.0 .0,
|
||||
rect.0 .1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(super::video_service::CapturerInfo {
|
||||
origin: rect.0,
|
||||
width: rect.1,
|
||||
|
||||
Reference in New Issue
Block a user