From 58d073b516c7d2ade6b158dd80790f8437848203 Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 1 Nov 2023 15:33:21 +0800 Subject: [PATCH] fix, remove unused capturer when switching display Signed-off-by: fufesou --- .../lib/desktop/widgets/remote_toolbar.dart | 5 +- flutter/lib/models/model.dart | 32 +++++--- src/flutter.rs | 82 ++++++++++++++----- src/flutter_ffi.rs | 8 +- src/server/connection.rs | 11 ++- src/server/display_service.rs | 2 +- 6 files changed, 98 insertions(+), 42 deletions(-) diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 199b557c810d..dac8ae528156 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -1223,8 +1223,9 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { @override Widget build(BuildContext context) { final isVirtualDisplay = ffiModel.isVirtualDisplayResolution; - final visible = - ffiModel.keyboard && (isVirtualDisplay || resolutions.length > 1); + final visible = ffiModel.keyboard && + (isVirtualDisplay || resolutions.length > 1) && + pi.currentDisplay != kAllDisplayValue; if (!visible) return Offstage(); final showOriginalBtn = ffiModel.isOriginalResolutionSet && !ffiModel.isOriginalResolution; diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 81a646f60cbe..05d5985a2eb0 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -431,15 +431,19 @@ class FfiModel with ChangeNotifier { handleSwitchDisplay( Map evt, SessionID sessionId, String peerId) { - final curDisplay = int.parse(evt['display']); + final display = int.parse(evt['display']); if (_pi.currentDisplay != kAllDisplayValue) { if (bind.peerGetDefaultSessionsCount(id: peerId) > 1) { - if (curDisplay != _pi.currentDisplay) { + if (display != _pi.currentDisplay) { return; } } - _pi.currentDisplay = curDisplay; + if (!_pi.isSupportMultiUiSession) { + _pi.currentDisplay = display; + } + // If `isSupportMultiUiSession` is true, the switch display message should not be used to update current display. + // It is only used to update the display info. } var newDisplay = Display(); @@ -452,16 +456,24 @@ class FfiModel with ChangeNotifier { int.tryParse(evt['original_width']) ?? kInvalidResolutionValue; newDisplay.originalHeight = int.tryParse(evt['original_height']) ?? kInvalidResolutionValue; - _pi.displays[curDisplay] = newDisplay; + _pi.displays[display] = newDisplay; - updateCurDisplay(sessionId); - try { - CurrentDisplayState.find(peerId).value = curDisplay; - } catch (e) { - // + if (!_pi.isSupportMultiUiSession || _pi.currentDisplay == display) { + updateCurDisplay(sessionId); + } + + if (!_pi.isSupportMultiUiSession) { + try { + CurrentDisplayState.find(peerId).value = display; + } catch (e) { + // + } } + parent.target?.recordingModel.onSwitchDisplay(); - handleResolutions(peerId, evt['resolutions']); + if (!_pi.isSupportMultiUiSession || _pi.currentDisplay == display) { + handleResolutions(peerId, evt['resolutions']); + } notifyListeners(); } diff --git a/src/flutter.rs b/src/flutter.rs index 6bda3ae3a024..24c2149d5fad 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -1466,25 +1466,7 @@ pub mod sessions { if write_lock.is_empty() { remove_peer_key = Some(peer_key.clone()); } else { - // Set capture displays if some are not used any more. - let mut remains_displays = HashSet::new(); - for (_, h) in write_lock.iter() { - remains_displays.extend( - h.renderer - .map_display_sessions - .read() - .unwrap() - .keys() - .cloned(), - ); - } - if !remains_displays.is_empty() { - s.capture_displays( - vec![], - vec![], - remains_displays.iter().map(|d| *d as i32).collect(), - ); - } + check_remove_unused_displays(None, id, s, &write_lock); } break; } @@ -1494,6 +1476,68 @@ pub mod sessions { SESSIONS.write().unwrap().remove(&remove_peer_key?) } + #[cfg(feature = "flutter_texture_render")] + fn check_remove_unused_displays( + current: Option, + session_id: &SessionID, + session: &FlutterSession, + handlers: &HashMap, + ) { + // Set capture displays if some are not used any more. + let mut remains_displays = HashSet::new(); + if let Some(current) = current { + remains_displays.insert(current); + } + for (k, h) in handlers.iter() { + if k == session_id { + continue; + } + remains_displays.extend( + h.renderer + .map_display_sessions + .read() + .unwrap() + .keys() + .cloned(), + ); + } + if !remains_displays.is_empty() { + session.capture_displays( + vec![], + vec![], + remains_displays.iter().map(|d| *d as i32).collect(), + ); + } + } + + pub fn session_switch_display(session_id: SessionID, value: Vec) { + for s in SESSIONS.read().unwrap().values() { + let read_lock = s.ui_handler.session_handlers.read().unwrap(); + if read_lock.contains_key(&session_id) { + if value.len() == 1 { + // Switch display. + // This operation will also cause the peer to send a switch display message. + // The switch display message will contain `SupportedResolutions`, which is useful when changing resolutions. + s.switch_display(value[0]); + + // Check if other displays are needed. + if value.len() == 1 { + check_remove_unused_displays( + Some(value[0] as _), + &session_id, + &s, + &read_lock, + ); + } + } else { + // Try capture all displays. + s.capture_displays(vec![], vec![], value); + } + break; + } + } + } + #[inline] pub fn insert_session(session_id: SessionID, conn_type: ConnType, session: FlutterSession) { SESSIONS diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index dc4a904d4d56..b72e706fb835 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -429,13 +429,7 @@ pub fn session_ctrl_alt_del(session_id: SessionID) { } pub fn session_switch_display(session_id: SessionID, value: Vec) { - if let Some(session) = sessions::get_session_by_session_id(&session_id) { - if value.len() == 1 { - session.switch_display(value[0]); - } else { - session.capture_displays(vec![], vec![], value); - } - } + sessions::session_switch_display(session_id, value); } pub fn session_handle_flutter_key_event( diff --git a/src/server/connection.rs b/src/server/connection.rs index 224b88eac0e0..a31fcb8d4fd3 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -2177,8 +2177,9 @@ impl Connection { } // Send display changed message. - // For compatibility with old versions ( < 1.2.4 ). - // sciter need it in new version + // 1. For compatibility with old versions ( < 1.2.4 ). + // 2. Sciter version. + // 3. Update `SupportedResolutions`. if let Some(msg_out) = video_service::make_display_changed_msg(self.display_idx, None) { self.send(msg_out).await; } @@ -2194,7 +2195,11 @@ impl Connection { lock.add_service(Box::new(video_service::new(display_idx))); } } - lock.subscribe(&old_service_name, self.inner.clone(), false); + // For versions greater than 1.2.4, a `CaptureDisplays` message will be sent immediately. + // Unnecessary capturers will be removed then. + if !crate::common::is_support_multi_ui_session(&self.lr.version) { + lock.subscribe(&old_service_name, self.inner.clone(), false); + } lock.subscribe(&new_service_name, self.inner.clone(), true); self.display_idx = display_idx; } diff --git a/src/server/display_service.rs b/src/server/display_service.rs index 30225e491e23..318ead5f631e 100644 --- a/src/server/display_service.rs +++ b/src/server/display_service.rs @@ -349,7 +349,7 @@ pub fn try_get_displays() -> ResultType> { #[cfg(all(windows, feature = "virtual_display_driver"))] pub fn try_get_displays() -> ResultType> { let mut displays = Display::all()?; - if no_displays(&displays) { + if crate::platform::is_installed() && no_displays(&displays) { log::debug!("no displays, create virtual display"); if let Err(e) = virtual_display_manager::plug_in_headless() { log::error!("plug in headless failed {}", e);