restore custom resolution for each display

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2023-06-05 18:01:43 +08:00
parent b07ac438f5
commit e670989e0f
7 changed files with 132 additions and 36 deletions

View File

@ -995,7 +995,7 @@ class _ResolutionsMenu extends StatefulWidget {
State<_ResolutionsMenu> createState() => _ResolutionsMenuState(); State<_ResolutionsMenu> createState() => _ResolutionsMenuState();
} }
const double _kCustonResolutionEditingWidth = 42; const double _kCustomResolutionEditingWidth = 42;
const _kCustomResolutionValue = 'custom'; const _kCustomResolutionValue = 'custom';
class _ResolutionsMenuState extends State<_ResolutionsMenu> { class _ResolutionsMenuState extends State<_ResolutionsMenu> {
@ -1102,6 +1102,7 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
_changeResolution(int w, int h) async { _changeResolution(int w, int h) async {
await bind.sessionChangeResolution( await bind.sessionChangeResolution(
id: widget.id, id: widget.id,
display: pi.currentDisplay,
width: w, width: w,
height: h, height: h,
); );
@ -1157,12 +1158,12 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
children: [ children: [
Text('${translate('resolution_custom_tip')} '), Text('${translate('resolution_custom_tip')} '),
SizedBox( SizedBox(
width: _kCustonResolutionEditingWidth, width: _kCustomResolutionEditingWidth,
child: _resolutionInput(_customWidth), child: _resolutionInput(_customWidth),
), ),
Text(' x '), Text(' x '),
SizedBox( SizedBox(
width: _kCustonResolutionEditingWidth, width: _kCustomResolutionEditingWidth,
child: _resolutionInput(_customHeight), child: _resolutionInput(_customHeight),
), ),
], ],

View File

@ -262,10 +262,10 @@ pub struct PeerConfig {
#[serde( #[serde(
default, default,
skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_hashmap_resolutions",
deserialize_with = "deserialize_option_resolution" skip_serializing_if = "HashMap::is_empty",
)] )]
pub custom_resolution: Option<Resolution>, pub custom_resolutions: HashMap<i32, Resolution>,
// The other scalar value must before this // The other scalar value must before this
#[serde(default, deserialize_with = "PeerConfig::deserialize_options")] #[serde(default, deserialize_with = "PeerConfig::deserialize_options")]
@ -1509,7 +1509,7 @@ deserialize_default!(deserialize_option_string, Option<String>);
deserialize_default!(deserialize_hashmap_string_string, HashMap<String, String>); deserialize_default!(deserialize_hashmap_string_string, HashMap<String, String>);
deserialize_default!(deserialize_hashmap_string_bool, HashMap<String, bool>); deserialize_default!(deserialize_hashmap_string_bool, HashMap<String, bool>);
deserialize_default!(deserialize_hashmap_string_configoidcprovider, HashMap<String, ConfigOidcProvider>); deserialize_default!(deserialize_hashmap_string_configoidcprovider, HashMap<String, ConfigOidcProvider>);
deserialize_default!(deserialize_option_resolution, Option<Resolution>); deserialize_default!(deserialize_hashmap_resolutions, HashMap<i32, Resolution>);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -1353,7 +1353,9 @@ impl LoginConfigHandler {
/// ///
/// * `ignore_default` - If `true`, ignore the default value of the option. /// * `ignore_default` - If `true`, ignore the default value of the option.
fn get_option_message(&self, ignore_default: bool) -> Option<OptionMessage> { fn get_option_message(&self, ignore_default: bool) -> Option<OptionMessage> {
if self.conn_type.eq(&ConnType::FILE_TRANSFER) || self.conn_type.eq(&ConnType::PORT_FORWARD) || self.conn_type.eq(&ConnType::RDP) if self.conn_type.eq(&ConnType::FILE_TRANSFER)
|| self.conn_type.eq(&ConnType::PORT_FORWARD)
|| self.conn_type.eq(&ConnType::RDP)
{ {
return None; return None;
} }
@ -1402,7 +1404,7 @@ impl LoginConfigHandler {
msg.disable_clipboard = BoolOption::Yes.into(); msg.disable_clipboard = BoolOption::Yes.into();
n += 1; n += 1;
} }
if let Some(r) = self.get_custom_resolution() { if let Some(r) = self.get_custom_resolution(0) {
if r.0 > 0 && r.1 > 0 { if r.0 > 0 && r.1 > 0 {
msg.custom_resolution = Some(ProtoResolution { msg.custom_resolution = Some(ProtoResolution {
width: r.0, width: r.0,
@ -1424,7 +1426,9 @@ impl LoginConfigHandler {
} }
pub fn get_option_message_after_login(&self) -> Option<OptionMessage> { pub fn get_option_message_after_login(&self) -> Option<OptionMessage> {
if self.conn_type.eq(&ConnType::FILE_TRANSFER) || self.conn_type.eq(&ConnType::PORT_FORWARD) || self.conn_type.eq(&ConnType::RDP) if self.conn_type.eq(&ConnType::FILE_TRANSFER)
|| self.conn_type.eq(&ConnType::PORT_FORWARD)
|| self.conn_type.eq(&ConnType::RDP)
{ {
return None; return None;
} }
@ -1584,14 +1588,26 @@ impl LoginConfigHandler {
} }
#[inline] #[inline]
pub fn get_custom_resolution(&self) -> Option<(i32, i32)> { pub fn get_custom_resolution(&self, display: i32) -> Option<(i32, i32)> {
self.config.custom_resolution.as_ref().map(|r| (r.w, r.h)) self.config
.custom_resolutions
.get(&display)
.map(|r| (r.w, r.h))
} }
#[inline] #[inline]
pub fn set_custom_resolution(&mut self, wh: Option<(i32, i32)>) { pub fn set_custom_resolution(&mut self, display: i32, wh: Option<(i32, i32)>) {
let mut config = self.load_config(); let mut config = self.load_config();
config.custom_resolution = wh.map(|r| Resolution { w: r.0, h: r.1 }); match wh {
Some((w, h)) => {
config
.custom_resolutions
.insert(display, Resolution { w, h });
}
None => {
config.custom_resolutions.remove(&display);
}
}
self.save_config(config); self.save_config(config);
} }

View File

@ -1201,7 +1201,7 @@ impl<T: InvokeUiSession> Remote<T> {
} }
} }
Some(misc::Union::SwitchDisplay(s)) => { Some(misc::Union::SwitchDisplay(s)) => {
self.handler.ui_handler.switch_display(&s); self.handler.handle_peer_switch_display(&s);
self.video_sender.send(MediaData::Reset).ok(); self.video_sender.send(MediaData::Reset).ok();
if s.width > 0 && s.height > 0 { if s.width > 0 && s.height > 0 {
self.handler.set_display( self.handler.set_display(
@ -1212,14 +1212,6 @@ impl<T: InvokeUiSession> Remote<T> {
s.cursor_embedded, s.cursor_embedded,
); );
} }
let custom_resolution = if s.width != s.original_resolution.width
|| s.height != s.original_resolution.height
{
Some((s.width, s.height))
} else {
None
};
self.handler.set_custom_resolution(custom_resolution);
} }
Some(misc::Union::CloseReason(c)) => { Some(misc::Union::CloseReason(c)) => {
self.handler.msgbox("error", "Connection Error", &c, ""); self.handler.msgbox("error", "Connection Error", &c, "");

View File

@ -535,9 +535,9 @@ pub fn session_switch_sides(id: String) {
} }
} }
pub fn session_change_resolution(id: String, width: i32, height: i32) { pub fn session_change_resolution(id: String, display: i32, width: i32, height: i32) {
if let Some(session) = SESSIONS.read().unwrap().get(&id) { if let Some(session) = SESSIONS.read().unwrap().get(&id) {
session.change_resolution(width, height); session.change_resolution(display, width, height);
} }
} }

View File

@ -1793,6 +1793,14 @@ impl Connection {
Some(message::Union::Misc(misc)) => match misc.union { Some(message::Union::Misc(misc)) => match misc.union {
Some(misc::Union::SwitchDisplay(s)) => { Some(misc::Union::SwitchDisplay(s)) => {
video_service::switch_display(s.display).await; video_service::switch_display(s.display).await;
#[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()
});
}
} }
Some(misc::Union::ChatMessage(c)) => { Some(misc::Union::ChatMessage(c)) => {
self.send_to_cm(ipc::Data::ChatMessage { text: c.text }); self.send_to_cm(ipc::Data::ChatMessage { text: c.text });
@ -2159,12 +2167,16 @@ impl Connection {
} }
} }
} }
// Custom resolution here is only valid in the process of establishing a connection.
// After the connection is established, the resolution is changed by another message.
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
if let Some(custom_resolution) = o.custom_resolution.as_ref() { if let Some(custom_resolution) = o.custom_resolution.as_ref() {
if Self::alive_conns().len() > 0 {
if custom_resolution.width > 0 && custom_resolution.height > 0 { if custom_resolution.width > 0 && custom_resolution.height > 0 {
self.change_resolution(&custom_resolution); self.change_resolution(&custom_resolution);
} }
} }
}
if self.keyboard { if self.keyboard {
if let Ok(q) = o.block_input.enum_value() { if let Ok(q) = o.block_input.enum_value() {
match q { match q {

View File

@ -15,13 +15,21 @@ use bytes::Bytes;
use rdev::{Event, EventType::*, KeyCode}; use rdev::{Event, EventType::*, KeyCode};
use uuid::Uuid; use uuid::Uuid;
use hbb_common::config::{Config, LocalConfig, PeerConfig};
#[cfg(not(feature = "flutter"))] #[cfg(not(feature = "flutter"))]
use hbb_common::fs; use hbb_common::fs;
use hbb_common::rendezvous_proto::ConnType; use hbb_common::{
use hbb_common::tokio::{self, sync::mpsc}; allow_err,
use hbb_common::{allow_err, message_proto::*}; config::{Config, LocalConfig, PeerConfig},
use hbb_common::{get_version_number, log, Stream}; get_version_number, log,
message_proto::*,
rendezvous_proto::ConnType,
tokio::{
self,
sync::mpsc,
time::{Duration as TokioDuration, Instant},
},
Stream,
};
use crate::client::io_loop::Remote; use crate::client::io_loop::Remote;
use crate::client::{ use crate::client::{
@ -37,6 +45,8 @@ use crate::{client::Data, client::Interface};
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
pub static IS_IN: AtomicBool = AtomicBool::new(false); pub static IS_IN: AtomicBool = AtomicBool::new(false);
const CHANGE_RESOLUTION_VALID_TIMEOUT_SECS: u64 = 15;
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct Session<T: InvokeUiSession> { pub struct Session<T: InvokeUiSession> {
pub id: String, pub id: String,
@ -49,6 +59,7 @@ pub struct Session<T: InvokeUiSession> {
pub server_keyboard_enabled: Arc<RwLock<bool>>, pub server_keyboard_enabled: Arc<RwLock<bool>>,
pub server_file_transfer_enabled: Arc<RwLock<bool>>, pub server_file_transfer_enabled: Arc<RwLock<bool>>,
pub server_clipboard_enabled: Arc<RwLock<bool>>, pub server_clipboard_enabled: Arc<RwLock<bool>>,
pub last_change_display: Arc<Mutex<ChangeDisplayRecord>>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -59,6 +70,43 @@ pub struct SessionPermissionConfig {
pub server_clipboard_enabled: Arc<RwLock<bool>>, pub server_clipboard_enabled: Arc<RwLock<bool>>,
} }
pub struct ChangeDisplayRecord {
time: Instant,
display: i32,
width: i32,
height: i32,
}
impl Default for ChangeDisplayRecord {
fn default() -> Self {
Self {
time: Instant::now()
- TokioDuration::from_secs(CHANGE_RESOLUTION_VALID_TIMEOUT_SECS + 1),
display: 0,
width: 0,
height: 0,
}
}
}
impl ChangeDisplayRecord {
fn new(display: i32, width: i32, height: i32) -> Self {
Self {
time: Instant::now(),
display,
width,
height,
}
}
pub fn is_the_same_record(&self, display: i32, width: i32, height: i32) -> bool {
self.time.elapsed().as_secs() < CHANGE_RESOLUTION_VALID_TIMEOUT_SECS
&& self.display == display
&& self.width == width
&& self.height == height
}
}
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
impl SessionPermissionConfig { impl SessionPermissionConfig {
pub fn is_text_clipboard_required(&self) -> bool { pub fn is_text_clipboard_required(&self) -> bool {
@ -485,9 +533,16 @@ impl<T: InvokeUiSession> Session<T> {
} }
pub fn switch_display(&self, display: i32) { pub fn switch_display(&self, display: i32) {
let (w, h) = match self.lc.read().unwrap().get_custom_resolution(display) {
Some((w, h)) => (w, h),
None => (0, 0),
};
let mut misc = Misc::new(); let mut misc = Misc::new();
misc.set_switch_display(SwitchDisplay { misc.set_switch_display(SwitchDisplay {
display, display,
width: w,
height: h,
..Default::default() ..Default::default()
}); });
let mut msg_out = Message::new(); let mut msg_out = Message::new();
@ -831,12 +886,32 @@ impl<T: InvokeUiSession> Session<T> {
} }
} }
#[inline] pub fn handle_peer_switch_display(&self, display: &SwitchDisplay) {
pub fn set_custom_resolution(&mut self, wh: Option<(i32, i32)>) { self.ui_handler.switch_display(display);
self.lc.write().unwrap().set_custom_resolution(wh);
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
};
self.lc
.write()
.unwrap()
.set_custom_resolution(display.display, custom_resolution);
}
} }
pub fn change_resolution(&self, width: i32, height: i32) { pub fn change_resolution(&self, display: i32, width: i32, height: i32) {
*self.last_change_display.lock().unwrap() =
ChangeDisplayRecord::new(display, width, height);
let mut misc = Misc::new(); let mut misc = Misc::new();
misc.set_change_resolution(Resolution { misc.set_change_resolution(Resolution {
width, width,