mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-11-27 23:19:02 +08:00
Merge pull request #6199 from fufesou/feat/windows_virtual_displays
feat, win virtual display
This commit is contained in:
commit
cef782c388
@ -32,7 +32,7 @@ import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
|||||||
for (var peer in peerData) {
|
for (var peer in peerData) {
|
||||||
if (peer is Map && peer.containsKey("id")) {
|
if (peer is Map && peer.containsKey("id")) {
|
||||||
String id = peer["id"];
|
String id = peer["id"];
|
||||||
if (id != null && !combinedPeers.containsKey(id)) {
|
if (!combinedPeers.containsKey(id)) {
|
||||||
combinedPeers[id] = peer;
|
combinedPeers[id] = peer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,9 @@ import 'package:flutter_hbb/common.dart';
|
|||||||
import 'package:flutter_hbb/models/state_model.dart';
|
import 'package:flutter_hbb/models/state_model.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
const int kMaxVirtualDisplayCount = 4;
|
||||||
|
const int kAllVirtualDisplay = -1;
|
||||||
|
|
||||||
const double kDesktopRemoteTabBarHeight = 28.0;
|
const double kDesktopRemoteTabBarHeight = 28.0;
|
||||||
const int kInvalidWindowId = -1;
|
const int kInvalidWindowId = -1;
|
||||||
const int kMainWindowId = 0;
|
const int kMainWindowId = 0;
|
||||||
@ -15,6 +18,11 @@ const kKeyLegacyMode = 'legacy';
|
|||||||
const kKeyMapMode = 'map';
|
const kKeyMapMode = 'map';
|
||||||
const kKeyTranslateMode = 'translate';
|
const kKeyTranslateMode = 'translate';
|
||||||
|
|
||||||
|
const String kPlatformAdditionsIsWayland = "is_wayland";
|
||||||
|
const String kPlatformAdditionsHeadless = "headless";
|
||||||
|
const String kPlatformAdditionsIsInstalled = "is_installed";
|
||||||
|
const String kPlatformAdditionsVirtualDisplays = "virtual_displays";
|
||||||
|
|
||||||
const String kPeerPlatformWindows = "Windows";
|
const String kPeerPlatformWindows = "Windows";
|
||||||
const String kPeerPlatformLinux = "Linux";
|
const String kPeerPlatformLinux = "Linux";
|
||||||
const String kPeerPlatformMacOS = "Mac OS";
|
const String kPeerPlatformMacOS = "Mac OS";
|
||||||
|
@ -978,6 +978,10 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||||||
ffi: widget.ffi,
|
ffi: widget.ffi,
|
||||||
screenAdjustor: _screenAdjustor,
|
screenAdjustor: _screenAdjustor,
|
||||||
),
|
),
|
||||||
|
_VirtualDisplayMenu(
|
||||||
|
id: widget.id,
|
||||||
|
ffi: widget.ffi,
|
||||||
|
),
|
||||||
Divider(),
|
Divider(),
|
||||||
toggles(),
|
toggles(),
|
||||||
widget.pluginItem,
|
widget.pluginItem,
|
||||||
@ -1387,6 +1391,70 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _VirtualDisplayMenu extends StatefulWidget {
|
||||||
|
final String id;
|
||||||
|
final FFI ffi;
|
||||||
|
|
||||||
|
_VirtualDisplayMenu({
|
||||||
|
Key? key,
|
||||||
|
required this.id,
|
||||||
|
required this.ffi,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_VirtualDisplayMenu> createState() => _VirtualDisplayMenuState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VirtualDisplayMenuState extends State<_VirtualDisplayMenu> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (widget.ffi.ffiModel.pi.platform != kPeerPlatformWindows) {
|
||||||
|
return Offstage();
|
||||||
|
}
|
||||||
|
if (!widget.ffi.ffiModel.pi.isInstalled) {
|
||||||
|
return Offstage();
|
||||||
|
}
|
||||||
|
|
||||||
|
final virtualDisplays = widget.ffi.ffiModel.pi.virtualDisplays;
|
||||||
|
|
||||||
|
final children = <Widget>[];
|
||||||
|
for (var i = 0; i < kMaxVirtualDisplayCount; i++) {
|
||||||
|
children.add(CkbMenuButton(
|
||||||
|
value: virtualDisplays.contains(i + 1),
|
||||||
|
onChanged: (bool? value) async {
|
||||||
|
if (value != null) {
|
||||||
|
bind.sessionToggleVirtualDisplay(
|
||||||
|
sessionId: widget.ffi.sessionId, index: i + 1, on: value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text('${translate('Virtual display')} ${i + 1}'),
|
||||||
|
ffi: widget.ffi,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
children.add(Divider());
|
||||||
|
children.add(MenuButton(
|
||||||
|
onPressed: () {
|
||||||
|
bind.sessionToggleVirtualDisplay(
|
||||||
|
sessionId: widget.ffi.sessionId,
|
||||||
|
index: kAllVirtualDisplay,
|
||||||
|
on: false);
|
||||||
|
},
|
||||||
|
ffi: widget.ffi,
|
||||||
|
child: Text(translate('Plug out all')),
|
||||||
|
));
|
||||||
|
return _SubmenuButton(
|
||||||
|
ffi: widget.ffi,
|
||||||
|
menuChildren: children,
|
||||||
|
child: Text(translate("Virtual display")),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _KeyboardMenu extends StatelessWidget {
|
class _KeyboardMenu extends StatelessWidget {
|
||||||
final String id;
|
final String id;
|
||||||
final FFI ffi;
|
final FFI ffi;
|
||||||
|
@ -248,6 +248,8 @@ class FfiModel with ChangeNotifier {
|
|||||||
handlePeerInfo(evt, peerId, false);
|
handlePeerInfo(evt, peerId, false);
|
||||||
} else if (name == 'sync_peer_info') {
|
} else if (name == 'sync_peer_info') {
|
||||||
handleSyncPeerInfo(evt, sessionId, peerId);
|
handleSyncPeerInfo(evt, sessionId, peerId);
|
||||||
|
} else if (name == 'sync_platform_additions') {
|
||||||
|
handlePlatformAdditions(evt, sessionId, peerId);
|
||||||
} else if (name == 'connection_ready') {
|
} else if (name == 'connection_ready') {
|
||||||
setConnectionType(
|
setConnectionType(
|
||||||
peerId, evt['secure'] == 'true', evt['direct'] == 'true');
|
peerId, evt['secure'] == 'true', evt['direct'] == 'true');
|
||||||
@ -895,6 +897,33 @@ class FfiModel with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlePlatformAdditions(
|
||||||
|
Map<String, dynamic> evt, SessionID sessionId, String peerId) async {
|
||||||
|
final updateData = evt['platform_additions'] as String?;
|
||||||
|
if (updateData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateData.isEmpty) {
|
||||||
|
_pi.platformAdditions.remove(kPlatformAdditionsVirtualDisplays);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
final updateJson = json.decode(updateData);
|
||||||
|
for (final key in updateJson.keys) {
|
||||||
|
_pi.platformAdditions[key] = updateJson[key];
|
||||||
|
}
|
||||||
|
if (!updateJson.contains(kPlatformAdditionsVirtualDisplays)) {
|
||||||
|
_pi.platformAdditions.remove(kPlatformAdditionsVirtualDisplays);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Failed to decode platformAdditions $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedPeerData.peerInfo['platform_additions'] =
|
||||||
|
json.encode(_pi.platformAdditions);
|
||||||
|
}
|
||||||
|
|
||||||
// Directly switch to the new display without waiting for the response.
|
// Directly switch to the new display without waiting for the response.
|
||||||
switchToNewDisplay(int display, SessionID sessionId, String peerId) {
|
switchToNewDisplay(int display, SessionID sessionId, String peerId) {
|
||||||
// VideoHandler creation is upon when video frames are received, so either caching commands(don't know next width/height) or stopping recording when switching displays.
|
// VideoHandler creation is upon when video frames are received, so either caching commands(don't know next width/height) or stopping recording when switching displays.
|
||||||
@ -2300,8 +2329,13 @@ class PeerInfo with ChangeNotifier {
|
|||||||
RxInt displaysCount = 0.obs;
|
RxInt displaysCount = 0.obs;
|
||||||
RxBool isSet = false.obs;
|
RxBool isSet = false.obs;
|
||||||
|
|
||||||
bool get isWayland => platformAdditions['is_wayland'] == true;
|
bool get isWayland => platformAdditions[kPlatformAdditionsIsWayland] == true;
|
||||||
bool get isHeadless => platformAdditions['headless'] == true;
|
bool get isHeadless => platformAdditions[kPlatformAdditionsHeadless] == true;
|
||||||
|
bool get isInstalled =>
|
||||||
|
platform != kPeerPlatformWindows ||
|
||||||
|
platformAdditions[kPlatformAdditionsIsInstalled] == true;
|
||||||
|
List<int> get virtualDisplays => List<int>.from(
|
||||||
|
platformAdditions[kPlatformAdditionsVirtualDisplays] ?? []);
|
||||||
|
|
||||||
bool get isSupportMultiDisplay => isDesktop && isSupportMultiUiSession;
|
bool get isSupportMultiDisplay => isDesktop && isSupportMultiUiSession;
|
||||||
|
|
||||||
|
@ -102,6 +102,7 @@ message PeerInfo {
|
|||||||
SupportedEncoding encoding = 10;
|
SupportedEncoding encoding = 10;
|
||||||
SupportedResolutions resolutions = 11;
|
SupportedResolutions resolutions = 11;
|
||||||
// Use JSON's key-value format which is friendly for peer to handle.
|
// Use JSON's key-value format which is friendly for peer to handle.
|
||||||
|
// NOTE: Only support one-level dictionaries (for peer to update), and the key is of type string.
|
||||||
string platform_additions = 12;
|
string platform_additions = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,6 +499,11 @@ message CaptureDisplays {
|
|||||||
repeated int32 set = 3;
|
repeated int32 set = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ToggleVirtualDisplay {
|
||||||
|
int32 display = 1;
|
||||||
|
bool on = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message PermissionInfo {
|
message PermissionInfo {
|
||||||
enum Permission {
|
enum Permission {
|
||||||
Keyboard = 0;
|
Keyboard = 0;
|
||||||
@ -697,6 +703,7 @@ message Misc {
|
|||||||
bool client_record_status = 29;
|
bool client_record_status = 29;
|
||||||
CaptureDisplays capture_displays = 30;
|
CaptureDisplays capture_displays = 30;
|
||||||
int32 refresh_video_display = 31;
|
int32 refresh_video_display = 31;
|
||||||
|
ToggleVirtualDisplay toggle_virtual_display = 32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub mod win10;
|
pub mod win10;
|
||||||
|
use hbb_common::ResultType;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use hbb_common::lazy_static;
|
use hbb_common::{bail, lazy_static};
|
||||||
use hbb_common::{bail, ResultType};
|
#[cfg(windows)]
|
||||||
use std::path::Path;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
@ -33,18 +34,25 @@ pub fn download_driver() -> ResultType<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[cfg(windows)]
|
||||||
pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
fn get_driver_install_abs_path() -> ResultType<PathBuf> {
|
||||||
#[cfg(windows)]
|
|
||||||
let install_path = win10::DRIVER_INSTALL_PATH;
|
let install_path = win10::DRIVER_INSTALL_PATH;
|
||||||
#[cfg(not(windows))]
|
let exe_file = std::env::current_exe()?;
|
||||||
let install_path = "";
|
let abs_path = match exe_file.parent() {
|
||||||
|
Some(cur_dir) => cur_dir.join(install_path),
|
||||||
let abs_path = Path::new(install_path).canonicalize()?;
|
None => bail!(
|
||||||
|
"Invalid exe parent for {}",
|
||||||
|
exe_file.to_string_lossy().as_ref()
|
||||||
|
),
|
||||||
|
};
|
||||||
if !abs_path.exists() {
|
if !abs_path.exists() {
|
||||||
bail!("{} not exists", install_path)
|
bail!("{} not exists", install_path)
|
||||||
}
|
}
|
||||||
|
Ok(abs_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
unsafe {
|
unsafe {
|
||||||
{
|
{
|
||||||
@ -54,6 +62,7 @@ pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
|||||||
bail!("{}", e);
|
bail!("{}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let abs_path = get_driver_install_abs_path()?;
|
||||||
let full_install_path: Vec<u16> = abs_path
|
let full_install_path: Vec<u16> = abs_path
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -76,19 +85,10 @@ pub fn install_update_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn uninstall_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
pub fn uninstall_driver(_reboot_required: &mut bool) -> ResultType<()> {
|
||||||
#[cfg(windows)]
|
|
||||||
let install_path = win10::DRIVER_INSTALL_PATH;
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
let install_path = "";
|
|
||||||
|
|
||||||
let abs_path = Path::new(install_path).canonicalize()?;
|
|
||||||
if !abs_path.exists() {
|
|
||||||
bail!("{} not exists", install_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
unsafe {
|
unsafe {
|
||||||
{
|
{
|
||||||
|
let abs_path = get_driver_install_abs_path()?;
|
||||||
let full_install_path: Vec<u16> = abs_path
|
let full_install_path: Vec<u16> = abs_path
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -1531,6 +1531,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
}
|
}
|
||||||
Some(message::Union::PeerInfo(pi)) => {
|
Some(message::Union::PeerInfo(pi)) => {
|
||||||
self.handler.set_displays(&pi.displays);
|
self.handler.set_displays(&pi.displays);
|
||||||
|
self.handler.set_platform_additions(&pi.platform_additions);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -691,6 +691,13 @@ impl InvokeUiSession for FlutterHandler {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_platform_additions(&self, data: &str) {
|
||||||
|
self.push_event(
|
||||||
|
"sync_platform_additions",
|
||||||
|
vec![("platform_additions", &data)],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn on_connected(&self, _conn_type: ConnType) {}
|
fn on_connected(&self, _conn_type: ConnType) {}
|
||||||
|
|
||||||
fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool) {
|
fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool) {
|
||||||
|
@ -1401,6 +1401,12 @@ pub fn session_on_waiting_for_image_dialog_show(session_id: SessionID) {
|
|||||||
super::flutter::session_on_waiting_for_image_dialog_show(session_id);
|
super::flutter::session_on_waiting_for_image_dialog_show(session_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn session_toggle_virtual_display(session_id: SessionID, index: i32, on: bool) {
|
||||||
|
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
|
||||||
|
session.toggle_virtual_display(index, on);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main_set_home_dir(_home: String) {
|
pub fn main_set_home_dir(_home: String) {
|
||||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
{
|
{
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", "虚拟显示器"),
|
||||||
|
("Plug out all", "拔出所有"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", "Velké dlaždice"),
|
("Big tiles", "Velké dlaždice"),
|
||||||
("Small tiles", "Malé dlaždice"),
|
("Small tiles", "Malé dlaždice"),
|
||||||
("List", "Seznam"),
|
("List", "Seznam"),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", "Große Kacheln"),
|
("Big tiles", "Große Kacheln"),
|
||||||
("Small tiles", "Kleine Kacheln"),
|
("Small tiles", "Kleine Kacheln"),
|
||||||
("List", "Liste"),
|
("List", "Liste"),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("selinux_tip", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -565,11 +565,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Open in new window", "Apri in una nuova finestra"),
|
("Open in new window", "Apri in una nuova finestra"),
|
||||||
("Show displays as individual windows", "Visualizza schermi come finestre individuali"),
|
("Show displays as individual windows", "Visualizza schermi come finestre individuali"),
|
||||||
("Use all my displays for the remote session", "Usa tutti gli schermi per la sessione remota"),
|
("Use all my displays for the remote session", "Usa tutti gli schermi per la sessione remota"),
|
||||||
("selinux_tip", ""),
|
|
||||||
("selinux_tip", "In questo dispositivo è abilitato SELinux, che potrebbe impedire il corretto funzionamento di RustDesk come lato controllato."),
|
("selinux_tip", "In questo dispositivo è abilitato SELinux, che potrebbe impedire il corretto funzionamento di RustDesk come lato controllato."),
|
||||||
("Change view", "Modifica vista"),
|
("Change view", "Modifica vista"),
|
||||||
("Big tiles", "Icone grandi"),
|
("Big tiles", "Icone grandi"),
|
||||||
("Small tiles", "Icone piccole"),
|
("Small tiles", "Icone piccole"),
|
||||||
("List", "Elenco"),
|
("List", "Elenco"),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -566,7 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Show displays as individual windows", "Rādīt displejus kā atsevišķus logus"),
|
("Show displays as individual windows", "Rādīt displejus kā atsevišķus logus"),
|
||||||
("Use all my displays for the remote session", "Izmantot visus manus displejus attālajai sesijai"),
|
("Use all my displays for the remote session", "Izmantot visus manus displejus attālajai sesijai"),
|
||||||
("selinux_tip", "Jūsu ierīcē ir iespējots SELinux, kas var neļaut RustDesk pareizi darboties kā kontrolētajai pusei."),
|
("selinux_tip", "Jūsu ierīcē ir iespējots SELinux, kas var neļaut RustDesk pareizi darboties kā kontrolētajai pusei."),
|
||||||
("Change view", "Mainīt skatu"),
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
|
(" view", "Mainīt skatu"),
|
||||||
("Big tiles", "Lielas flīzes"),
|
("Big tiles", "Lielas flīzes"),
|
||||||
("Small tiles", "Mazas flīzes"),
|
("Small tiles", "Mazas flīzes"),
|
||||||
("List", "Saraksts"),
|
("List", "Saraksts"),
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", "Большие значки"),
|
("Big tiles", "Большие значки"),
|
||||||
("Small tiles", "Маленькие значки"),
|
("Small tiles", "Маленькие значки"),
|
||||||
("List", "Список"),
|
("List", "Список"),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -570,5 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Big tiles", ""),
|
("Big tiles", ""),
|
||||||
("Small tiles", ""),
|
("Small tiles", ""),
|
||||||
("List", ""),
|
("List", ""),
|
||||||
|
("Virtual display", ""),
|
||||||
|
("Plug out all", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
@ -1838,7 +1838,7 @@ pub fn uninstall_cert() -> ResultType<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod cert {
|
mod cert {
|
||||||
use hbb_common::{allow_err, bail, log, ResultType};
|
use hbb_common::{bail, log, ResultType};
|
||||||
use std::{ffi::OsStr, io::Error, os::windows::ffi::OsStrExt, path::Path, str::from_utf8};
|
use std::{ffi::OsStr, io::Error, os::windows::ffi::OsStrExt, path::Path, str::from_utf8};
|
||||||
use winapi::{
|
use winapi::{
|
||||||
shared::{
|
shared::{
|
||||||
|
@ -53,9 +53,10 @@ use std::{
|
|||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
use system_shutdown;
|
use system_shutdown;
|
||||||
|
|
||||||
|
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
||||||
|
use crate::virtual_display_manager;
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
pub type Sender = mpsc::UnboundedSender<(Instant, Arc<Message>)>;
|
pub type Sender = mpsc::UnboundedSender<(Instant, Arc<Message>)>;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
@ -1031,9 +1032,10 @@ impl Connection {
|
|||||||
pi.hostname = DEVICE_NAME.lock().unwrap().clone();
|
pi.hostname = DEVICE_NAME.lock().unwrap().clone();
|
||||||
pi.platform = "Android".into();
|
pi.platform = "Android".into();
|
||||||
}
|
}
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
|
let mut platform_additions = serde_json::Map::new();
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
let mut platform_additions = serde_json::Map::new();
|
|
||||||
if crate::platform::current_is_wayland() {
|
if crate::platform::current_is_wayland() {
|
||||||
platform_additions.insert("is_wayland".into(), json!(true));
|
platform_additions.insert("is_wayland".into(), json!(true));
|
||||||
}
|
}
|
||||||
@ -1044,12 +1046,27 @@ impl Connection {
|
|||||||
platform_additions.insert("headless".into(), json!(true));
|
platform_additions.insert("headless".into(), json!(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !platform_additions.is_empty() {
|
}
|
||||||
pi.platform_additions =
|
#[cfg(target_os = "windows")]
|
||||||
serde_json::to_string(&platform_additions).unwrap_or("".into());
|
{
|
||||||
|
platform_additions.insert(
|
||||||
|
"is_installed".into(),
|
||||||
|
json!(crate::platform::is_installed()),
|
||||||
|
);
|
||||||
|
#[cfg(feature = "virtual_display_driver")]
|
||||||
|
if crate::platform::is_installed() {
|
||||||
|
let virtual_displays = virtual_display_manager::get_virtual_displays();
|
||||||
|
if !virtual_displays.is_empty() {
|
||||||
|
platform_additions.insert("virtual_displays".into(), json!(&virtual_displays));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
|
if !platform_additions.is_empty() {
|
||||||
|
pi.platform_additions = serde_json::to_string(&platform_additions).unwrap_or("".into());
|
||||||
|
}
|
||||||
|
|
||||||
pi.encoding = Some(scrap::codec::Encoder::supported_encoding()).into();
|
pi.encoding = Some(scrap::codec::Encoder::supported_encoding()).into();
|
||||||
|
|
||||||
if self.port_forward_socket.is_some() {
|
if self.port_forward_socket.is_some() {
|
||||||
@ -1962,6 +1979,10 @@ impl Connection {
|
|||||||
let set = displays.set.iter().map(|d| *d as usize).collect::<Vec<_>>();
|
let set = displays.set.iter().map(|d| *d as usize).collect::<Vec<_>>();
|
||||||
self.capture_displays(&add, &sub, &set).await;
|
self.capture_displays(&add, &sub, &set).await;
|
||||||
}
|
}
|
||||||
|
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
||||||
|
Some(misc::Union::ToggleVirtualDisplay(t)) => {
|
||||||
|
self.toggle_virtual_display(t).await;
|
||||||
|
}
|
||||||
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 });
|
||||||
self.chat_unanswered = true;
|
self.chat_unanswered = true;
|
||||||
@ -2214,6 +2235,25 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
||||||
|
async fn toggle_virtual_display(&mut self, t: ToggleVirtualDisplay) {
|
||||||
|
if t.on {
|
||||||
|
if let Err(e) = virtual_display_manager::plug_in_index_modes(t.display as _, Vec::new())
|
||||||
|
{
|
||||||
|
log::error!("Failed to plug in virtual display: {}", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let indices = if t.display == -1 {
|
||||||
|
virtual_display_manager::get_virtual_displays()
|
||||||
|
} else {
|
||||||
|
vec![t.display as _]
|
||||||
|
};
|
||||||
|
if let Err(e) = virtual_display_manager::plug_out_peer_request(&indices) {
|
||||||
|
log::error!("Failed to plug out virtual display {:?}: {}", &indices, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
fn change_resolution(&mut self, r: &Resolution) {
|
fn change_resolution(&mut self, r: &Resolution) {
|
||||||
if self.keyboard {
|
if self.keyboard {
|
||||||
@ -2222,7 +2262,7 @@ impl Connection {
|
|||||||
let name = display.name();
|
let name = display.name();
|
||||||
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
||||||
if let Some(_ok) =
|
if let Some(_ok) =
|
||||||
crate::virtual_display_manager::change_resolution_if_is_virtual_display(
|
virtual_display_manager::change_resolution_if_is_virtual_display(
|
||||||
&name,
|
&name,
|
||||||
r.width as _,
|
r.width as _,
|
||||||
r.height as _,
|
r.height as _,
|
||||||
@ -2918,7 +2958,7 @@ mod raii {
|
|||||||
}
|
}
|
||||||
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
||||||
if active_conns_lock.is_empty() {
|
if active_conns_lock.is_empty() {
|
||||||
display_service::try_plug_out_virtual_display();
|
let _ = virtual_display_manager::reset_all();
|
||||||
}
|
}
|
||||||
#[cfg(all(windows))]
|
#[cfg(all(windows))]
|
||||||
if active_conns_lock.is_empty() {
|
if active_conns_lock.is_empty() {
|
||||||
|
@ -12,6 +12,8 @@ use scrap::Display;
|
|||||||
|
|
||||||
pub const NAME: &'static str = "display";
|
pub const NAME: &'static str = "display";
|
||||||
|
|
||||||
|
const DUMMY_DISPLAY_SIDE_MAX_SIZE: usize = 1024;
|
||||||
|
|
||||||
struct ChangedResolution {
|
struct ChangedResolution {
|
||||||
original: (i32, i32),
|
original: (i32, i32),
|
||||||
changed: (i32, i32),
|
changed: (i32, i32),
|
||||||
@ -154,6 +156,20 @@ fn displays_to_msg(displays: Vec<DisplayInfo>) -> Message {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
pi.displays = displays.clone();
|
pi.displays = displays.clone();
|
||||||
|
|
||||||
|
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
||||||
|
if crate::platform::is_installed() {
|
||||||
|
let virtual_displays = crate::virtual_display_manager::get_virtual_displays();
|
||||||
|
if !virtual_displays.is_empty() {
|
||||||
|
let mut platform_additions = serde_json::Map::new();
|
||||||
|
platform_additions.insert(
|
||||||
|
"virtual_displays".into(),
|
||||||
|
serde_json::json!(&virtual_displays),
|
||||||
|
);
|
||||||
|
pi.platform_additions = serde_json::to_string(&platform_additions).unwrap_or("".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// current_display should not be used in server.
|
// current_display should not be used in server.
|
||||||
// It is set to 0 for compatibility with old clients.
|
// It is set to 0 for compatibility with old clients.
|
||||||
pi.current_display = 0;
|
pi.current_display = 0;
|
||||||
@ -168,11 +184,6 @@ fn check_get_displays_changed_msg() -> Option<Message> {
|
|||||||
Some(displays_to_msg(displays))
|
Some(displays_to_msg(displays))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
|
||||||
pub fn try_plug_out_virtual_display() {
|
|
||||||
let _res = virtual_display_manager::plug_out_headless();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(sp: EmptyExtraFieldService) -> ResultType<()> {
|
fn run(sp: EmptyExtraFieldService) -> ResultType<()> {
|
||||||
while sp.ok() {
|
while sp.ok() {
|
||||||
sp.snapshot(|sps| {
|
sp.snapshot(|sps| {
|
||||||
@ -312,9 +323,18 @@ fn no_displays(displays: &Vec<Display>) -> bool {
|
|||||||
true
|
true
|
||||||
} else if display_len == 1 {
|
} else if display_len == 1 {
|
||||||
let display = &displays[0];
|
let display = &displays[0];
|
||||||
let dummy_display_side_max_size = 800;
|
if display.width() > DUMMY_DISPLAY_SIDE_MAX_SIZE
|
||||||
display.width() <= dummy_display_side_max_size
|
|| display.height() > DUMMY_DISPLAY_SIDE_MAX_SIZE
|
||||||
&& display.height() <= dummy_display_side_max_size
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let any_real = crate::platform::resolutions(&display.name())
|
||||||
|
.iter()
|
||||||
|
.any(|r| {
|
||||||
|
(r.height as usize) > DUMMY_DISPLAY_SIDE_MAX_SIZE
|
||||||
|
|| (r.width as usize) > DUMMY_DISPLAY_SIDE_MAX_SIZE
|
||||||
|
});
|
||||||
|
!any_real
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -255,7 +255,7 @@ pub fn test_create_capturer(
|
|||||||
) -> String {
|
) -> String {
|
||||||
let test_begin = Instant::now();
|
let test_begin = Instant::now();
|
||||||
loop {
|
loop {
|
||||||
let err = match try_get_displays() {
|
let err = match Display::all() {
|
||||||
Ok(mut displays) => {
|
Ok(mut displays) => {
|
||||||
if displays.len() <= display_idx {
|
if displays.len() <= display_idx {
|
||||||
anyhow!(
|
anyhow!(
|
||||||
@ -271,7 +271,7 @@ pub fn test_create_capturer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => e,
|
Err(e) => e.into(),
|
||||||
};
|
};
|
||||||
if test_begin.elapsed().as_millis() >= timeout_millis as _ {
|
if test_begin.elapsed().as_millis() >= timeout_millis as _ {
|
||||||
return err.to_string();
|
return err.to_string();
|
||||||
@ -332,7 +332,7 @@ fn get_capturer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut displays = try_get_displays()?;
|
let mut displays = Display::all()?;
|
||||||
let ndisplay = displays.len();
|
let ndisplay = displays.len();
|
||||||
if ndisplay <= current {
|
if ndisplay <= current {
|
||||||
bail!(
|
bail!(
|
||||||
@ -761,52 +761,6 @@ pub fn refresh() {
|
|||||||
Display::refresh_size();
|
Display::refresh_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[cfg(not(all(windows, feature = "virtual_display_driver")))]
|
|
||||||
fn try_get_displays() -> ResultType<Vec<Display>> {
|
|
||||||
Ok(Display::all()?)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
|
||||||
fn no_displays(displays: &Vec<Display>) -> bool {
|
|
||||||
let display_len = displays.len();
|
|
||||||
if display_len == 0 {
|
|
||||||
true
|
|
||||||
} else if display_len == 1 {
|
|
||||||
let display = &displays[0];
|
|
||||||
let dummy_display_side_max_size = 800;
|
|
||||||
if display.width() > dummy_display_side_max_size
|
|
||||||
|| display.height() > dummy_display_side_max_size
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let any_real = crate::platform::resolutions(&display.name())
|
|
||||||
.iter()
|
|
||||||
.any(|r| {
|
|
||||||
(r.height as usize) > dummy_display_side_max_size
|
|
||||||
|| (r.width as usize) > dummy_display_side_max_size
|
|
||||||
});
|
|
||||||
!any_real
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(windows, feature = "virtual_display_driver"))]
|
|
||||||
fn try_get_displays() -> ResultType<Vec<Display>> {
|
|
||||||
// let mut displays = Display::all()?;
|
|
||||||
// if no_displays(&displays) {
|
|
||||||
// log::debug!("no displays, create virtual display");
|
|
||||||
// if let Err(e) = virtual_display_manager::plug_in_headless() {
|
|
||||||
// log::error!("plug in headless failed {}", e);
|
|
||||||
// } else {
|
|
||||||
// displays = Display::all()?;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
Ok(Display::all()?)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn start_uac_elevation_check() {
|
fn start_uac_elevation_check() {
|
||||||
static START: Once = Once::new();
|
static START: Once = Once::new();
|
||||||
|
@ -254,6 +254,10 @@ impl InvokeUiSession for SciterHandler {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_platform_additions(&self, _data: &str) {
|
||||||
|
// Ignore for sciter version.
|
||||||
|
}
|
||||||
|
|
||||||
fn on_connected(&self, conn_type: ConnType) {
|
fn on_connected(&self, conn_type: ConnType) {
|
||||||
match conn_type {
|
match conn_type {
|
||||||
ConnType::RDP => {}
|
ConnType::RDP => {}
|
||||||
|
@ -237,11 +237,19 @@ impl<T: InvokeUiSession> Session<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_displays_as_individual_windows(&self) -> String {
|
pub fn get_displays_as_individual_windows(&self) -> String {
|
||||||
self.lc.read().unwrap().displays_as_individual_windows.clone()
|
self.lc
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.displays_as_individual_windows
|
||||||
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_use_all_my_displays_for_the_remote_session(&self) -> String {
|
pub fn get_use_all_my_displays_for_the_remote_session(&self) -> String {
|
||||||
self.lc.read().unwrap().use_all_my_displays_for_the_remote_session.clone()
|
self.lc
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.use_all_my_displays_for_the_remote_session
|
||||||
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_reverse_mouse_wheel(&self, value: String) {
|
pub fn save_reverse_mouse_wheel(&self, value: String) {
|
||||||
@ -249,11 +257,17 @@ impl<T: InvokeUiSession> Session<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_displays_as_individual_windows(&self, value: String) {
|
pub fn save_displays_as_individual_windows(&self, value: String) {
|
||||||
self.lc.write().unwrap().save_displays_as_individual_windows(value);
|
self.lc
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.save_displays_as_individual_windows(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_use_all_my_displays_for_the_remote_session(&self, value: String) {
|
pub fn save_use_all_my_displays_for_the_remote_session(&self, value: String) {
|
||||||
self.lc.write().unwrap().save_use_all_my_displays_for_the_remote_session(value);
|
self.lc
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.save_use_all_my_displays_for_the_remote_session(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_view_style(&self, value: String) {
|
pub fn save_view_style(&self, value: String) {
|
||||||
@ -310,6 +324,18 @@ impl<T: InvokeUiSession> Session<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn toggle_virtual_display(&self, index: i32, on: bool) {
|
||||||
|
let mut misc = Misc::new();
|
||||||
|
misc.set_toggle_virtual_display(ToggleVirtualDisplay {
|
||||||
|
display: index,
|
||||||
|
on,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let mut msg_out = Message::new();
|
||||||
|
msg_out.set_misc(misc);
|
||||||
|
self.send(Data::Message(msg_out));
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "flutter"))]
|
#[cfg(not(feature = "flutter"))]
|
||||||
pub fn refresh_video(&self, _display: i32) {
|
pub fn refresh_video(&self, _display: i32) {
|
||||||
self.send(Data::Message(LoginConfigHandler::refresh()));
|
self.send(Data::Message(LoginConfigHandler::refresh()));
|
||||||
@ -1175,6 +1201,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
|
|||||||
fn switch_display(&self, display: &SwitchDisplay);
|
fn switch_display(&self, display: &SwitchDisplay);
|
||||||
fn set_peer_info(&self, peer_info: &PeerInfo); // flutter
|
fn set_peer_info(&self, peer_info: &PeerInfo); // flutter
|
||||||
fn set_displays(&self, displays: &Vec<DisplayInfo>);
|
fn set_displays(&self, displays: &Vec<DisplayInfo>);
|
||||||
|
fn set_platform_additions(&self, data: &str);
|
||||||
fn on_connected(&self, conn_type: ConnType);
|
fn on_connected(&self, conn_type: ConnType);
|
||||||
fn update_privacy_mode(&self);
|
fn update_privacy_mode(&self);
|
||||||
fn set_permission(&self, name: &str, value: bool);
|
fn set_permission(&self, name: &str, value: bool);
|
||||||
|
@ -18,10 +18,18 @@ lazy_static::lazy_static! {
|
|||||||
struct VirtualDisplayManager {
|
struct VirtualDisplayManager {
|
||||||
headless_index_name: Option<(u32, String)>,
|
headless_index_name: Option<(u32, String)>,
|
||||||
peer_index_name: HashMap<u32, String>,
|
peer_index_name: HashMap<u32, String>,
|
||||||
|
is_driver_installed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualDisplayManager {
|
impl VirtualDisplayManager {
|
||||||
fn prepare_driver() -> ResultType<()> {
|
fn prepare_driver(&mut self) -> ResultType<()> {
|
||||||
|
if !self.is_driver_installed {
|
||||||
|
self.install_update_driver()?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn install_update_driver(&mut self) -> ResultType<()> {
|
||||||
if let Err(e) = virtual_display::create_device() {
|
if let Err(e) = virtual_display::create_device() {
|
||||||
if !e.to_string().contains("Device is already created") {
|
if !e.to_string().contains("Device is already created") {
|
||||||
bail!("Create device failed {}", e);
|
bail!("Create device failed {}", e);
|
||||||
@ -29,9 +37,8 @@ impl VirtualDisplayManager {
|
|||||||
}
|
}
|
||||||
// Reboot is not required for this case.
|
// Reboot is not required for this case.
|
||||||
let mut _reboot_required = false;
|
let mut _reboot_required = false;
|
||||||
allow_err!(virtual_display::install_update_driver(
|
virtual_display::install_update_driver(&mut _reboot_required)?;
|
||||||
&mut _reboot_required
|
self.is_driver_installed = true;
|
||||||
));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +55,7 @@ impl VirtualDisplayManager {
|
|||||||
|
|
||||||
pub fn plug_in_headless() -> ResultType<()> {
|
pub fn plug_in_headless() -> ResultType<()> {
|
||||||
let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap();
|
let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap();
|
||||||
VirtualDisplayManager::prepare_driver()?;
|
manager.prepare_driver()?;
|
||||||
let modes = [virtual_display::MonitorMode {
|
let modes = [virtual_display::MonitorMode {
|
||||||
width: 1920,
|
width: 1920,
|
||||||
height: 1080,
|
height: 1080,
|
||||||
@ -93,9 +100,55 @@ fn get_new_device_name(device_names: &HashSet<String>) -> String {
|
|||||||
"".to_string()
|
"".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_virtual_displays() -> Vec<u32> {
|
||||||
|
VIRTUAL_DISPLAY_MANAGER
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.peer_index_name
|
||||||
|
.keys()
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn plug_in_index_modes(
|
||||||
|
idx: u32,
|
||||||
|
mut modes: Vec<virtual_display::MonitorMode>,
|
||||||
|
) -> ResultType<()> {
|
||||||
|
let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap();
|
||||||
|
manager.prepare_driver()?;
|
||||||
|
if !manager.peer_index_name.contains_key(&idx) {
|
||||||
|
let device_names = windows::get_device_names();
|
||||||
|
if modes.is_empty() {
|
||||||
|
modes.push(virtual_display::MonitorMode {
|
||||||
|
width: 1920,
|
||||||
|
height: 1080,
|
||||||
|
sync: 60,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
match VirtualDisplayManager::plug_in_monitor(idx, modes.as_slice()) {
|
||||||
|
Ok(_) => {
|
||||||
|
let device_name = get_new_device_name(&device_names);
|
||||||
|
manager.peer_index_name.insert(idx, device_name);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Plug in monitor failed {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_all() -> ResultType<()> {
|
||||||
|
let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap();
|
||||||
|
manager.install_update_driver()?;
|
||||||
|
manager.peer_index_name.clear();
|
||||||
|
manager.headless_index_name = None;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn plug_in_peer_request(modes: Vec<Vec<virtual_display::MonitorMode>>) -> ResultType<Vec<u32>> {
|
pub fn plug_in_peer_request(modes: Vec<Vec<virtual_display::MonitorMode>>) -> ResultType<Vec<u32>> {
|
||||||
let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap();
|
let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap();
|
||||||
VirtualDisplayManager::prepare_driver()?;
|
manager.prepare_driver()?;
|
||||||
|
|
||||||
let mut indices: Vec<u32> = Vec::new();
|
let mut indices: Vec<u32> = Vec::new();
|
||||||
for m in modes.iter() {
|
for m in modes.iter() {
|
||||||
@ -119,9 +172,9 @@ pub fn plug_in_peer_request(modes: Vec<Vec<virtual_display::MonitorMode>>) -> Re
|
|||||||
Ok(indices)
|
Ok(indices)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plug_out_peer_request(modes: &[u32]) -> ResultType<()> {
|
pub fn plug_out_peer_request(indices: &[u32]) -> ResultType<()> {
|
||||||
let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap();
|
let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap();
|
||||||
for idx in modes.iter() {
|
for idx in indices.iter() {
|
||||||
if manager.peer_index_name.contains_key(idx) {
|
if manager.peer_index_name.contains_key(idx) {
|
||||||
allow_err!(virtual_display::plug_out_monitor(*idx));
|
allow_err!(virtual_display::plug_out_monitor(*idx));
|
||||||
manager.peer_index_name.remove(idx);
|
manager.peer_index_name.remove(idx);
|
||||||
|
Loading…
Reference in New Issue
Block a user