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

View File

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

View File

@ -56,6 +56,10 @@ use windows_service::{
use winreg::enums::*;
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)> {
unsafe {
#[allow(invalid_value)]
@ -1831,21 +1835,25 @@ pub fn set_path_permission(dir: &PathBuf, permission: &str) -> ResultType<()> {
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> {
unsafe {
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 num = 0;
let device_name = str_to_device_name(name);
loop {
if EnumDisplaySettingsW(NULL as _, num, &mut dm) == 0 {
if EnumDisplaySettingsW(device_name.as_ptr(), num, &mut dm) == 0 {
break;
}
let r = Resolution {
@ -1866,8 +1874,8 @@ pub fn current_resolution(name: &str) -> ResultType<Resolution> {
unsafe {
let mut dm: DEVMODEW = std::mem::zeroed();
dm.dmSize = std::mem::size_of::<DEVMODEW>() as _;
let wname = wide_string(name);
if EnumDisplaySettingsW(wname.as_ptr(), ENUM_CURRENT_SETTINGS, &mut dm) == 0 {
let device_name = str_to_device_name(name);
if EnumDisplaySettingsW(device_name.as_ptr(), ENUM_CURRENT_SETTINGS, &mut dm) == 0 {
bail!(
"failed to get currrent resolution, errno={}",
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<()> {
let device_name = str_to_device_name(name);
unsafe {
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());
}
// to-do: check if need change
println!("REMOVE ME ========================== dm ({},{}) to ({},{})", dm.dmPelsWidth, dm.dmPelsHeight, width, height);
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 _;
// dmPelsWidth and dmPelsHeight is the same to width and height
// Because this process is running in dpi awareness mode.
if dm.dmPelsWidth == width as u32 && dm.dmPelsHeight == height as u32 {
return Ok(());
}
dm.dmPelsWidth = width as _;
dm.dmPelsHeight = height as _;
dm.dmFields = DM_PELSHEIGHT | DM_PELSWIDTH;
let res = ChangeDisplaySettingsExW(
wname.as_ptr(),
device_name.as_ptr(),
&mut dm,
NULL as _,
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};
#[cfg(windows)]
use hbb_common::get_version_number;
use hbb_common::tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex,
use hbb_common::{
protobuf::MessageField,
tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex,
},
};
#[cfg(not(windows))]
use scrap::Capturer;
@ -65,8 +68,9 @@ lazy_static::lazy_static! {
static ref ORIGINAL_RESOLUTIONS: Arc<RwLock<HashMap<String, (i32, i32)>>> = Default::default();
}
// Not virtual display
#[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();
match original_resolutions.get(display_name) {
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]
fn get_original_resolution(display_name: &str) -> Option<(i32, i32)> {
fn get_original_resolution_(display_name: &str) -> Option<(i32, i32)> {
ORIGINAL_RESOLUTIONS
.read()
.unwrap()
@ -86,13 +91,25 @@ fn get_original_resolution(display_name: &str) -> Option<(i32, i32)> {
.map(|r| r.clone())
}
// Not virtual display
#[inline]
fn get_or_set_original_resolution(display_name: &str, wh: (i32, i32)) -> (i32, i32) {
let r = get_original_resolution(display_name);
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)
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]
@ -543,10 +560,13 @@ fn run(sp: GenericService) -> ResultType<()> {
if *SWITCH.lock().unwrap() {
log::debug!("Broadcasting display switch");
let mut misc = Misc::new();
let display_name = get_current_display_name();
// to-do: check if is virtual display
let display_name = get_current_display_name().unwrap_or_default();
println!(
"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 {
display: c.current as _,
x: c.origin.0 as _,
@ -556,19 +576,15 @@ fn run(sp: GenericService) -> ResultType<()> {
cursor_embedded: capture_cursor_embedded(),
#[cfg(not(any(target_os = "android", target_os = "ios")))]
resolutions: Some(SupportedResolutions {
resolutions: display_name
.as_ref()
.map(|name| crate::platform::resolutions(name))
.unwrap_or(vec![]),
resolutions: if display_name.is_empty() {
vec![]
} else {
crate::platform::resolutions(&display_name)
},
..SupportedResolutions::default()
})
.into(),
original_resolution: Some(update_get_original_resolution(
&display_name.unwrap_or_default(),
c.width,
c.height,
))
.into(),
original_resolution,
..Default::default()
});
let mut msg_out = Message::new();
@ -884,15 +900,37 @@ pub fn handle_one_frame_encoded(
}
#[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()
fn get_original_resolution(display_name: &str, w: usize, h: usize) -> MessageField<Resolution> {
Some(if is_virtual_display(&display_name) {
Resolution {
width: 0,
height: 0,
..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>) {
let mut displays = Vec::new();
let mut primary = 0;
@ -900,20 +938,17 @@ pub(super) fn get_displays_2(all: &Vec<Display>) -> (usize, Vec<DisplayInfo>) {
if d.is_primary() {
primary = i;
}
let display_name = d.name();
let original_resolution = get_original_resolution(&display_name, d.width(), d.height());
displays.push(DisplayInfo {
x: d.origin().0 as _,
y: d.origin().1 as _,
width: d.width() as _,
height: d.height() as _,
name: d.name(),
name: display_name,
online: d.is_online(),
cursor_embedded: false,
original_resolution: Some(update_get_original_resolution(
&d.name(),
d.width(),
d.height(),
))
.into(),
original_resolution,
..Default::default()
});
}