mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-08 05:20:59 +03:00
drm: give the DRM uinput update the timeout and the bookkeeping (M3, M6)
The DRM path sets the uinput absolute range itself, because it bypasses check_init. That copy awaited update_mouse_resolution raw, and it was missing three things check_init has sixty lines above it. No timeout: uinput set_resolution reads its reply with no timeout of its own, so a hung uinput socket blocked every video-service start on this branch, and wedged the hotplug worker inside rt.block_on with UINPUT_REFRESH_BUSY latched true, after which every later hotplug refresh was silently skipped for the process lifetime. It is bounded at 3 s now, the same bound check_init uses. No bookkeeping: it never called set_wayland_uinput_rect or set_wayland_layout_baseline, which is why the #15601 layout-drift remap never activated on the DRM path. Both are recorded now, and only after a successful apply, so a transient failure is retried rather than remembered as applied. No cache invalidation: the cached Wayland layout can predate compositor changes made while no session was active, which is the case #15601 is about. Dropped first, as check_init does. It also stops reprogramming the device when the range has not changed (M6): a display in a rebuild loop called this about once a second, and reapplying an identical range is an IPC roundtrip plus a uinput reconfiguration under a user who may be at the console. The layout baseline is still re-snapshotted on every call, since it is what the client coordinates are measured against. Left as a separate copy rather than folded into check_init: check_init ships in every Linux build and the standing rule for this feature is that the drm-off build does not change by a line. Both configs build, 94 tests pass.
This commit is contained in:
@@ -65,6 +65,13 @@ pub(super) fn set_wayland_uinput_rect(rect: (i32, i32, i32, i32)) {
|
||||
WAYLAND_UINPUT_RECT.lock().unwrap().rect = Some(rect);
|
||||
}
|
||||
|
||||
// The uinput ABS range currently programmed into the device, for the DRM path's "reapply only when
|
||||
// it changed" check. The PipeWire path compares it inline in refresh_wayland_uinput_rect_if_changed.
|
||||
#[cfg(all(target_os = "linux", feature = "drm"))]
|
||||
pub(super) fn wayland_uinput_rect() -> Option<(i32, i32, i32, i32)> {
|
||||
WAYLAND_UINPUT_RECT.lock().unwrap().rect
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(super) fn set_wayland_layout_baseline(baseline: Vec<scrap::wayland::display::DisplayRect>) {
|
||||
WAYLAND_LAYOUT_DRIFTED.store(false, Ordering::Relaxed);
|
||||
|
||||
@@ -113,19 +113,62 @@ struct CapDisplayInfo {
|
||||
/// too, otherwise on a multi-monitor host the injected pointer lands on the wrong output — and the
|
||||
/// hardware cursor, which lives on whichever CRTC the pointer is over, never appears on the captured
|
||||
/// CRTC (the "cursor not visible" symptom). Reads the layout from the Wayland outputs, so it is
|
||||
/// independent of the capture backend. DRM-only: check_init keeps its own inline copy so the
|
||||
/// drm-off build stays byte-identical to upstream.
|
||||
/// independent of the capture backend.
|
||||
///
|
||||
/// This is the DRM path's single copy of what `check_init` does inline for PipeWire, and it does the
|
||||
/// same three things, for the same reasons:
|
||||
///
|
||||
/// - drops the cached Wayland layout first, because it can predate compositor changes made while no
|
||||
/// session was active (rustdesk#15601), and on the hotplug path it is stale by definition;
|
||||
/// - bounds the IPC wait, because `uinput::client::set_resolution` reads its reply with no timeout of
|
||||
/// its own, so a hung uinput socket would otherwise block every video-service start on this branch
|
||||
/// and wedge the hotplug worker inside `rt.block_on`, leaving `UINPUT_REFRESH_BUSY` latched true so
|
||||
/// that every later hotplug refresh is silently skipped for the process lifetime;
|
||||
/// - records the applied rect and snapshots the per-display layout baseline, which is what arms the
|
||||
/// #15601 drift remap. Without it the remap never activates on the DRM path at all.
|
||||
///
|
||||
/// It stays a separate copy rather than being folded into `check_init` because `check_init` ships in
|
||||
/// every Linux build and this feature must not change the drm-off one by so much as a line.
|
||||
#[cfg(feature = "drm")]
|
||||
pub(super) async fn update_uinput_resolution() {
|
||||
if crate::input_service::wayland_use_uinput() {
|
||||
if let Some((minx, maxx, miny, maxy)) =
|
||||
scrap::wayland::display::get_desktop_rect_for_uinput()
|
||||
{
|
||||
log::info!("update mouse resolution: ({minx}, {maxx}), ({miny}, {maxy})");
|
||||
allow_err!(input_service::update_mouse_resolution(minx, maxx, miny, maxy).await);
|
||||
} else {
|
||||
log::warn!("Failed to get desktop rect for uinput");
|
||||
if !crate::input_service::wayland_use_uinput() {
|
||||
return;
|
||||
}
|
||||
scrap::wayland::display::clear_wayland_displays_cache();
|
||||
let Some(rect) = scrap::wayland::display::get_desktop_rect_for_uinput() else {
|
||||
log::warn!("Failed to get desktop rect for uinput");
|
||||
return;
|
||||
};
|
||||
// Re-snapshot the baseline on every call: this runs at session init and after every hotplug, and
|
||||
// the baseline is what the client's coordinates are measured against.
|
||||
let snapshot_layout = || {
|
||||
super::display_service::set_wayland_layout_baseline(
|
||||
scrap::wayland::display::get_display_rects_for_uinput(),
|
||||
);
|
||||
};
|
||||
// Reprogram the device only when the range actually changes. A display stuck in a rebuild loop
|
||||
// calls this about once a second, and reapplying an identical range is an IPC roundtrip plus a
|
||||
// uinput device reconfiguration under a user who may be at the console.
|
||||
if super::display_service::wayland_uinput_rect() == Some(rect) {
|
||||
snapshot_layout();
|
||||
return;
|
||||
}
|
||||
let (minx, maxx, miny, maxy) = rect;
|
||||
log::info!("update mouse resolution: ({minx}, {maxx}), ({miny}, {maxy})");
|
||||
match timeout(
|
||||
3_000,
|
||||
input_service::update_mouse_resolution(minx, maxx, miny, maxy),
|
||||
)
|
||||
.await
|
||||
{
|
||||
// Record the rect only after a successful apply, so a transient failure is retried on the
|
||||
// next call instead of being remembered as applied.
|
||||
Ok(Ok(())) => {
|
||||
super::display_service::set_wayland_uinput_rect(rect);
|
||||
snapshot_layout();
|
||||
}
|
||||
Ok(Err(err)) => log::error!("Failed to update mouse resolution: {}", err),
|
||||
Err(err) => log::error!("Failed to update mouse resolution: {}", err),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user