From fb1aa9c0285fbbad10cb75c958e791b534fc021d Mon Sep 17 00:00:00 2001 From: fufesou Date: Sat, 20 Apr 2024 14:54:23 +0800 Subject: [PATCH] Fix. Multi-display connection, resolutions (#7782) * fix: multi-display, change resolution Signed-off-by: fufesou * fix: multi-displays, resolutions of displays Signed-off-by: fufesou * fix: build Signed-off-by: fufesou * refact: Function rename Signed-off-by: fufesou * refact. Function rename Signed-off-by: fufesou --------- Signed-off-by: fufesou --- flutter/lib/models/model.dart | 8 ++++- flutter/lib/web/bridge.dart | 5 +++ libs/hbb_common/protos/message.proto | 16 ++++++++++ src/flutter_ffi.rs | 6 ++++ src/server/connection.rs | 48 ++++++++++++++++++++-------- src/ui_session_interface.rs | 33 ++++++++++++++++--- src/virtual_display_manager.rs | 7 ++++ 7 files changed, 105 insertions(+), 18 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 046767be6..4da7d54cd 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -715,6 +715,8 @@ class FfiModel with ChangeNotifier { // Map clone is required here, otherwise "evt" may be changed by other threads through the reference. // Because this function is asynchronous, there's an "await" in this function. cachedPeerData.peerInfo = {...evt}; + // Do not cache resolutions, because a new display connection have different resolutions. + cachedPeerData.peerInfo.remove('resolutions'); // Recent peer is updated by handle_peer_info(ui_session_interface.rs) --> handle_peer_info(client.rs) --> save_config(client.rs) bind.mainLoadRecentPeers(); @@ -770,7 +772,9 @@ class FfiModel with ChangeNotifier { } Map features = json.decode(evt['features']); _pi.features.privacyMode = features['privacy_mode'] == 1; - handleResolutions(peerId, evt["resolutions"]); + if (!isCache) { + handleResolutions(peerId, evt["resolutions"]); + } parent.target?.elevationModel.onPeerInfo(_pi); } if (connType == ConnType.defaultConn) { @@ -2317,6 +2321,8 @@ class FFI { } await ffiModel.handleCachedPeerData(data, id); await sessionRefreshVideo(sessionId, ffiModel.pi); + await bind.sessionRequestNewDisplayInitMsgs( + sessionId: sessionId, display: ffiModel.pi.currentDisplay); }); isToNewWindowNotified.value = true; } diff --git a/flutter/lib/web/bridge.dart b/flutter/lib/web/bridge.dart index 952893393..fd0d7189b 100644 --- a/flutter/lib/web/bridge.dart +++ b/flutter/lib/web/bridge.dart @@ -1577,5 +1577,10 @@ class RustdeskImpl { throw UnimplementedError(); } + Future sessionRequestNewDisplayInitMsgs( + {required UuidValue sessionId, required int display, dynamic hint}) { + throw UnimplementedError(); + } + void dispose() {} } diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index b2001ba68..7ffa0e6de 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -504,6 +504,11 @@ message Resolution { int32 height = 2; } +message DisplayResolution { + int32 display = 1; + Resolution resolution = 2; +} + message SupportedResolutions { repeated Resolution resolutions = 1; } message SwitchDisplay { @@ -716,6 +721,13 @@ message WindowsSessions { uint32 current_sid = 2; } +// Query a message from peer. +message MessageQuery { + // The SwitchDisplay message of the target display. + // If the target display is not found, the message will be ignored. + int32 switch_display = 1; +} + message Misc { oneof union { ChatMessage chat_message = 4; @@ -736,6 +748,8 @@ message Misc { bool portable_service_running = 20; SwitchSidesRequest switch_sides_request = 21; SwitchBack switch_back = 22; + // Deprecated since 1.2.4, use `change_display_resolution` (36) instead. + // But we must keep it for compatibility when peer version < 1.2.4. Resolution change_resolution = 24; PluginRequest plugin_request = 25; PluginFailure plugin_failure = 26; @@ -748,6 +762,8 @@ message Misc { TogglePrivacyMode toggle_privacy_mode = 33; SupportedEncoding supported_encoding = 34; uint32 selected_sid = 35; + DisplayResolution change_display_resolution = 36; + MessageQuery message_query = 37; } } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 86235dc2f..6ff927796 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -2104,6 +2104,12 @@ pub fn main_check_hwcodec() { check_hwcodec() } +pub fn session_request_new_display_init_msgs(session_id: SessionID, display: usize) { + if let Some(session) = sessions::get_session_by_session_id(&session_id) { + session.request_init_msgs(display); + } +} + #[cfg(target_os = "android")] pub mod server_side { use hbb_common::{config, log}; diff --git a/src/server/connection.rs b/src/server/connection.rs index 8526a998d..69aa52b50 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -2300,7 +2300,11 @@ impl Connection { } } #[cfg(not(any(target_os = "android", target_os = "ios")))] - Some(misc::Union::ChangeResolution(r)) => self.change_resolution(&r), + Some(misc::Union::ChangeResolution(r)) => self.change_resolution(None, &r), + #[cfg(not(any(target_os = "android", target_os = "ios")))] + Some(misc::Union::ChangeDisplayResolution(dr)) => { + self.change_resolution(Some(dr.display as _), &dr.resolution) + } #[cfg(all(feature = "flutter", feature = "plugin_framework"))] #[cfg(not(any(target_os = "android", target_os = "ios")))] Some(misc::Union::PluginRequest(p)) => { @@ -2343,6 +2347,13 @@ impl Connection { } } } + Some(misc::Union::MessageQuery(mq)) => { + if let Some(msg_out) = + video_service::make_display_changed_msg(mq.switch_display as _, None) + { + self.send(msg_out).await; + } + } _ => {} }, Some(message::Union::AudioFrame(frame)) => { @@ -2472,11 +2483,14 @@ impl Connection { #[cfg(not(any(target_os = "android", target_os = "ios")))] if s.width != 0 && s.height != 0 { - self.change_resolution(&Resolution { - width: s.width, - height: s.height, - ..Default::default() - }); + self.change_resolution( + None, + &Resolution { + width: s.width, + height: s.height, + ..Default::default() + }, + ); } } @@ -2623,10 +2637,11 @@ impl Connection { } #[cfg(not(any(target_os = "android", target_os = "ios")))] - fn change_resolution(&mut self, r: &Resolution) { + fn change_resolution(&mut self, d: Option, r: &Resolution) { if self.keyboard { if let Ok(displays) = display_service::try_get_displays() { - if let Some(display) = displays.get(self.display_idx) { + let display_idx = d.unwrap_or(self.display_idx); + if let Some(display) = displays.get(display_idx) { let name = display.name(); #[cfg(all(windows, feature = "virtual_display_driver"))] if let Some(_ok) = @@ -2638,11 +2653,18 @@ impl Connection { { return; } - display_service::set_last_changed_resolution( - &name, - (display.width() as _, display.height() as _), - (r.width, r.height), - ); + let mut record_changed = true; + #[cfg(all(windows, feature = "virtual_display_driver"))] + if virtual_display_manager::amyuni_idd::is_my_display(&name) { + record_changed = false; + } + if record_changed { + display_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/ui_session_interface.rs b/src/ui_session_interface.rs index 44aa6c6b6..61c11feb0 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -1222,7 +1222,7 @@ impl Session { 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); + self.do_change_resolution(display, width, height); } #[inline] @@ -1232,13 +1232,22 @@ impl Session { } } - fn do_change_resolution(&self, width: i32, height: i32) { + fn do_change_resolution(&self, display: i32, width: i32, height: i32) { let mut misc = Misc::new(); - misc.set_change_resolution(Resolution { + let resolution = Resolution { width, height, ..Default::default() - }); + }; + if crate::common::is_support_multi_ui_session_num(self.lc.read().unwrap().version) { + misc.set_change_display_resolution(DisplayResolution { + display, + resolution: Some(resolution).into(), + ..Default::default() + }); + } else { + misc.set_change_resolution(resolution); + } let mut msg = Message::new(); msg.set_misc(misc); self.send(Data::Message(msg)); @@ -1293,6 +1302,22 @@ impl Session { log::error!("selected invalid sid: {}", sid); } } + + #[inline] + pub fn request_init_msgs(&self, display: usize) { + self.send_message_query(display); + } + + fn send_message_query(&self, display: usize) { + let mut misc = Misc::new(); + misc.set_message_query(MessageQuery { + switch_display: display as _, + ..Default::default() + }); + let mut msg = Message::new(); + msg.set_misc(misc); + self.send(Data::Message(msg)); + } } pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default { diff --git a/src/virtual_display_manager.rs b/src/virtual_display_manager.rs index 3188fc33e..1a0a03b01 100644 --- a/src/virtual_display_manager.rs +++ b/src/virtual_display_manager.rs @@ -536,6 +536,13 @@ pub mod amyuni_idd { pub fn get_monitor_count() -> usize { windows::get_device_names(Some(super::AMYUNI_IDD_DEVICE_STRING)).len() } + + #[inline] + pub fn is_my_display(name: &str) -> bool { + windows::get_device_names(Some(super::AMYUNI_IDD_DEVICE_STRING)) + .iter() + .any(|s| windows::is_device_name(s, name)) + } } mod windows {