mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-08-23 22:56:41 +00:00
fix: ask the greeter compositor for the multi-monitor layout
The display arrangement and the pointer mapping were wrong at a multi-monitor login screen, and the mechanism is measured on a two-head virtio VM: DRM has no origins, so every display was advertised at (0,0) (a stacked arrangement on the client), and the uinput range was taken from the union of the DRM modes while the compositor had arranged the outputs side by side. Both came from the same premise, written before the hbb_common socket fallback existed: "a login screen has no compositor to ask". wayland_outputs_askable() skipped the wl_output augmentation at any greeter, and update_uinput_resolution took the DRM union directly. The premise is false now: a greeter runs a compositor, and the socket fallback reaches it with no environment variables, measured answering two outputs at the VM greeter while the old gate was still routing around it. Drop the gate and take the compositor-first path everywhere. Where the fallback cannot answer, the output list comes back empty and both call sites degrade to exactly the old behavior, so a build against an older hbb_common is unchanged.
This commit is contained in:
@@ -1095,9 +1095,6 @@ pub(super) fn get_primary_index() -> usize {
|
||||
ProbeState::Available(_, list) => list.clone(),
|
||||
_ => return 0,
|
||||
};
|
||||
if !wayland_outputs_askable() {
|
||||
return 0;
|
||||
}
|
||||
let wl = scrap::wayland::display::get_displays();
|
||||
if wl.displays.is_empty() {
|
||||
return 0;
|
||||
@@ -1108,18 +1105,16 @@ pub(super) fn get_primary_index() -> usize {
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Whether the compositor can be asked for its outputs here. A login screen has none, and
|
||||
/// `get_displays()` does not cache that failure, so it reopens a connection every call. Both
|
||||
/// callers treat an empty list as "no augmentation", so skipping cannot change either answer.
|
||||
fn wayland_outputs_askable() -> bool {
|
||||
!crate::platform::linux::is_login_screen_wayland_cached()
|
||||
}
|
||||
|
||||
/// DRM reports every monitor at physical size and origin (0,0), stacking a multi-monitor client.
|
||||
///
|
||||
/// Asked at login screens too, on purpose: a greeter runs a compositor, and the socket fallback in
|
||||
/// hbb_common lets the enumerator reach it with no environment variables. Where that fallback
|
||||
/// cannot answer, the list comes back empty and everything stays unaugmented, which is what the
|
||||
/// old is-login-screen gate produced unconditionally.
|
||||
fn augment_with_wayland_geometry(drm: &[DrmDisplayInfo]) -> Vec<DisplayInfo> {
|
||||
let mut infos: Vec<DisplayInfo> = drm.iter().map(display_info_from_drm).collect();
|
||||
// Below two displays there is nothing to augment, compositor or not.
|
||||
if drm.len() < 2 || !wayland_outputs_askable() {
|
||||
if drm.len() < 2 {
|
||||
return infos;
|
||||
}
|
||||
let wl = scrap::wayland::display::get_displays();
|
||||
|
||||
+10
-21
@@ -153,29 +153,18 @@ pub(super) async fn update_uinput_resolution() {
|
||||
if !crate::input_service::wayland_use_uinput() {
|
||||
return;
|
||||
}
|
||||
// A greeter's `--server` gets no compositor variables, so the enumerator cannot answer and
|
||||
// the device would keep its default range. The DRM displays are the ones being captured, so
|
||||
// their coordinate space matches by construction; ask them first rather than after a failure.
|
||||
let rect = if crate::platform::linux::is_login_screen_wayland_cached() {
|
||||
let Some(rect) = drm_desktop_rect_for_uinput() else {
|
||||
// Compositor first at a login screen too: a greeter runs one, and the hbb_common socket
|
||||
// fallback reaches it with no environment variables. The DRM union is the fallback, and it is
|
||||
// a real loss to land there on a multi-monitor host: DRM has no origins, so its union rect
|
||||
// mis-maps the pointer whenever the compositor arranged the outputs side by side.
|
||||
scrap::wayland::display::clear_wayland_displays_cache();
|
||||
let rect = match scrap::wayland::display::get_desktop_rect_for_uinput()
|
||||
.or_else(drm_desktop_rect_for_uinput)
|
||||
{
|
||||
Some(rect) => rect,
|
||||
None => {
|
||||
log::warn!("Failed to get desktop rect for uinput");
|
||||
return;
|
||||
};
|
||||
log::info!(
|
||||
"uinput desktop rect taken from the DRM display list (no compositor here): {rect:?}"
|
||||
);
|
||||
rect
|
||||
} else {
|
||||
scrap::wayland::display::clear_wayland_displays_cache();
|
||||
// Also for a compositor that answers late: the DRM list beats no answer.
|
||||
match scrap::wayland::display::get_desktop_rect_for_uinput()
|
||||
.or_else(drm_desktop_rect_for_uinput)
|
||||
{
|
||||
Some(rect) => rect,
|
||||
None => {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user