diff --git a/src/server/connection.rs b/src/server/connection.rs index e32a4c1c3..486d52829 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1051,13 +1051,15 @@ impl Connection { ..Default::default() }) .into(); + // `try_reset_current_display` is needed because `get_displays` may change the current display, + // which may cause the mismatch of current display and the current display name. #[cfg(not(any(target_os = "android", target_os = "ios")))] video_service::try_reset_current_display(); #[cfg(not(any(target_os = "android", target_os = "ios")))] { pi.resolutions = Some(SupportedResolutions { - resolutions: video_service::get_current_display_name() - .map(|name| crate::platform::resolutions(&name)) + resolutions: video_service::get_current_display() + .map(|(_, _, d)| crate::platform::resolutions(&d.name())) .unwrap_or(vec![]), ..Default::default() }) @@ -1948,7 +1950,8 @@ impl Connection { #[cfg(not(any(target_os = "android", target_os = "ios")))] fn change_resolution(&mut self, r: &Resolution) { if self.keyboard { - if let Ok(name) = video_service::get_current_display_name() { + if let Ok((_, _, display)) = video_service::get_current_display() { + let name = display.name(); #[cfg(all(windows, feature = "virtual_display_driver"))] if let Some(_ok) = crate::virtual_display_manager::change_resolution_if_is_virtual_display( @@ -1959,6 +1962,11 @@ impl Connection { { return; } + video_service::set_last_changed_resolution( + &name, + (display.width() as _, display.height() as _), + (r.width, r.height), + ); if let Err(e) = crate::platform::change_resolution(&name, r.width as _, r.height as _) { diff --git a/src/server/video_service.rs b/src/server/video_service.rs index a74211fcd..d4578f547 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -52,6 +52,11 @@ use std::{ pub const NAME: &'static str = "video"; +struct ChangedResolution { + original: (i32, i32), + changed: (i32, i32), +} + lazy_static::lazy_static! { pub static ref CURRENT_DISPLAY: Arc> = Arc::new(Mutex::new(usize::MAX)); static ref LAST_ACTIVE: Arc> = Arc::new(Mutex::new(Instant::now())); @@ -66,58 +71,29 @@ lazy_static::lazy_static! { pub static ref IS_UAC_RUNNING: Arc> = Default::default(); pub static ref IS_FOREGROUND_WINDOW_ELEVATED: Arc> = Default::default(); pub static ref LAST_SYNC_DISPLAYS: Arc>> = Default::default(); - static ref ORIGINAL_RESOLUTIONS: Arc>> = Default::default(); + static ref CHANGED_RESOLUTIONS: Arc>> = Default::default(); } -// Not virtual display #[inline] -fn set_original_resolution_(display_name: &str, wh: (i32, i32)) -> (i32, i32) { - let mut original_resolutions = ORIGINAL_RESOLUTIONS.write().unwrap(); - match original_resolutions.get(display_name) { - Some(r) => r.clone(), +pub fn set_last_changed_resolution(display_name: &str, original: (i32, i32), changed: (i32, i32)) { + let mut lock = CHANGED_RESOLUTIONS.write().unwrap(); + match lock.get_mut(display_name) { + Some(res) => res.changed = changed, None => { - original_resolutions.insert(display_name.to_owned(), wh.clone()); - wh + lock.insert( + display_name.to_owned(), + ChangedResolution { original, changed }, + ); } } } -// Not virtual display -#[inline] -fn get_original_resolution_(display_name: &str) -> Option<(i32, i32)> { - ORIGINAL_RESOLUTIONS - .read() - .unwrap() - .get(display_name) - .map(|r| r.clone()) -} - -// Not virtual display -#[inline] -fn get_or_set_original_resolution_(display_name: &str, wh: (i32, i32)) -> (i32, i32) { - let r = get_original_resolution_(display_name); - if let Some(r) = r { - return r; - } - set_original_resolution_(display_name, wh) -} - -// Not virtual display -#[inline] -fn update_get_original_resolution_(display_name: &str, w: usize, h: usize) -> Resolution { - let wh = get_or_set_original_resolution_(display_name, (w as _, h as _)); - Resolution { - width: wh.0, - height: wh.1, - ..Default::default() - } -} - #[inline] #[cfg(not(any(target_os = "android", target_os = "ios")))] pub fn reset_resolutions() { - for (name, (w, h)) in ORIGINAL_RESOLUTIONS.read().unwrap().iter() { - if let Err(e) = crate::platform::change_resolution(name, *w as _, *h as _) { + for (name, res) in CHANGED_RESOLUTIONS.read().unwrap().iter() { + let (w, h) = res.original; + if let Err(e) = crate::platform::change_resolution(name, w as _, h as _) { log::error!( "Failed to reset resolution of display '{}' to ({},{}): {}", name, @@ -461,27 +437,17 @@ fn get_capturer(use_yuv: bool, portable_service_running: bool) -> ResultType Option> { let displays = try_get_displays().ok()?; let last_sync_displays = &*LAST_SYNC_DISPLAYS.read().unwrap(); - if displays.len() != last_sync_displays.len() { + // No need to check if the resolutions are changed by third process. Some(displays) } else { - for i in 0..displays.len() { - if displays[i].height() != (last_sync_displays[i].height as usize) { - return Some(displays); - } - if displays[i].width() != (last_sync_displays[i].width as usize) { - return Some(displays); - } - if displays[i].origin() != (last_sync_displays[i].x, last_sync_displays[i].y) { - return Some(displays); - } - } None } } fn check_get_displays_changed_msg() -> Option { let displays = check_displays_new()?; + // Display to DisplayInfo let (current, displays) = get_displays_2(&displays); let mut pi = PeerInfo { ..Default::default() @@ -537,7 +503,9 @@ fn run(sp: GenericService) -> ResultType<()> { if *SWITCH.lock().unwrap() { log::debug!("Broadcasting display switch"); let mut misc = Misc::new(); - let display_name = get_current_display_name().unwrap_or_default(); + let display_name = get_current_display() + .map(|(_, _, d)| d.name()) + .unwrap_or_default(); let original_resolution = get_original_resolution(&display_name, c.width, c.height); misc.set_switch_display(SwitchDisplay { display: c.current as _, @@ -895,7 +863,24 @@ fn get_original_resolution(display_name: &str, w: usize, h: usize) -> MessageFie ..Default::default() } } else { - update_get_original_resolution_(&display_name, w, h) + let mut changed_resolutions = CHANGED_RESOLUTIONS.write().unwrap(); + let (width, height) = match changed_resolutions.get(display_name) { + Some(res) => { + if res.changed.0 != w as i32 || res.changed.1 != h as i32 { + // If the resolution is changed by third process, remove the record in changed_resolutions. + changed_resolutions.remove(display_name); + (w as _, h as _) + } else { + res.original + } + } + None => (w as _, h as _), + }; + Resolution { + width, + height, + ..Default::default() + } }) .into() } @@ -1057,13 +1042,6 @@ pub fn get_current_display() -> ResultType<(usize, usize, Display)> { get_current_display_2(try_get_displays()?) } -// `try_reset_current_display` is needed because `get_displays` may change the current display, -// which may cause the mismatch of current display and the current display name. -#[inline] -pub fn get_current_display_name() -> ResultType { - Ok(get_current_display_2(try_get_displays()?)?.2.name()) -} - #[cfg(windows)] fn start_uac_elevation_check() { static START: Once = Once::new(); diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index bbf6d0aec..6d8000352 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -927,34 +927,49 @@ impl Session { } } - pub fn handle_peer_switch_display(&self, display: &SwitchDisplay) { - self.ui_handler.switch_display(display); - - if self.last_change_display.lock().unwrap().is_the_same_record( - display.display, - display.width, - display.height, - ) { - let custom_resolution = if display.width != display.original_resolution.width - || display.height != display.original_resolution.height - { - Some((display.width, display.height)) - } else { - None - }; + fn set_custom_resolution(&self, display: &SwitchDisplay) { + if display.width == display.original_resolution.width + && display.height == display.original_resolution.height + { self.lc .write() .unwrap() - .set_custom_resolution(display.display, custom_resolution); + .set_custom_resolution(display.display, None); + } else { + let last_change_display = self.last_change_display.lock().unwrap(); + if last_change_display.display == display.display { + let wh = if last_change_display.is_the_same_record( + display.display, + display.width, + display.height, + ) { + Some((display.width, display.height)) + } else { + // display origin is changed, or some other events. + None + }; + self.lc + .write() + .unwrap() + .set_custom_resolution(display.display, wh); + } } } + #[inline] + pub fn handle_peer_switch_display(&self, display: &SwitchDisplay) { + self.ui_handler.switch_display(display); + self.set_custom_resolution(display); + } + + #[inline] pub fn change_resolution(&self, display: i32, width: i32, height: i32) { *self.last_change_display.lock().unwrap() = ChangeDisplayRecord::new(display, width, height); self.do_change_resolution(width, height); } + #[inline] fn try_change_init_resolution(&self, display: i32) { if let Some((w, h)) = self.lc.read().unwrap().get_custom_resolution(display) { self.do_change_resolution(w, h); @@ -973,10 +988,12 @@ impl Session { self.send(Data::Message(msg)); } + #[inline] pub fn request_voice_call(&self) { self.send(Data::NewVoiceCall); } + #[inline] pub fn close_voice_call(&self) { self.send(Data::CloseVoiceCall); }