mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-18 10:21:03 +03:00
fix stale primary display selection (#15460)
* fix stale primary display selection Signed-off-by: 21pages <sunboeasy@gmail.com> * fix stale display selection during login and switching - resolve the primary display from the refreshed login snapshot - defer display enumeration until authentication succeeds - read Wayland displays and primary index from the same cache snapshot - reject stale monitor and camera indices during display switching Signed-off-by: 21pages <sunboeasy@gmail.com> * fix inconsistent display snapshots during login - return displays from the same enumeration used to select the primary - avoid re-reading the shared display cache after updating it - use the same converted snapshot during Wayland initialization Signed-off-by: 21pages <sunboeasy@gmail.com> * avoid cloning unchanged display snapshots Signed-off-by: 21pages <sunboeasy@gmail.com> * fix invalid display subset handling Signed-off-by: 21pages <sunboeasy@gmail.com> * minimize code churn in switch_display_to Signed-off-by: 21pages <sunboeasy@gmail.com> --------- Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
@@ -25,9 +25,6 @@ struct ChangedResolution {
|
||||
lazy_static::lazy_static! {
|
||||
static ref IS_CAPTURER_MAGNIFIER_SUPPORTED: bool = is_capturer_mag_supported();
|
||||
static ref CHANGED_RESOLUTIONS: Arc<RwLock<HashMap<String, ChangedResolution>>> = Default::default();
|
||||
// Initial primary display index.
|
||||
// It should not be updated when displays changed.
|
||||
pub static ref PRIMARY_DISPLAY_IDX: usize = get_primary();
|
||||
static ref SYNC_DISPLAYS: Arc<Mutex<SyncDisplaysInfo>> = Default::default();
|
||||
}
|
||||
|
||||
@@ -41,22 +38,14 @@ struct SyncDisplaysInfo {
|
||||
}
|
||||
|
||||
impl SyncDisplaysInfo {
|
||||
fn check_changed(&mut self, displays: Vec<DisplayInfo>) {
|
||||
if self.displays.len() != displays.len() {
|
||||
self.displays = displays;
|
||||
if !TEMP_IGNORE_DISPLAYS_CHANGED.load(Ordering::Relaxed) {
|
||||
self.is_synced = false;
|
||||
}
|
||||
fn check_changed(&mut self, displays: &[DisplayInfo]) {
|
||||
if self.displays.as_slice() == displays {
|
||||
return;
|
||||
}
|
||||
for (i, d) in displays.iter().enumerate() {
|
||||
if d != &self.displays[i] {
|
||||
self.displays = displays;
|
||||
if !TEMP_IGNORE_DISPLAYS_CHANGED.load(Ordering::Relaxed) {
|
||||
self.is_synced = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
self.displays = displays.to_vec();
|
||||
if !TEMP_IGNORE_DISPLAYS_CHANGED.load(Ordering::Relaxed) {
|
||||
self.is_synced = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,6 +293,11 @@ pub(super) fn get_display_info(idx: usize) -> Option<DisplayInfo> {
|
||||
// Display to DisplayInfo
|
||||
// The DisplayInfo is be sent to the peer.
|
||||
pub(super) fn check_update_displays(all: &Vec<Display>) {
|
||||
let _ = update_sync_displays(all);
|
||||
}
|
||||
|
||||
// Return the converted input snapshot while updating the shared display cache.
|
||||
pub(super) fn update_sync_displays(all: &Vec<Display>) -> Vec<DisplayInfo> {
|
||||
// For compatibility: if only one display, scale remains 1.0 and we use the physical size for `uinput`.
|
||||
// If there are multiple displays, we use the logical size for `uinput` by setting scale to d.scale().
|
||||
#[cfg(target_os = "linux")]
|
||||
@@ -346,7 +340,8 @@ pub(super) fn check_update_displays(all: &Vec<Display>) {
|
||||
}
|
||||
})
|
||||
.collect::<Vec<DisplayInfo>>();
|
||||
SYNC_DISPLAYS.lock().unwrap().check_changed(displays);
|
||||
SYNC_DISPLAYS.lock().unwrap().check_changed(&displays);
|
||||
displays
|
||||
}
|
||||
|
||||
pub fn is_inited_msg() -> Option<Message> {
|
||||
@@ -357,34 +352,38 @@ pub fn is_inited_msg() -> Option<Message> {
|
||||
None
|
||||
}
|
||||
|
||||
pub async fn update_get_sync_displays_on_login() -> ResultType<Vec<DisplayInfo>> {
|
||||
// Return the primary index with the refreshed list so login cannot mix display snapshots.
|
||||
pub async fn update_get_sync_displays_on_login() -> ResultType<(Vec<DisplayInfo>, usize)> {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
if !is_x11() {
|
||||
return super::wayland::get_displays().await;
|
||||
let (displays, primary_display_idx) =
|
||||
super::wayland::get_displays_and_primary().await?;
|
||||
let primary_display_idx =
|
||||
normalize_primary_display_idx(primary_display_idx, displays.len());
|
||||
return Ok((displays, primary_display_idx));
|
||||
}
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
let displays = display_service::try_get_displays();
|
||||
#[cfg(windows)]
|
||||
let displays = display_service::try_get_displays_add_amyuni_headless();
|
||||
check_update_displays(&displays?);
|
||||
Ok(SYNC_DISPLAYS.lock().unwrap().displays.clone())
|
||||
let displays = displays?;
|
||||
let primary_display_idx = get_primary_2(&displays);
|
||||
let sync_displays = update_sync_displays(&displays);
|
||||
let primary_display_idx =
|
||||
normalize_primary_display_idx(primary_display_idx, sync_displays.len());
|
||||
Ok((sync_displays, primary_display_idx))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_primary() -> usize {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
if !is_x11() {
|
||||
return match super::wayland::get_primary() {
|
||||
Ok(n) => n,
|
||||
Err(_) => 0,
|
||||
};
|
||||
}
|
||||
fn normalize_primary_display_idx(primary_display_idx: usize, display_len: usize) -> usize {
|
||||
// Zero is the protocol fallback when the list is empty or its primary index is stale.
|
||||
if primary_display_idx < display_len {
|
||||
primary_display_idx
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
try_get_displays().map(|d| get_primary_2(&d)).unwrap_or(0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -486,3 +485,16 @@ pub fn try_get_displays_(add_amyuni_headless: bool) -> ResultType<Vec<Display>>
|
||||
}
|
||||
Ok(displays)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::normalize_primary_display_idx;
|
||||
|
||||
#[test]
|
||||
fn normalize_primary_display_idx_bounds() {
|
||||
assert_eq!(normalize_primary_display_idx(0, 0), 0);
|
||||
assert_eq!(normalize_primary_display_idx(0, 2), 0);
|
||||
assert_eq!(normalize_primary_display_idx(1, 2), 1);
|
||||
assert_eq!(normalize_primary_display_idx(2, 2), 0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user