drm: address review findings 3.1, 4.2, 4.3, 4.4, 4.7 + minors

3.1: snapshot the stock flutter bundle before the CI drm relink and restore it
before makepkg, so the official Arch package ships the stock cdylib, not the
drm-enabled one. 4.2: wrap the drm block in a failure-tolerant subshell so a
drm-only failure no longer aborts the stock deb/rpm/arch publish. 4.3: narrow the
publish glob to rustdesk-[0-9]*.deb so the consent-bypass unattended-wayland deb
stays an artifact, not on the public release. 4.4: rewrite the three stale
DRM_CAPTURE_SECURITY.md statements to the split (default path passes a read-only
scanout dma-buf fd over SCM_RIGHTS with an import-once cache; export validation is
metadata-only; BGRA-over-the-wire is the fallback) and document that grab_desc's
fd is O_RDONLY (DRM_RDWR dropped upstream, dup preserves it). 4.7: only
short-circuit to the DRM cursor when it is authoritative (visible, or hidden in a
pure-DRM session); fall through to the normal cursor path in a mixed
DRM+PipeWire session. minors: thread the deb variant by feature not glob; TODO
for the ld.so.conf.d system path; drop a stray blank line. All gated or
whitespace so the drm-off build stays byte-identical.
This commit is contained in:
Mariano Abad
2026-07-21 15:13:33 -03:00
parent b642c75a64
commit 75af53b9bf
6 changed files with 148 additions and 32 deletions

View File

@@ -365,7 +365,17 @@ pub fn get_cursor() -> ResultType<Option<u64>> {
#[cfg(feature = "drm")]
if !is_x11() {
if let Some(id) = crate::server::drm_capturer::drm_cursor_id() {
return Ok(Some(id));
// In a mixed DRM + PipeWire session the DRM streams only cover the DRM-backed displays;
// when the pointer sits on a PipeWire-served display every DRM stream reports the hidden
// sentinel. Returning that sentinel here would hide the cursor globally, including on the
// PipeWire display where it is still visible, so only report a hidden DRM cursor when it
// is authoritative -- a pure-DRM session. A visible DRM cursor is always authoritative;
// otherwise fall through to the normal cursor path.
if id != scrap::drm_reader::HIDDEN_CURSOR_ID
|| !crate::server::display_service::has_non_drm_backed_display()
{
return Ok(Some(id));
}
}
}
let mut res = None;
@@ -392,14 +402,21 @@ pub fn get_cursor_data(hcursor: u64) -> ResultType<CursorData> {
#[cfg(feature = "drm")]
if !is_x11() {
if let Some(c) = crate::server::drm_capturer::drm_cursor() {
let mut cd: CursorData = Default::default();
cd.id = c.id;
cd.width = c.width;
cd.height = c.height;
cd.hotx = c.hotx;
cd.hoty = c.hoty;
cd.colors = c.colors.into();
return Ok(cd);
// See get_cursor(): a hidden DRM sentinel is authoritative only in a pure-DRM session. In
// a mixed DRM + PipeWire session fall through so the PipeWire display's cursor is served
// by the normal path instead of being hidden everywhere.
if c.id != scrap::drm_reader::HIDDEN_CURSOR_ID
|| !crate::server::display_service::has_non_drm_backed_display()
{
let mut cd: CursorData = Default::default();
cd.id = c.id;
cd.width = c.width;
cd.height = c.height;
cd.hotx = c.hotx;
cd.hoty = c.hoty;
cd.colors = c.colors.into();
return Ok(cd);
}
}
}
let mut res = None;

View File

@@ -444,6 +444,23 @@ pub(super) fn get_display_info(idx: usize) -> Option<DisplayInfo> {
SYNC_DISPLAYS.lock().unwrap().displays.get(idx).cloned()
}
// True when at least one advertised (synced) display is NOT served by the DRM/KMS capture path,
// i.e. a mixed DRM + PipeWire session. The cursor service (platform::linux::get_cursor /
// get_cursor_data) uses this to decide whether a hidden DRM hardware-cursor sentinel is
// authoritative: in a pure-DRM session it is (the pointer is genuinely off every captured CRTC),
// but in a mixed session the sentinel only means the pointer moved onto a PipeWire-served display,
// whose cursor must come from the normal path instead of being hidden everywhere.
//
// When DRM capture is active the advertised list is enumerated from the DRM display list, so a DRM
// list shorter than the synced list means at least one advertised display is served by PipeWire.
#[cfg(all(target_os = "linux", feature = "drm"))]
pub fn has_non_drm_backed_display() -> bool {
match super::drm_capturer::get_display_infos() {
Some(drm) => drm.len() < SYNC_DISPLAYS.lock().unwrap().displays.len(),
None => false,
}
}
// Display to DisplayInfo
// The DisplayInfo is be sent to the peer.
pub(super) fn check_update_displays(all: &Vec<Display>) {
@@ -545,7 +562,6 @@ pub fn get_primary_2(all: &Vec<Display>) -> usize {
all.iter().position(|d| d.is_primary()).unwrap_or(0)
}
#[inline]
#[cfg(windows)]
fn no_displays(displays: &Vec<Display>) -> bool {