refactor resolution, mid commit

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2023-05-17 23:19:20 +08:00
parent 154b86d2a5
commit a603e046e3
9 changed files with 196 additions and 55 deletions

View File

@ -29,6 +29,10 @@ const _kKeyLegacyMode = 'legacy';
const _kKeyMapMode = 'map'; const _kKeyMapMode = 'map';
const _kKeyTranslateMode = 'translate'; const _kKeyTranslateMode = 'translate';
const _kResolutionOrigin = 'Origin';
const _kResolutionCustom = 'Custom';
const _kResolutionFitLocal = 'FitLocal';
class MenubarState { class MenubarState {
final kStoreKey = 'remoteMenubarState'; final kStoreKey = 'remoteMenubarState';
late RxBool show; late RxBool show;
@ -692,6 +696,8 @@ class _DisplayMenuState extends State<_DisplayMenu> {
int get windowId => stateGlobal.windowId; int get windowId => stateGlobal.windowId;
Map<String, bool> get perms => widget.ffi.ffiModel.permissions; Map<String, bool> get perms => widget.ffi.ffiModel.permissions;
RxBool _isOrignalResolution = true.obs;
RxBool _isFitLocalResolution = false.obs;
PeerInfo get pi => widget.ffi.ffiModel.pi; PeerInfo get pi => widget.ffi.ffiModel.pi;
FfiModel get ffiModel => widget.ffi.ffiModel; FfiModel get ffiModel => widget.ffi.ffiModel;
@ -943,6 +949,7 @@ class _DisplayMenuState extends State<_DisplayMenu> {
final groupValue = "${display.width}x${display.height}"; final groupValue = "${display.width}x${display.height}";
onChanged(String? value) async { onChanged(String? value) async {
if (value == null) return; if (value == null) return;
final list = value.split('x'); final list = value.split('x');
if (list.length == 2) { if (list.length == 2) {
final w = int.tryParse(list[0]); final w = int.tryParse(list[0]);
@ -964,14 +971,37 @@ class _DisplayMenuState extends State<_DisplayMenu> {
return _SubmenuButton( return _SubmenuButton(
ffi: widget.ffi, ffi: widget.ffi,
menuChildren: resolutions menuChildren: [
.map((e) => RdoMenuButton( RdoMenuButton(
value: '${e.width}x${e.height}', value: _kResolutionOrigin,
groupValue: groupValue, groupValue: groupValue,
onChanged: onChanged, onChanged: onChanged,
ffi: widget.ffi, ffi: widget.ffi,
child: Text('${e.width}x${e.height}'))) child: Text('Origin'),
.toList(), ),
RdoMenuButton(
value: _kResolutionFitLocal,
groupValue: groupValue,
onChanged: onChanged,
ffi: widget.ffi,
child: Text('Fit local'),
),
// RdoMenuButton(
// value: _kResolutionCustom,
// groupValue: groupValue,
// onChanged: onChanged,
// ffi: widget.ffi,
// child: Text('Custom resolution'),
// ),
] +
resolutions
.map((e) => RdoMenuButton(
value: '${e.width}x${e.height}',
groupValue: groupValue,
onChanged: onChanged,
ffi: widget.ffi,
child: Text('${e.width}x${e.height}')))
.toList(),
child: Text(translate("Resolution"))); child: Text(translate("Resolution")));
} }

View File

@ -41,6 +41,7 @@ message DisplayInfo {
string name = 5; string name = 5;
bool online = 6; bool online = 6;
bool cursor_embedded = 7; bool cursor_embedded = 7;
Resolution original_resolution = 8;
} }
message PortForward { message PortForward {
@ -444,6 +445,8 @@ message SwitchDisplay {
int32 height = 5; int32 height = 5;
bool cursor_embedded = 6; bool cursor_embedded = 6;
SupportedResolutions resolutions = 7; SupportedResolutions resolutions = 7;
// Do not care about the origin point for now.
Resolution original_resolution = 8;
} }
message PermissionInfo { message PermissionInfo {
@ -501,6 +504,7 @@ message OptionMessage {
SupportedDecoding supported_decoding = 10; SupportedDecoding supported_decoding = 10;
int32 custom_fps = 11; int32 custom_fps = 11;
BoolOption disable_keyboard = 12; BoolOption disable_keyboard = 12;
Resolution custom_resolution = 13;
} }
message TestDelay { message TestDelay {

View File

@ -191,6 +191,12 @@ pub struct Config2 {
pub options: HashMap<String, String>, pub options: HashMap<String, String>,
} }
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct Resolution {
pub w: i32,
pub h: i32,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] #[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct PeerConfig { pub struct PeerConfig {
#[serde(default, deserialize_with = "deserialize_vec_u8")] #[serde(default, deserialize_with = "deserialize_vec_u8")]
@ -246,6 +252,9 @@ pub struct PeerConfig {
#[serde(flatten)] #[serde(flatten)]
pub view_only: ViewOnly, pub view_only: ViewOnly,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub custom_resolution: Option<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")]
pub options: HashMap<String, String>, // not use delete to represent default values pub options: HashMap<String, String>, // not use delete to represent default values

View File

@ -31,9 +31,11 @@ use hbb_common::{
allow_err, allow_err,
anyhow::{anyhow, Context}, anyhow::{anyhow, Context},
bail, bail,
config::{Config, PeerConfig, PeerInfoSerde, CONNECT_TIMEOUT, READ_TIMEOUT, RELAY_PORT}, config::{
Config, PeerConfig, PeerInfoSerde, Resolution, CONNECT_TIMEOUT, READ_TIMEOUT, RELAY_PORT,
},
get_version_number, log, get_version_number, log,
message_proto::{option_message::BoolOption, *}, message_proto::{option_message::BoolOption, Resolution as ProtoResolution, *},
protobuf::Message as _, protobuf::Message as _,
rand, rand,
rendezvous_proto::*, rendezvous_proto::*,
@ -1400,6 +1402,16 @@ 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 r.0 > 0 && r.1 > 0 {
msg.custom_resolution = Some(ProtoResolution {
width: r.0,
height: r.1,
..Default::default()
})
.into();
}
}
msg.supported_decoding = msg.supported_decoding =
hbb_common::protobuf::MessageField::some(Decoder::supported_decodings(Some(&self.id))); hbb_common::protobuf::MessageField::some(Decoder::supported_decodings(Some(&self.id)));
n += 1; n += 1;
@ -1571,6 +1583,18 @@ impl LoginConfigHandler {
} }
} }
#[inline]
pub fn get_custom_resolution(&self) -> Option<(i32, i32)> {
self.config.custom_resolution.as_ref().map(|r| (r.w, r.h))
}
#[inline]
pub fn set_custom_resolution(&mut self, wh: Option<(i32, i32)>) {
let mut config = self.load_config();
config.custom_resolution = wh.map(|r| Resolution { w: r.0, h: r.1 });
self.save_config(config);
}
/// Get user name. /// Get user name.
/// Return the name of the given peer. If the peer has no name, return the name in the config. /// Return the name of the given peer. If the peer has no name, return the name in the config.
/// ///

View File

@ -1,10 +1,10 @@
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
use crate::platform::breakdown_callback; use crate::platform::breakdown_callback;
use hbb_common::log;
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
use hbb_common::platform::register_breakdown_handler; use hbb_common::platform::register_breakdown_handler;
use hbb_common::{allow_err, log};
/// shared by flutter and sciter main function /// shared by flutter and sciter main function
/// ///
@ -270,7 +270,7 @@ fn init_plugins(args: &Vec<String>) {
crate::plugin::init(); crate::plugin::init();
} }
} else if "--service" == (&args[0] as &str) { } else if "--service" == (&args[0] as &str) {
allow_err!(crate::plugin::remove_uninstalled()); hbb_common::allow_err!(crate::plugin::remove_uninstalled());
} }
} }

View File

@ -1888,6 +1888,10 @@ pub fn change_resolution(name: &str, width: usize, height: usize) -> ResultType<
if FALSE == EnumDisplaySettingsW(NULL as _, ENUM_CURRENT_SETTINGS, &mut dm) { if FALSE == EnumDisplaySettingsW(NULL as _, ENUM_CURRENT_SETTINGS, &mut dm) {
bail!("EnumDisplaySettingsW failed, errno={}", GetLastError()); bail!("EnumDisplaySettingsW failed, errno={}", GetLastError());
} }
// to-do: check if need change
println!("REMOVE ME ========================== dm ({},{}) to ({},{})", dm.dmPelsWidth, dm.dmPelsHeight, width, height);
let wname = wide_string(name); let wname = wide_string(name);
let len = if wname.len() <= dm.dmDeviceName.len() { let len = if wname.len() <= dm.dmDeviceName.len() {
wname.len() wname.len()

View File

@ -179,8 +179,6 @@ pub struct Connection {
#[cfg(windows)] #[cfg(windows)]
portable: PortableState, portable: PortableState,
from_switch: bool, from_switch: bool,
#[cfg(not(any(target_os = "android", target_os = "ios")))]
origin_resolution: HashMap<String, Resolution>,
voice_call_request_timestamp: Option<NonZeroI64>, voice_call_request_timestamp: Option<NonZeroI64>,
audio_input_device_before_voice_call: Option<String>, audio_input_device_before_voice_call: Option<String>,
options_in_login: Option<OptionMessage>, options_in_login: Option<OptionMessage>,
@ -306,8 +304,6 @@ impl Connection {
#[cfg(windows)] #[cfg(windows)]
portable: Default::default(), portable: Default::default(),
from_switch: false, from_switch: false,
#[cfg(not(any(target_os = "android", target_os = "ios")))]
origin_resolution: Default::default(),
audio_sender: None, audio_sender: None,
voice_call_request_timestamp: None, voice_call_request_timestamp: None,
audio_input_device_before_voice_call: None, audio_input_device_before_voice_call: None,
@ -631,15 +627,18 @@ impl Connection {
conn.post_conn_audit(json!({ conn.post_conn_audit(json!({
"action": "close", "action": "close",
})); }));
#[cfg(not(any(target_os = "android", target_os = "ios")))] let mut active_conns_lock = ALIVE_CONNS.lock().unwrap();
conn.reset_resolution(); active_conns_lock.retain(|&c| c != id);
ALIVE_CONNS.lock().unwrap().retain(|&c| c != id);
if let Some(s) = conn.server.upgrade() { if let Some(s) = conn.server.upgrade() {
let mut s = s.write().unwrap(); let mut s = s.write().unwrap();
s.remove_connection(&conn.inner); s.remove_connection(&conn.inner);
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
try_stop_record_cursor_pos(); try_stop_record_cursor_pos();
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))]
if active_conns_lock.is_empty() {
video_service::reset_resolutions();
}
log::info!("#{} connection loop exited", id); log::info!("#{} connection loop exited", id);
} }
@ -1893,25 +1892,7 @@ impl Connection {
} }
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
Some(misc::Union::ChangeResolution(r)) => { Some(misc::Union::ChangeResolution(r)) => self.change_resolution(&r),
if self.keyboard {
if let Ok(name) = video_service::get_current_display_name() {
if let Ok(current) = crate::platform::current_resolution(&name) {
if let Err(e) = crate::platform::change_resolution(
&name,
r.width as _,
r.height as _,
) {
log::error!("change resolution failed:{:?}", e);
} else {
if !self.origin_resolution.contains_key(&name) {
self.origin_resolution.insert(name, current);
}
}
}
}
}
}
#[cfg(all(feature = "flutter", feature = "plugin_framework"))] #[cfg(all(feature = "flutter", feature = "plugin_framework"))]
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
Some(misc::Union::PluginRequest(p)) => { Some(misc::Union::PluginRequest(p)) => {
@ -1953,6 +1934,24 @@ impl Connection {
true true
} }
fn change_resolution(&mut self, r: &Resolution) {
if self.keyboard {
if let Ok(name) = video_service::get_current_display_name() {
if let Err(e) =
crate::platform::change_resolution(&name, r.width as _, r.height as _)
{
log::error!(
"Failed to change resolution '{}' to ({},{}):{:?}",
&name,
r.width,
r.height,
e
);
}
}
}
}
pub async fn handle_voice_call(&mut self, accepted: bool) { pub async fn handle_voice_call(&mut self, accepted: bool) {
if let Some(ts) = self.voice_call_request_timestamp.take() { if let Some(ts) = self.voice_call_request_timestamp.take() {
let msg = new_voice_call_response(ts.get(), accepted); let msg = new_voice_call_response(ts.get(), accepted);
@ -2147,6 +2146,11 @@ impl Connection {
} }
} }
} }
if let Some(custom_resolution) = o.custom_resolution.as_ref() {
if custom_resolution.width > 0 && custom_resolution.height > 0 {
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 {
@ -2262,20 +2266,6 @@ impl Connection {
} }
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))]
fn reset_resolution(&self) {
self.origin_resolution
.iter()
.map(|(name, r)| {
if let Err(e) =
crate::platform::change_resolution(&name, r.width as _, r.height as _)
{
log::error!("change resolution failed:{:?}", e);
}
})
.count();
}
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
fn release_pressed_modifiers(&mut self) { fn release_pressed_modifiers(&mut self) {
for modifier in self.pressed_modifiers.iter() { for modifier in self.pressed_modifiers.iter() {

View File

@ -62,8 +62,55 @@ lazy_static::lazy_static! {
pub static ref IS_UAC_RUNNING: Arc<Mutex<bool>> = Default::default(); pub static ref IS_UAC_RUNNING: Arc<Mutex<bool>> = Default::default();
pub static ref IS_FOREGROUND_WINDOW_ELEVATED: Arc<Mutex<bool>> = Default::default(); pub static ref IS_FOREGROUND_WINDOW_ELEVATED: Arc<Mutex<bool>> = Default::default();
pub static ref LAST_SYNC_DISPLAYS: Arc<RwLock<Vec<DisplayInfo>>> = Default::default(); pub static ref LAST_SYNC_DISPLAYS: Arc<RwLock<Vec<DisplayInfo>>> = Default::default();
static ref ORIGINAL_RESOLUTIONS: Arc<RwLock<HashMap<String, (i32, i32)>>> = Default::default();
} }
#[inline]
pub 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(),
None => {
original_resolutions.insert(display_name.to_owned(), wh.clone());
wh
}
}
}
#[inline]
fn get_original_resolution(display_name: &str) -> Option<(i32, i32)> {
ORIGINAL_RESOLUTIONS
.read()
.unwrap()
.get(display_name)
.map(|r| r.clone())
}
#[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)
}
#[inline]
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 _) {
log::error!(
"Failed to reset resolution of display '{}' to ({},{}): {}",
name,
w,
h,
e
);
}
}
}
#[inline]
fn is_capturer_mag_supported() -> bool { fn is_capturer_mag_supported() -> bool {
#[cfg(windows)] #[cfg(windows)]
return scrap::CapturerMag::is_supported(); return scrap::CapturerMag::is_supported();
@ -71,22 +118,27 @@ fn is_capturer_mag_supported() -> bool {
false false
} }
#[inline]
pub fn capture_cursor_embedded() -> bool { pub fn capture_cursor_embedded() -> bool {
scrap::is_cursor_embedded() scrap::is_cursor_embedded()
} }
#[inline]
pub fn notify_video_frame_fetched(conn_id: i32, frame_tm: Option<Instant>) { pub fn notify_video_frame_fetched(conn_id: i32, frame_tm: Option<Instant>) {
FRAME_FETCHED_NOTIFIER.0.send((conn_id, frame_tm)).unwrap() FRAME_FETCHED_NOTIFIER.0.send((conn_id, frame_tm)).unwrap()
} }
#[inline]
pub fn set_privacy_mode_conn_id(conn_id: i32) { pub fn set_privacy_mode_conn_id(conn_id: i32) {
*PRIVACY_MODE_CONN_ID.lock().unwrap() = conn_id *PRIVACY_MODE_CONN_ID.lock().unwrap() = conn_id
} }
#[inline]
pub fn get_privacy_mode_conn_id() -> i32 { pub fn get_privacy_mode_conn_id() -> i32 {
*PRIVACY_MODE_CONN_ID.lock().unwrap() *PRIVACY_MODE_CONN_ID.lock().unwrap()
} }
#[inline]
pub fn is_privacy_mode_supported() -> bool { pub fn is_privacy_mode_supported() -> bool {
#[cfg(windows)] #[cfg(windows)]
return *IS_CAPTURER_MAGNIFIER_SUPPORTED return *IS_CAPTURER_MAGNIFIER_SUPPORTED
@ -491,6 +543,10 @@ fn run(sp: GenericService) -> ResultType<()> {
if *SWITCH.lock().unwrap() { if *SWITCH.lock().unwrap() {
log::debug!("Broadcasting display switch"); log::debug!("Broadcasting display switch");
let mut misc = Misc::new(); let mut misc = Misc::new();
let display_name = get_current_display_name();
// to-do: check if is virtual display
misc.set_switch_display(SwitchDisplay { misc.set_switch_display(SwitchDisplay {
display: c.current as _, display: c.current as _,
x: c.origin.0 as _, x: c.origin.0 as _,
@ -500,12 +556,19 @@ fn run(sp: GenericService) -> ResultType<()> {
cursor_embedded: capture_cursor_embedded(), cursor_embedded: capture_cursor_embedded(),
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
resolutions: Some(SupportedResolutions { resolutions: Some(SupportedResolutions {
resolutions: get_current_display_name() resolutions: display_name
.map(|name| crate::platform::resolutions(&name)) .as_ref()
.map(|name| crate::platform::resolutions(name))
.unwrap_or(vec![]), .unwrap_or(vec![]),
..SupportedResolutions::default() ..SupportedResolutions::default()
}) })
.into(), .into(),
original_resolution: Some(update_get_original_resolution(
&display_name.unwrap_or_default(),
c.width,
c.height,
))
.into(),
..Default::default() ..Default::default()
}); });
let mut msg_out = Message::new(); let mut msg_out = Message::new();
@ -820,6 +883,16 @@ pub fn handle_one_frame_encoded(
Ok(send_conn_ids) Ok(send_conn_ids)
} }
#[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()
}
}
pub(super) fn get_displays_2(all: &Vec<Display>) -> (usize, Vec<DisplayInfo>) { pub(super) fn get_displays_2(all: &Vec<Display>) -> (usize, Vec<DisplayInfo>) {
let mut displays = Vec::new(); let mut displays = Vec::new();
let mut primary = 0; let mut primary = 0;
@ -835,6 +908,12 @@ pub(super) fn get_displays_2(all: &Vec<Display>) -> (usize, Vec<DisplayInfo>) {
name: d.name(), name: d.name(),
online: d.is_online(), online: d.is_online(),
cursor_embedded: false, cursor_embedded: false,
original_resolution: Some(update_get_original_resolution(
&d.name(),
d.width(),
d.height(),
))
.into(),
..Default::default() ..Default::default()
}); });
} }

View File

@ -88,10 +88,7 @@ impl<T: InvokeUiSession> Session<T> {
} }
pub fn is_port_forward(&self) -> bool { pub fn is_port_forward(&self) -> bool {
let conn_type = self.lc let conn_type = self.lc.read().unwrap().conn_type;
.read()
.unwrap()
.conn_type;
conn_type == ConnType::PORT_FORWARD || conn_type == ConnType::RDP conn_type == ConnType::PORT_FORWARD || conn_type == ConnType::RDP
} }
@ -833,6 +830,10 @@ impl<T: InvokeUiSession> Session<T> {
} }
pub fn change_resolution(&self, width: i32, height: i32) { pub fn change_resolution(&self, width: i32, height: i32) {
self.lc
.write()
.unwrap()
.set_custom_resolution(Some((width, height)));
let mut misc = Misc::new(); let mut misc = Misc::new();
misc.set_change_resolution(Resolution { misc.set_change_resolution(Resolution {
width, width,