win resolution && api
Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
parent
340ec0975f
commit
91a2a5b56e
@ -270,6 +270,7 @@ class FfiModel with ChangeNotifier {
|
|||||||
parent.target?.canvasModel.updateViewStyle();
|
parent.target?.canvasModel.updateViewStyle();
|
||||||
}
|
}
|
||||||
parent.target?.recordingModel.onSwitchDisplay();
|
parent.target?.recordingModel.onSwitchDisplay();
|
||||||
|
handleResolutions(peerId, evt["resolutions"]);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,10 +438,35 @@ class FfiModel with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
Map<String, dynamic> features = json.decode(evt['features']);
|
Map<String, dynamic> features = json.decode(evt['features']);
|
||||||
_pi.features.privacyMode = features['privacy_mode'] == 1;
|
_pi.features.privacyMode = features['privacy_mode'] == 1;
|
||||||
|
handleResolutions(peerId, evt["resolutions"]);
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleResolutions(String id, dynamic resolutions) {
|
||||||
|
try {
|
||||||
|
final List<dynamic> dynamicArray = jsonDecode(resolutions as String);
|
||||||
|
List<Resolution> arr = List.empty(growable: true);
|
||||||
|
for (int i = 0; i < dynamicArray.length; i++) {
|
||||||
|
var width = dynamicArray[i]["width"];
|
||||||
|
var height = dynamicArray[i]["height"];
|
||||||
|
if (width is int && width > 0 && height is int && height > 0) {
|
||||||
|
arr.add(Resolution(width, height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr.sort((a, b) {
|
||||||
|
if (b.width != a.width) {
|
||||||
|
return b.width - a.width;
|
||||||
|
} else {
|
||||||
|
return b.height - a.height;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_pi.resolutions = arr;
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint("Failed to parse resolutions:$e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle the peer info synchronization event based on [evt].
|
/// Handle the peer info synchronization event based on [evt].
|
||||||
handleSyncPeerInfo(Map<String, dynamic> evt, String peerId) async {
|
handleSyncPeerInfo(Map<String, dynamic> evt, String peerId) async {
|
||||||
if (evt['displays'] != null) {
|
if (evt['displays'] != null) {
|
||||||
@ -458,6 +484,9 @@ class FfiModel with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
_pi.displays = newDisplays;
|
_pi.displays = newDisplays;
|
||||||
stateGlobal.displaysCount.value = _pi.displays.length;
|
stateGlobal.displaysCount.value = _pi.displays.length;
|
||||||
|
if (_pi.currentDisplay >= 0 && _pi.currentDisplay < _pi.displays.length) {
|
||||||
|
_display = _pi.displays[_pi.currentDisplay];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
@ -1532,6 +1561,17 @@ class Display {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Resolution {
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
Resolution(this.width, this.height);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Resolution($width,$height)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Features {
|
class Features {
|
||||||
bool privacyMode = false;
|
bool privacyMode = false;
|
||||||
}
|
}
|
||||||
@ -1545,6 +1585,7 @@ class PeerInfo {
|
|||||||
int currentDisplay = 0;
|
int currentDisplay = 0;
|
||||||
List<Display> displays = [];
|
List<Display> displays = [];
|
||||||
Features features = Features();
|
Features features = Features();
|
||||||
|
List<Resolution> resolutions = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const canvasKey = 'canvas';
|
const canvasKey = 'canvas';
|
||||||
|
@ -90,6 +90,7 @@ message PeerInfo {
|
|||||||
int32 conn_id = 8;
|
int32 conn_id = 8;
|
||||||
Features features = 9;
|
Features features = 9;
|
||||||
SupportedEncoding encoding = 10;
|
SupportedEncoding encoding = 10;
|
||||||
|
SupportedResolutions resolutions = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LoginResponse {
|
message LoginResponse {
|
||||||
@ -416,6 +417,13 @@ message Cliprdr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message Resolution {
|
||||||
|
int32 width = 1;
|
||||||
|
int32 height = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SupportedResolutions { repeated Resolution resolutions = 1; }
|
||||||
|
|
||||||
message SwitchDisplay {
|
message SwitchDisplay {
|
||||||
int32 display = 1;
|
int32 display = 1;
|
||||||
sint32 x = 2;
|
sint32 x = 2;
|
||||||
@ -423,6 +431,7 @@ message SwitchDisplay {
|
|||||||
int32 width = 4;
|
int32 width = 4;
|
||||||
int32 height = 5;
|
int32 height = 5;
|
||||||
bool cursor_embedded = 6;
|
bool cursor_embedded = 6;
|
||||||
|
SupportedResolutions resolutions = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PermissionInfo {
|
message PermissionInfo {
|
||||||
@ -597,6 +606,7 @@ message Misc {
|
|||||||
bool portable_service_running = 20;
|
bool portable_service_running = 20;
|
||||||
SwitchSidesRequest switch_sides_request = 21;
|
SwitchSidesRequest switch_sides_request = 21;
|
||||||
SwitchBack switch_back = 22;
|
SwitchBack switch_back = 22;
|
||||||
|
Resolution change_resolution = 24;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,6 +480,7 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
features.insert("privacy_mode", 0);
|
features.insert("privacy_mode", 0);
|
||||||
}
|
}
|
||||||
let features = serde_json::ser::to_string(&features).unwrap_or("".to_owned());
|
let features = serde_json::ser::to_string(&features).unwrap_or("".to_owned());
|
||||||
|
let resolutions = serialize_resolutions(&pi.resolutions.resolutions);
|
||||||
*self.peer_info.write().unwrap() = pi.clone();
|
*self.peer_info.write().unwrap() = pi.clone();
|
||||||
self.push_event(
|
self.push_event(
|
||||||
"peer_info",
|
"peer_info",
|
||||||
@ -492,6 +493,7 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
("version", &pi.version),
|
("version", &pi.version),
|
||||||
("features", &features),
|
("features", &features),
|
||||||
("current_display", &pi.current_display.to_string()),
|
("current_display", &pi.current_display.to_string()),
|
||||||
|
("resolutions", &resolutions),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -529,6 +531,7 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn switch_display(&self, display: &SwitchDisplay) {
|
fn switch_display(&self, display: &SwitchDisplay) {
|
||||||
|
let resolutions = serialize_resolutions(&display.resolutions.resolutions);
|
||||||
self.push_event(
|
self.push_event(
|
||||||
"switch_display",
|
"switch_display",
|
||||||
vec![
|
vec![
|
||||||
@ -548,6 +551,7 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
}
|
}
|
||||||
.to_string(),
|
.to_string(),
|
||||||
),
|
),
|
||||||
|
("resolutions", &resolutions),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -861,6 +865,27 @@ pub fn set_cur_session_id(id: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn serialize_resolutions(resolutions: &Vec<Resolution>) -> String {
|
||||||
|
#[derive(Debug, serde::Serialize)]
|
||||||
|
struct ResolutionSerde {
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut v = vec![];
|
||||||
|
resolutions
|
||||||
|
.iter()
|
||||||
|
.map(|r| {
|
||||||
|
v.push(ResolutionSerde {
|
||||||
|
width: r.width,
|
||||||
|
height: r.height,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
serde_json::ser::to_string(&v).unwrap_or("".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[cfg(not(feature = "flutter_texture_render"))]
|
#[cfg(not(feature = "flutter_texture_render"))]
|
||||||
pub fn session_get_rgba_size(id: *const char) -> usize {
|
pub fn session_get_rgba_size(id: *const char) -> usize {
|
||||||
|
@ -529,7 +529,13 @@ pub fn session_switch_sides(id: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn session_set_size(_id: String, _width: i32, _height: i32) {
|
pub fn session_change_resolution(id: String, width: i32, height: i32) {
|
||||||
|
if let Some(session) = SESSIONS.read().unwrap().get(&id) {
|
||||||
|
session.change_resolution(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_set_size(_id: String, _width: i32, _height: i32) {
|
||||||
#[cfg(feature = "flutter_texture_render")]
|
#[cfg(feature = "flutter_texture_render")]
|
||||||
if let Some(session) = SESSIONS.write().unwrap().get_mut(&_id) {
|
if let Some(session) = SESSIONS.write().unwrap().get_mut(&_id) {
|
||||||
session.set_size(_width, _height);
|
session.set_size(_width, _height);
|
||||||
|
@ -74,5 +74,13 @@ mod tests {
|
|||||||
assert!(!get_cursor_pos().is_none());
|
assert!(!get_cursor_pos().is_none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
|
#[test]
|
||||||
|
fn test_resolution() {
|
||||||
|
let name = r"\\.\DISPLAY1";
|
||||||
|
println!("current:{:?}", current_resolution(name));
|
||||||
|
println!("change:{:?}", change_resolution(name, 2880, 1800));
|
||||||
|
println!("resolutions:{:?}", resolutions(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,7 +5,9 @@ use crate::license::*;
|
|||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
allow_err, bail,
|
allow_err, bail,
|
||||||
config::{self, Config},
|
config::{self, Config},
|
||||||
log, sleep, timeout, tokio,
|
log,
|
||||||
|
message_proto::Resolution,
|
||||||
|
sleep, timeout, tokio,
|
||||||
};
|
};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::{
|
use std::{
|
||||||
@ -1784,3 +1786,89 @@ pub fn set_path_permission(dir: &PathBuf, permission: &str) -> ResultType<()> {
|
|||||||
.spawn()?;
|
.spawn()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
loop {
|
||||||
|
if EnumDisplaySettingsW(NULL as _, num, &mut dm) == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let r = Resolution {
|
||||||
|
width: dm.dmPelsWidth as _,
|
||||||
|
height: dm.dmPelsHeight as _,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
if !v.contains(&r) {
|
||||||
|
v.push(r);
|
||||||
|
}
|
||||||
|
num += 1;
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
bail!(
|
||||||
|
"failed to get currrent resolution, errno={}",
|
||||||
|
GetLastError()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let r = Resolution {
|
||||||
|
width: dm.dmPelsWidth as _,
|
||||||
|
height: dm.dmPelsHeight as _,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
Ok(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change_resolution(name: &str, width: usize, height: usize) -> ResultType<()> {
|
||||||
|
unsafe {
|
||||||
|
let mut dm: DEVMODEW = std::mem::zeroed();
|
||||||
|
if FALSE == EnumDisplaySettingsW(NULL as _, ENUM_CURRENT_SETTINGS, &mut dm) {
|
||||||
|
bail!("EnumDisplaySettingsW failed, errno={}", GetLastError());
|
||||||
|
}
|
||||||
|
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.dmPelsHeight = height as _;
|
||||||
|
dm.dmFields = DM_PELSHEIGHT | DM_PELSWIDTH;
|
||||||
|
let res = ChangeDisplaySettingsExW(
|
||||||
|
wname.as_ptr(),
|
||||||
|
&mut dm,
|
||||||
|
NULL as _,
|
||||||
|
CDS_UPDATEREGISTRY | CDS_GLOBAL | CDS_RESET,
|
||||||
|
NULL,
|
||||||
|
);
|
||||||
|
if res != DISP_CHANGE_SUCCESSFUL {
|
||||||
|
bail!(
|
||||||
|
"ChangeDisplaySettingsExW failed, res={}, errno={}",
|
||||||
|
res,
|
||||||
|
GetLastError()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -123,6 +123,7 @@ pub struct Connection {
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
portable: PortableState,
|
portable: PortableState,
|
||||||
from_switch: bool,
|
from_switch: bool,
|
||||||
|
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>,
|
||||||
}
|
}
|
||||||
@ -228,6 +229,7 @@ impl Connection {
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
portable: Default::default(),
|
portable: Default::default(),
|
||||||
from_switch: false,
|
from_switch: false,
|
||||||
|
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,
|
||||||
@ -533,6 +535,8 @@ 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")))]
|
||||||
|
conn.reset_resolution();
|
||||||
ALIVE_CONNS.lock().unwrap().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() {
|
||||||
s.write().unwrap().remove_connection(&conn.inner);
|
s.write().unwrap().remove_connection(&conn.inner);
|
||||||
@ -881,6 +885,16 @@ impl Connection {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.into();
|
.into();
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
|
{
|
||||||
|
pi.resolutions = Some(SupportedResolutions {
|
||||||
|
resolutions: video_service::get_current_display_name()
|
||||||
|
.map(|name| crate::platform::resolutions(&name))
|
||||||
|
.unwrap_or(vec![]),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
|
||||||
let mut sub_service = false;
|
let mut sub_service = false;
|
||||||
if self.file_transfer.is_some() {
|
if self.file_transfer.is_some() {
|
||||||
@ -1597,6 +1611,26 @@ impl Connection {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
|
Some(misc::Union::ChangeResolution(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Some(message::Union::AudioFrame(frame)) => {
|
Some(message::Union::AudioFrame(frame)) => {
|
||||||
@ -1937,6 +1971,20 @@ 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_switch_sides_uuid(id: String, uuid: uuid::Uuid) {
|
pub fn insert_switch_sides_uuid(id: String, uuid: uuid::Uuid) {
|
||||||
|
@ -356,7 +356,7 @@ fn get_capturer(use_yuv: bool, portable_service_running: bool) -> ResultType<Cap
|
|||||||
let (ndisplay, current, display) = get_current_display()?;
|
let (ndisplay, current, display) = get_current_display()?;
|
||||||
let (origin, width, height) = (display.origin(), display.width(), display.height());
|
let (origin, width, height) = (display.origin(), display.width(), display.height());
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"#displays={}, current={}, origin: {:?}, width={}, height={}, cpus={}/{}",
|
"#displays={}, current={}, origin: {:?}, width={}, height={}, cpus={}/{}, name:{}",
|
||||||
ndisplay,
|
ndisplay,
|
||||||
current,
|
current,
|
||||||
&origin,
|
&origin,
|
||||||
@ -364,6 +364,7 @@ fn get_capturer(use_yuv: bool, portable_service_running: bool) -> ResultType<Cap
|
|||||||
height,
|
height,
|
||||||
num_cpus::get_physical(),
|
num_cpus::get_physical(),
|
||||||
num_cpus::get(),
|
num_cpus::get(),
|
||||||
|
display.name(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let privacy_mode_id = *PRIVACY_MODE_CONN_ID.lock().unwrap();
|
let privacy_mode_id = *PRIVACY_MODE_CONN_ID.lock().unwrap();
|
||||||
@ -501,6 +502,14 @@ fn run(sp: GenericService) -> ResultType<()> {
|
|||||||
width: c.width as _,
|
width: c.width as _,
|
||||||
height: c.height as _,
|
height: c.height as _,
|
||||||
cursor_embedded: capture_cursor_embedded(),
|
cursor_embedded: capture_cursor_embedded(),
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
|
resolutions: Some(SupportedResolutions {
|
||||||
|
resolutions: get_current_display_name()
|
||||||
|
.map(|name| crate::platform::resolutions(&name))
|
||||||
|
.unwrap_or(vec![]),
|
||||||
|
..SupportedResolutions::default()
|
||||||
|
})
|
||||||
|
.into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
let mut msg_out = Message::new();
|
let mut msg_out = Message::new();
|
||||||
@ -992,6 +1001,10 @@ pub fn get_current_display() -> ResultType<(usize, usize, Display)> {
|
|||||||
get_current_display_2(try_get_displays()?)
|
get_current_display_2(try_get_displays()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_current_display_name() -> ResultType<String> {
|
||||||
|
Ok(get_current_display_2(try_get_displays()?)?.2.name())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn start_uac_elevation_check() {
|
fn start_uac_elevation_check() {
|
||||||
static START: Once = Once::new();
|
static START: Once = Once::new();
|
||||||
|
@ -713,6 +713,18 @@ impl<T: InvokeUiSession> Session<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn change_resolution(&self, width: i32, height: i32) {
|
||||||
|
let mut misc = Misc::new();
|
||||||
|
misc.set_change_resolution(Resolution {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let mut msg = Message::new();
|
||||||
|
msg.set_misc(misc);
|
||||||
|
self.send(Data::Message(msg));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn request_voice_call(&self) {
|
pub fn request_voice_call(&self) {
|
||||||
self.send(Data::NewVoiceCall);
|
self.send(Data::NewVoiceCall);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user