remember resolution, mid commit

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2023-05-18 21:25:48 +08:00
parent 07500013ff
commit c6ccee67aa
4 changed files with 165 additions and 93 deletions

View File

@ -1019,17 +1019,22 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final visible = ffiModel.keyboard && resolutions.length > 1; final isVirtualDisplay = display.isVirtualDisplayResolution;
final visible =
ffiModel.keyboard && (isVirtualDisplay || resolutions.length > 1);
if (!visible) return Offstage(); if (!visible) return Offstage();
_groupValue = "${display.width}x${display.height}"; _groupValue = '${display.width}x${display.height}';
_getLocalResolution(); _getLocalResolution();
final showOriginalBtn =
display.isOriginalResolutionSet && !display.isOriginalResolution;
final showFitLocalBtn = !_isRemoteResolutionFitLocal();
return _SubmenuButton( return _SubmenuButton(
ffi: widget.ffi, ffi: widget.ffi,
menuChildren: <Widget>[ menuChildren: <Widget>[
_OriginalResolutionMenuButton(), _OriginalResolutionMenuButton(showOriginalBtn),
_FitLocalResolutionMenuButton(), _FitLocalResolutionMenuButton(showFitLocalBtn),
_customResolutionMenuButton(), _customResolutionMenuButton(isVirtualDisplay),
] + ] +
_supportedResolutionMenuButtons(), _supportedResolutionMenuButtons(),
child: Text(translate("Resolution"))); child: Text(translate("Resolution")));
@ -1065,8 +1070,6 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
h = resolution.height; h = resolution.height;
} }
} else if (value == _kResolutionCustom) { } else if (value == _kResolutionCustom) {
debugPrint(
'REMOVE ME ======================= ${_customWidth.value} ${_customHeight.value}');
w = int.tryParse(_customWidth.value as String); w = int.tryParse(_customWidth.value as String);
h = int.tryParse(_customHeight.value as String); h = int.tryParse(_customHeight.value as String);
} else { } else {
@ -1094,9 +1097,9 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
} }
} }
Widget _OriginalResolutionMenuButton() { Widget _OriginalResolutionMenuButton(bool showOriginalBtn) {
return Offstage( return Offstage(
offstage: display.isOriginalResolution, offstage: !showOriginalBtn,
child: RdoMenuButton( child: RdoMenuButton(
value: _kResolutionOrigin, value: _kResolutionOrigin,
groupValue: _groupValue, groupValue: _groupValue,
@ -1108,16 +1111,16 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
); );
} }
Widget _FitLocalResolutionMenuButton() { Widget _FitLocalResolutionMenuButton(bool showFitLocalBtn) {
return Offstage( return Offstage(
offstage: _isRemoteResolutionFitLocal(), offstage: !showFitLocalBtn,
child: RdoMenuButton( child: RdoMenuButton(
value: _kResolutionFitLocal, value: _kResolutionFitLocal,
groupValue: _groupValue, groupValue: _groupValue,
onChanged: _onChanged, onChanged: _onChanged,
ffi: widget.ffi, ffi: widget.ffi,
child: Text( child: Text(
'${translate('Fit Local')} ${display.originalWidth}x${display.originalHeight}'), '${translate('Fit Local')} ${_localResolution?.width ?? 0}x${_localResolution?.height ?? 0}'),
), ),
); );
} }
@ -1131,9 +1134,9 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
child: Text('${e.width}x${e.height}'))) child: Text('${e.width}x${e.height}')))
.toList(); .toList();
Widget _customResolutionMenuButton() { Widget _customResolutionMenuButton(bool showCustomBtn) {
return Offstage( return Offstage(
offstage: _isRemoteResolutionFitLocal(), offstage: !showCustomBtn,
child: RdoMenuButton( child: RdoMenuButton(
value: _kResolutionCustom, value: _kResolutionCustom,
groupValue: _groupValue, groupValue: _groupValue,
@ -1148,18 +1151,18 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
return Column( return Column(
children: [ children: [
Text(translate('Custom')), Text(translate('Custom')),
SizedBox( Container(
width: 5, width: 5,
), ),
_resolutionInput(_customWidth), // _resolutionInput(_customWidth),
SizedBox( Container(
width: 3, width: 3,
), ),
Text('x'), Text('x'),
SizedBox( Container(
width: 3, width: 3,
), ),
_resolutionInput(_customHeight), // _resolutionInput(_customHeight),
], ],
); );
} }
@ -1185,24 +1188,24 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
return null; return null;
} }
if (display.isVirtualDisplayResolution) {
return _localResolution!;
}
squareDistance(Resolution lhs, Resolution rhs) => squareDistance(Resolution lhs, Resolution rhs) =>
(lhs.width - rhs.width) * (lhs.width - rhs.width) + (lhs.width - rhs.width) * (lhs.width - rhs.width) +
(lhs.height - rhs.height) * (lhs.height - rhs.height); (lhs.height - rhs.height) * (lhs.height - rhs.height);
Resolution? res; Resolution res = Resolution(display.width, display.height);
for (final r in resolutions) { for (final r in resolutions) {
if (r.width <= _localResolution!.width && if (r.width <= _localResolution!.width &&
r.height <= _localResolution!.height) { r.height <= _localResolution!.height) {
if (res == null) {
res = r;
} else {
if (squareDistance(r, _localResolution!) < if (squareDistance(r, _localResolution!) <
squareDistance(res, _localResolution!)) { squareDistance(res, _localResolution!)) {
res = r; res = r;
} }
} }
} }
}
return res; return res;
} }

View File

@ -301,9 +301,9 @@ class FfiModel with ChangeNotifier {
newDisplay.height = int.tryParse(evt['height']) ?? newDisplay.height; newDisplay.height = int.tryParse(evt['height']) ?? newDisplay.height;
newDisplay.cursorEmbedded = int.tryParse(evt['cursor_embedded']) == 1; newDisplay.cursorEmbedded = int.tryParse(evt['cursor_embedded']) == 1;
newDisplay.originalWidth = newDisplay.originalWidth =
int.tryParse(evt['original_width']) ?? newDisplay.originalWidth; int.tryParse(evt['original_width']) ?? kInvalidResolutionValue;
newDisplay.originalHeight = newDisplay.originalHeight =
int.tryParse(evt['original_height']) ?? newDisplay.originalHeight; int.tryParse(evt['original_height']) ?? kInvalidResolutionValue;
_updateCurDisplay(peerId, newDisplay); _updateCurDisplay(peerId, newDisplay);
@ -537,8 +537,8 @@ class FfiModel with ChangeNotifier {
d.width = evt['width'] ?? d.width; d.width = evt['width'] ?? d.width;
d.height = evt['height'] ?? d.height; d.height = evt['height'] ?? d.height;
d.cursorEmbedded = evt['cursor_embedded'] == 1; d.cursorEmbedded = evt['cursor_embedded'] == 1;
d.originalWidth = evt['original_width'] ?? d.originalWidth; d.originalWidth = evt['original_width'] ?? kInvalidResolutionValue;
d.originalHeight = evt['original_height'] ?? d.originalHeight; d.originalHeight = evt['original_height'] ?? kInvalidResolutionValue;
return d; return d;
} }
@ -1714,14 +1714,17 @@ class FFI {
} }
} }
const kInvalidResolutionValue = -1;
const kVirtualDisplayResolutionValue = 0;
class Display { class Display {
double x = 0; double x = 0;
double y = 0; double y = 0;
int width = 0; int width = 0;
int height = 0; int height = 0;
bool cursorEmbedded = false; bool cursorEmbedded = false;
int originalWidth = 0; int originalWidth = kInvalidResolutionValue;
int originalHeight = 0; int originalHeight = kInvalidResolutionValue;
Display() { Display() {
width = (isDesktop || isWebDesktop) width = (isDesktop || isWebDesktop)
@ -1745,6 +1748,12 @@ class Display {
other.height == height && other.height == height &&
other.cursorEmbedded == cursorEmbedded; other.cursorEmbedded == cursorEmbedded;
bool get isOriginalResolutionSet =>
originalWidth != kInvalidResolutionValue &&
originalHeight != kInvalidResolutionValue;
bool get isVirtualDisplayResolution =>
originalWidth == kVirtualDisplayResolutionValue &&
originalHeight == kVirtualDisplayResolutionValue;
bool get isOriginalResolution => bool get isOriginalResolution =>
width == originalWidth && height == originalHeight; width == originalWidth && height == originalHeight;
} }

View File

@ -56,6 +56,10 @@ use windows_service::{
use winreg::enums::*; use winreg::enums::*;
use winreg::RegKey; use winreg::RegKey;
// This string is defined here.
// https://github.com/fufesou/RustDeskIddDriver/blob/b370aad3f50028b039aad211df60c8051c4a64d6/RustDeskIddDriver/RustDeskIddDriver.inf#LL73C1-L73C40
const IDD_DEVICE_STRING: &'static str = "RustDeskIddDriver Device\0";
pub fn get_cursor_pos() -> Option<(i32, i32)> { pub fn get_cursor_pos() -> Option<(i32, i32)> {
unsafe { unsafe {
#[allow(invalid_value)] #[allow(invalid_value)]
@ -1831,21 +1835,25 @@ pub fn set_path_permission(dir: &PathBuf, permission: &str) -> ResultType<()> {
Ok(()) Ok(())
} }
#[inline]
fn str_to_device_name(name: &str) -> [u16; 32] {
let mut device_name: Vec<u16> = wide_string(name);
if device_name.len() < 32 {
device_name.resize(32, 0);
}
let mut result = [0; 32];
result.copy_from_slice(&device_name[..32]);
result
}
pub fn resolutions(name: &str) -> Vec<Resolution> { pub fn resolutions(name: &str) -> Vec<Resolution> {
unsafe { unsafe {
let mut dm: DEVMODEW = std::mem::zeroed(); let mut dm: DEVMODEW = std::mem::zeroed();
let wname = wide_string(name);
let len = if wname.len() <= dm.dmDeviceName.len() {
wname.len()
} else {
dm.dmDeviceName.len()
};
std::ptr::copy_nonoverlapping(wname.as_ptr(), dm.dmDeviceName.as_mut_ptr(), len);
dm.dmSize = std::mem::size_of::<DEVMODEW>() as _;
let mut v = vec![]; let mut v = vec![];
let mut num = 0; let mut num = 0;
let device_name = str_to_device_name(name);
loop { loop {
if EnumDisplaySettingsW(NULL as _, num, &mut dm) == 0 { if EnumDisplaySettingsW(device_name.as_ptr(), num, &mut dm) == 0 {
break; break;
} }
let r = Resolution { let r = Resolution {
@ -1866,8 +1874,8 @@ pub fn current_resolution(name: &str) -> ResultType<Resolution> {
unsafe { unsafe {
let mut dm: DEVMODEW = std::mem::zeroed(); let mut dm: DEVMODEW = std::mem::zeroed();
dm.dmSize = std::mem::size_of::<DEVMODEW>() as _; dm.dmSize = std::mem::size_of::<DEVMODEW>() as _;
let wname = wide_string(name); let device_name = str_to_device_name(name);
if EnumDisplaySettingsW(wname.as_ptr(), ENUM_CURRENT_SETTINGS, &mut dm) == 0 { if EnumDisplaySettingsW(device_name.as_ptr(), ENUM_CURRENT_SETTINGS, &mut dm) == 0 {
bail!( bail!(
"failed to get currrent resolution, errno={}", "failed to get currrent resolution, errno={}",
GetLastError() GetLastError()
@ -1882,29 +1890,46 @@ pub fn current_resolution(name: &str) -> ResultType<Resolution> {
} }
} }
pub fn is_virtual_display(name: &str) -> ResultType<bool> {
let device_name = str_to_device_name(name);
let mut dd: DISPLAY_DEVICEW = unsafe { std::mem::zeroed() };
dd.cb = std::mem::size_of::<DISPLAY_DEVICEW>() as _;
let ok = unsafe { EnumDisplayDevicesW(device_name.as_ptr(), 0, &mut dd as _, 0) };
if ok == FALSE {
bail!(
"enumerate display devices with device name '{}', errno {}",
name,
unsafe { GetLastError() }
);
}
match std::string::String::from_utf16(&dd.DeviceString) {
Ok(s) => Ok(&s[..IDD_DEVICE_STRING.len()] == IDD_DEVICE_STRING),
Err(e) => bail!(
"convert the device string of '{}' to string: {}",
name,
e
),
}
}
pub fn change_resolution(name: &str, width: usize, height: usize) -> ResultType<()> { pub fn change_resolution(name: &str, width: usize, height: usize) -> ResultType<()> {
let device_name = str_to_device_name(name);
unsafe { unsafe {
let mut dm: DEVMODEW = std::mem::zeroed(); let mut dm: DEVMODEW = std::mem::zeroed();
if FALSE == EnumDisplaySettingsW(NULL as _, ENUM_CURRENT_SETTINGS, &mut dm) { if FALSE == EnumDisplaySettingsW(device_name.as_ptr() as _, ENUM_CURRENT_SETTINGS, &mut dm)
{
bail!("EnumDisplaySettingsW failed, errno={}", GetLastError()); bail!("EnumDisplaySettingsW failed, errno={}", GetLastError());
} }
// dmPelsWidth and dmPelsHeight is the same to width and height
// to-do: check if need change // Because this process is running in dpi awareness mode.
println!("REMOVE ME ========================== dm ({},{}) to ({},{})", dm.dmPelsWidth, dm.dmPelsHeight, width, height); if dm.dmPelsWidth == width as u32 && dm.dmPelsHeight == height as u32 {
return Ok(());
let wname = wide_string(name); }
let len = if wname.len() <= dm.dmDeviceName.len() {
wname.len()
} else {
dm.dmDeviceName.len()
};
std::ptr::copy_nonoverlapping(wname.as_ptr(), dm.dmDeviceName.as_mut_ptr(), len);
dm.dmSize = std::mem::size_of::<DEVMODEW>() as _;
dm.dmPelsWidth = width as _; dm.dmPelsWidth = width as _;
dm.dmPelsHeight = height as _; dm.dmPelsHeight = height as _;
dm.dmFields = DM_PELSHEIGHT | DM_PELSWIDTH; dm.dmFields = DM_PELSHEIGHT | DM_PELSWIDTH;
let res = ChangeDisplaySettingsExW( let res = ChangeDisplaySettingsExW(
wname.as_ptr(), device_name.as_ptr(),
&mut dm, &mut dm,
NULL as _, NULL as _,
CDS_UPDATEREGISTRY | CDS_GLOBAL | CDS_RESET, CDS_UPDATEREGISTRY | CDS_GLOBAL | CDS_RESET,

View File

@ -25,9 +25,12 @@ use crate::virtual_display_manager;
use crate::{platform::windows::is_process_consent_running, privacy_win_mag}; use crate::{platform::windows::is_process_consent_running, privacy_win_mag};
#[cfg(windows)] #[cfg(windows)]
use hbb_common::get_version_number; use hbb_common::get_version_number;
use hbb_common::tokio::sync::{ use hbb_common::{
protobuf::MessageField,
tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex, Mutex as TokioMutex,
},
}; };
#[cfg(not(windows))] #[cfg(not(windows))]
use scrap::Capturer; use scrap::Capturer;
@ -65,8 +68,9 @@ lazy_static::lazy_static! {
static ref ORIGINAL_RESOLUTIONS: Arc<RwLock<HashMap<String, (i32, i32)>>> = Default::default(); static ref ORIGINAL_RESOLUTIONS: Arc<RwLock<HashMap<String, (i32, i32)>>> = Default::default();
} }
// Not virtual display
#[inline] #[inline]
pub fn set_original_resolution(display_name: &str, wh: (i32, i32)) -> (i32, i32) { fn set_original_resolution_(display_name: &str, wh: (i32, i32)) -> (i32, i32) {
let mut original_resolutions = ORIGINAL_RESOLUTIONS.write().unwrap(); let mut original_resolutions = ORIGINAL_RESOLUTIONS.write().unwrap();
match original_resolutions.get(display_name) { match original_resolutions.get(display_name) {
Some(r) => r.clone(), Some(r) => r.clone(),
@ -77,8 +81,9 @@ pub fn set_original_resolution(display_name: &str, wh: (i32, i32)) -> (i32, i32)
} }
} }
// Not virtual display
#[inline] #[inline]
fn get_original_resolution(display_name: &str) -> Option<(i32, i32)> { fn get_original_resolution_(display_name: &str) -> Option<(i32, i32)> {
ORIGINAL_RESOLUTIONS ORIGINAL_RESOLUTIONS
.read() .read()
.unwrap() .unwrap()
@ -86,13 +91,25 @@ fn get_original_resolution(display_name: &str) -> Option<(i32, i32)> {
.map(|r| r.clone()) .map(|r| r.clone())
} }
// Not virtual display
#[inline] #[inline]
fn get_or_set_original_resolution(display_name: &str, wh: (i32, i32)) -> (i32, i32) { fn get_or_set_original_resolution_(display_name: &str, wh: (i32, i32)) -> (i32, i32) {
let r = get_original_resolution(display_name); let r = get_original_resolution_(display_name);
if let Some(r) = r { if let Some(r) = r {
return r; return r;
} }
set_original_resolution(display_name, wh) 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] #[inline]
@ -543,10 +560,13 @@ 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(); let display_name = get_current_display_name().unwrap_or_default();
println!(
// to-do: check if is virtual display "REMOVE ME ============================ display_name: {:?}, is_virtual: {}",
display_name,
is_virtual_display(&display_name)
);
let original_resolution = get_original_resolution(&display_name, c.width, c.height);
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 _,
@ -556,19 +576,15 @@ 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: display_name resolutions: if display_name.is_empty() {
.as_ref() vec![]
.map(|name| crate::platform::resolutions(name)) } else {
.unwrap_or(vec![]), crate::platform::resolutions(&display_name)
},
..SupportedResolutions::default() ..SupportedResolutions::default()
}) })
.into(), .into(),
original_resolution: Some(update_get_original_resolution( 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();
@ -884,13 +900,35 @@ pub fn handle_one_frame_encoded(
} }
#[inline] #[inline]
fn update_get_original_resolution(display_name: &str, w: usize, h: usize) -> Resolution { fn get_original_resolution(display_name: &str, w: usize, h: usize) -> MessageField<Resolution> {
let wh = get_or_set_original_resolution(display_name, (w as _, h as _)); Some(if is_virtual_display(&display_name) {
Resolution { Resolution {
width: wh.0, width: 0,
height: wh.1, height: 0,
..Default::default() ..Default::default()
} }
} else {
update_get_original_resolution_(&display_name, w, h)
})
.into()
}
#[inline]
#[cfg(target_os = "windows")]
fn is_virtual_display(name: &str) -> bool {
match crate::platform::windows::is_virtual_display(&name) {
Ok(b) => b,
Err(e) => {
log::error!("Failed to check is virtual display for '{}': {}", &name, e);
false
}
}
}
#[inline]
#[cfg(not(target_os = "windows"))]
fn is_virtual_display(_name: &str) -> bool {
false
} }
pub(super) fn get_displays_2(all: &Vec<Display>) -> (usize, Vec<DisplayInfo>) { pub(super) fn get_displays_2(all: &Vec<Display>) -> (usize, Vec<DisplayInfo>) {
@ -900,20 +938,17 @@ pub(super) fn get_displays_2(all: &Vec<Display>) -> (usize, Vec<DisplayInfo>) {
if d.is_primary() { if d.is_primary() {
primary = i; primary = i;
} }
let display_name = d.name();
let original_resolution = get_original_resolution(&display_name, d.width(), d.height());
displays.push(DisplayInfo { displays.push(DisplayInfo {
x: d.origin().0 as _, x: d.origin().0 as _,
y: d.origin().1 as _, y: d.origin().1 as _,
width: d.width() as _, width: d.width() as _,
height: d.height() as _, height: d.height() as _,
name: d.name(), name: display_name,
online: d.is_online(), online: d.is_online(),
cursor_embedded: false, cursor_embedded: false,
original_resolution: Some(update_get_original_resolution( original_resolution,
&d.name(),
d.width(),
d.height(),
))
.into(),
..Default::default() ..Default::default()
}); });
} }