From ff20acc3678f610c2260f1f73429b30098a8705c Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Fri, 13 Oct 2023 23:01:19 +0530 Subject: [PATCH 001/114] add rust bindings to get peers data Signed-off-by: Sahil Yeole --- src/flutter_ffi.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index c931d8926..2a714d949 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -886,6 +886,72 @@ pub fn main_load_recent_peers_sync() -> SyncReturn { SyncReturn("".to_string()) } +pub fn main_load_fav_peers_sync() -> SyncReturn { + if !config::APP_DIR.read().unwrap().is_empty() { + let favs = get_fav(); + let mut recent = PeerConfig::peers(None); + let mut lan = config::LanPeers::load() + .peers + .iter() + .filter(|d| recent.iter().all(|r| r.0 != d.id)) + .map(|d| { + ( + d.id.clone(), + SystemTime::UNIX_EPOCH, + PeerConfig { + info: PeerInfoSerde { + username: d.username.clone(), + hostname: d.hostname.clone(), + platform: d.platform.clone(), + }, + ..Default::default() + }, + ) + }) + .collect(); + recent.append(&mut lan); + let peers: Vec> = recent + .into_iter() + .filter_map(|(id, _, p)| { + if favs.contains(&id) { + Some(peer_to_map(id, p)) + } else { + None + } + }) + .collect(); + + let data = HashMap::from([ + ("name", "load_fav_peers".to_owned()), + ( + "peers", + serde_json::ser::to_string(&peers).unwrap_or("".to_owned()), + ), + ]); + return SyncReturn(serde_json::ser::to_string(&data).unwrap_or("".to_owned())); + } + SyncReturn("".to_string()) +} + +pub fn main_load_lan_peers_sync() -> SyncReturn { + let data = HashMap::from([ + ("name", "load_lan_peers".to_owned()), + ( + "peers", + serde_json::to_string(&get_lan_peers()).unwrap_or_default(), + ), + ]); + return SyncReturn(serde_json::ser::to_string(&data).unwrap_or("".to_owned())); +} + +pub fn main_load_ab_sync() -> SyncReturn { + return SyncReturn(serde_json::to_string(&config::Ab::load()).unwrap_or_default()); +} + +pub fn main_load_group_sync() -> SyncReturn { + return SyncReturn(serde_json::to_string(&config::Group::load()).unwrap_or_default()); +} + pub fn main_load_recent_peers_for_ab(filter: String) -> String { let id_filters = serde_json::from_str::>(&filter).unwrap_or_default(); let id_filters = if id_filters.is_empty() { From f6b5c752f4125f8290c5ac205bd5d7ba8ca4b053 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Fri, 13 Oct 2023 23:10:31 +0530 Subject: [PATCH 002/114] add autocomplete feat Signed-off-by: Sahil Yeole --- .../lib/desktop/pages/connection_page.dart | 166 ++++++++++++++---- 1 file changed, 136 insertions(+), 30 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 359746f4c..029899150 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -11,6 +11,7 @@ import 'package:flutter_hbb/models/state_model.dart'; import 'package:get/get.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:window_manager/window_manager.dart'; +import 'package:flutter_hbb/models/peer_model.dart'; import '../../common.dart'; import '../../common/formatter/id_formatter.dart'; @@ -41,6 +42,7 @@ class _ConnectionPageState extends State var svcIsUsingPublicServer = true.obs; bool isWindowMinimized = false; + List peers = []; @override void initState() { @@ -145,6 +147,7 @@ class _ConnectionPageState extends State /// UI for the remote ID TextField. /// Search for a peer and connect to it if the id exists. Widget _buildRemoteIDTextField(BuildContext context) { + final TextEditingController fieldTextEditingController = TextEditingController.fromValue(_idController.value); var w = Container( width: 320 + 20 * 2, padding: const EdgeInsets.fromLTRB(20, 24, 20, 22), @@ -171,36 +174,139 @@ class _ConnectionPageState extends State Row( children: [ Expanded( - child: Obx( - () => TextField( - maxLength: 90, - autocorrect: false, - enableSuggestions: false, - keyboardType: TextInputType.visiblePassword, - focusNode: _idFocusNode, - style: const TextStyle( - fontFamily: 'WorkSans', - fontSize: 22, - height: 1.4, - ), - maxLines: 1, - cursorColor: - Theme.of(context).textTheme.titleLarge?.color, - decoration: InputDecoration( - filled: false, - counterText: '', - hintText: _idInputFocused.value - ? null - : translate('Enter Remote ID'), - contentPadding: const EdgeInsets.symmetric( - horizontal: 15, vertical: 13)), - controller: _idController, - inputFormatters: [IDTextInputFormatter()], - onSubmitted: (s) { - onConnect(); - }, - ), - ), + child: + Autocomplete( + optionsBuilder: (TextEditingValue textEditingValue) { + if (textEditingValue.text == '') { + return const Iterable.empty(); + } + else { + peers.clear(); + Map recentPeers = jsonDecode(bind.mainLoadRecentPeersSync()); + Map favPeers = jsonDecode(bind.mainLoadFavPeersSync()); + Map lanPeers = jsonDecode(bind.mainLoadLanPeersSync()); + Map abPeers = jsonDecode(bind.mainLoadAbSync()); + Map groupPeers = jsonDecode(bind.mainLoadGroupSync()); + + Map combinedPeers = {}; + + void mergePeers(Map peers) { + if (peers.containsKey("peers")) { + dynamic peerData = peers["peers"]; + + if (peerData is String) { + try { + peerData = jsonDecode(peerData); + } catch (e) { + print("Error decoding peers: $e"); + return; + } + } + + if (peerData is List) { + for (var peer in peerData) { + if (peer is Map && peer.containsKey("id")) { + String id = peer["id"]; + if (id != null && !combinedPeers.containsKey(id)) { + combinedPeers[id] = peer; + } + } + } + } + } + } + + mergePeers(recentPeers); + mergePeers(favPeers); + mergePeers(lanPeers); + mergePeers(abPeers); + mergePeers(groupPeers); + + for (var peer in combinedPeers.values) { + peers.add(Peer.fromJson(peer)); + } + + return peers.where((peer) => + peer.id.toLowerCase().contains(textEditingValue.text.toLowerCase()) || + peer.username.toLowerCase().contains(textEditingValue.text.toLowerCase()) || + peer.hostname.toLowerCase().contains(textEditingValue.text.toLowerCase()) || + peer.platform.toLowerCase().contains(textEditingValue.text.toLowerCase())) + .toList(); + } + }, + + fieldViewBuilder: (BuildContext context, + TextEditingController fieldTextEditingController, + FocusNode fieldFocusNode , + VoidCallback onFieldSubmitted, + + ) { + return Obx(() => + TextField( + maxLength: 90, + autocorrect: false, + enableSuggestions: false, + keyboardType: TextInputType.visiblePassword, + // focusNode: _idFocusNode, + focusNode: fieldFocusNode, + style: const TextStyle( + fontFamily: 'WorkSans', + fontSize: 22, + height: 1.4, + ), + maxLines: 1, + cursorColor: Theme.of(context).textTheme.titleLarge?.color, + decoration: InputDecoration( + filled: false, + counterText: '', + hintText: _idInputFocused.value + ? null + : translate('Enter Remote ID'), + contentPadding: const EdgeInsets.symmetric( + horizontal: 15, vertical: 13)), + // controller: _idController, + controller: fieldTextEditingController, + inputFormatters: [IDTextInputFormatter()], + onSubmitted: (s) { + onConnect(); + }, + )); + }, + optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { + return Align( + alignment: Alignment.topLeft, + child: Material( + elevation: 4.0, + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: 200.0, + ), + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: options.map((peer) { + return ListTile( + // title: Text(peer.id), + title: Text(peer.id.length <= 6 ? peer.id : peer.id.substring(0, 6)), + subtitle: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(peer.username), + Text(peer.hostname), + Text(peer.platform), + for (var tag in peer.tags) + Text(tag), + ], + ), + onTap: () { + onSelected(peer); + }, + ); + }).toList(), + )))) + ); + }, + ) ), ], ), From bbd7cf306a1937ed5cefa486826b46743e0339f7 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Fri, 13 Oct 2023 23:28:54 +0530 Subject: [PATCH 003/114] handle id whitespaces for autocomplete Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 029899150..0e1c65896 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -226,6 +226,13 @@ class _ConnectionPageState extends State peers.add(Peer.fromJson(peer)); } + if (textEditingValue.text.contains(" ")) { + textEditingValue = TextEditingValue( + text: textEditingValue.text.replaceAll(" ", ""), + selection: textEditingValue.selection, + ); + } + return peers.where((peer) => peer.id.toLowerCase().contains(textEditingValue.text.toLowerCase()) || peer.username.toLowerCase().contains(textEditingValue.text.toLowerCase()) || From 83d47aed2d94b6817e8a25e58abcbb677d32c33d Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Sat, 14 Oct 2023 01:55:04 +0530 Subject: [PATCH 004/114] update UI for autocomplete Signed-off-by: Sahil Yeole --- .../lib/desktop/pages/connection_page.dart | 156 ++++++++++++++---- 1 file changed, 126 insertions(+), 30 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 0e1c65896..959a94a40 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -16,6 +16,7 @@ import 'package:flutter_hbb/models/peer_model.dart'; import '../../common.dart'; import '../../common/formatter/id_formatter.dart'; import '../../common/widgets/peer_tab_page.dart'; +import '../../common/widgets/peer_card.dart'; import '../../models/platform_model.dart'; import '../widgets/button.dart'; @@ -43,6 +44,13 @@ class _ConnectionPageState extends State bool isWindowMinimized = false; List peers = []; + List _frontN(List list, int n) { + if (list.length <= n) { + return list; + } else { + return list.sublist(0, n); + } + } @override void initState() { @@ -280,37 +288,27 @@ class _ConnectionPageState extends State )); }, optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { - return Align( - alignment: Alignment.topLeft, - child: Material( - elevation: 4.0, - child: ConstrainedBox( - constraints: BoxConstraints( - maxHeight: 200.0, + double maxHeight = 0; + for (var peer in options) { + if (maxHeight < 200) + maxHeight += 47; + } + return Align( + alignment: Alignment.topLeft, + child: Material( + elevation: 4, + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: maxHeight, + maxWidth: 320, + ), + child: ListView( + children: options + .map((peer) => _buildPeerTile(context, peer, null)) + .toList() + ), ), - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - children: options.map((peer) { - return ListTile( - // title: Text(peer.id), - title: Text(peer.id.length <= 6 ? peer.id : peer.id.substring(0, 6)), - subtitle: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(peer.username), - Text(peer.hostname), - Text(peer.platform), - for (var tag in peer.tags) - Text(tag), - ], - ), - onTap: () { - onSelected(peer); - }, - ); - }).toList(), - )))) + ), ); }, ) @@ -342,6 +340,104 @@ class _ConnectionPageState extends State constraints: const BoxConstraints(maxWidth: 600), child: w); } + Widget _buildPeerTile( + BuildContext context, Peer peer, Rx? deco) { + final double _tileRadius = 5; + final name = + '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; + final greyStyle = TextStyle( + fontSize: 11, + color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6)); + final child = Container( + height: 42, + margin: EdgeInsets.only(bottom: 5), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Container( + decoration: BoxDecoration( + color: str2color('${peer.id}${peer.platform}', 0x7f), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(_tileRadius), + bottomLeft: Radius.circular(_tileRadius), + ), + ), + alignment: Alignment.center, + width: 42, + height: null, + child: getPlatformImage(peer.platform, size: 30) + .paddingAll(6), + ), + Expanded( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.background, + borderRadius: BorderRadius.only( + topRight: Radius.circular(_tileRadius), + bottomRight: Radius.circular(_tileRadius), + ), + ), + child: Row( + children: [ + Expanded( + child: Column( + children: [ + Row(children: [ + getOnline(8, peer.online), + Expanded( + child: Text( + peer.alias.isEmpty ? formatID(peer.id) : peer.alias, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall, + )), + ]).marginOnly(top: 2), + Align( + alignment: Alignment.centerLeft, + child: Text( + name, + style: greyStyle, + textAlign: TextAlign.start, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ).marginOnly(top: 2), + ), + ], + ).paddingOnly(left: 10.0, top: 3.0), + ), + ) + ], + )); + final colors = + _frontN(peer.tags, 25).map((e) => gFFI.abModel.getTagColor(e)).toList(); + return Tooltip( + message: isMobile + ? '' + : peer.tags.isNotEmpty + ? '${translate('Tags')}: ${peer.tags.join(', ')}' + : '', + child: Stack(children: [ + deco == null + ? child + : Obx( + () => Container( + foregroundDecoration: deco.value, + child: child, + ), + ), + if (colors.isNotEmpty) + Positioned( + top: 5, + right: 10, + child: CustomPaint( + painter: TagPainter(radius: 3, colors: colors), + ), + ) + ]), + ); + } + Widget buildStatus() { final em = 14.0; return Container( From 95e3fb24f3a4673ec1b9b5fe4628ceaf624ee9d9 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Sat, 14 Oct 2023 03:09:59 +0530 Subject: [PATCH 005/114] add ontap for autocomplete Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 959a94a40..a3b6d646d 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -155,7 +155,6 @@ class _ConnectionPageState extends State /// UI for the remote ID TextField. /// Search for a peer and connect to it if the id exists. Widget _buildRemoteIDTextField(BuildContext context) { - final TextEditingController fieldTextEditingController = TextEditingController.fromValue(_idController.value); var w = Container( width: 320 + 20 * 2, padding: const EdgeInsets.fromLTRB(20, 24, 20, 22), @@ -348,7 +347,13 @@ class _ConnectionPageState extends State final greyStyle = TextStyle( fontSize: 11, color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6)); - final child = Container( + final child = GestureDetector( + onTap: () { + _idController.id = peer.id; + onConnect(); + }, + child: + Container( height: 42, margin: EdgeInsets.only(bottom: 5), child: Row( @@ -408,7 +413,7 @@ class _ConnectionPageState extends State ), ) ], - )); + ))); final colors = _frontN(peer.tags, 25).map((e) => gFFI.abModel.getTagColor(e)).toList(); return Tooltip( From 7b5801920b8a54e43653c1c774721a18a24df289 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Sun, 15 Oct 2023 03:34:53 +0530 Subject: [PATCH 006/114] update focusnode and texteditingcontroller for autocomplete Signed-off-by: Sahil Yeole --- .../lib/desktop/pages/connection_page.dart | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index a3b6d646d..db233fdbb 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -253,15 +253,20 @@ class _ConnectionPageState extends State TextEditingController fieldTextEditingController, FocusNode fieldFocusNode , VoidCallback onFieldSubmitted, - ) { + fieldTextEditingController.text = _idController.text; + fieldFocusNode.addListener(() { + _idInputFocused.value = fieldFocusNode.hasFocus; + // select all to faciliate removing text, just following the behavior of address input of chrome + _idController.selection = TextSelection( + baseOffset: 0, extentOffset: _idController.value.text.length); + }); return Obx(() => TextField( maxLength: 90, autocorrect: false, enableSuggestions: false, keyboardType: TextInputType.visiblePassword, - // focusNode: _idFocusNode, focusNode: fieldFocusNode, style: const TextStyle( fontFamily: 'WorkSans', @@ -278,11 +283,22 @@ class _ConnectionPageState extends State : translate('Enter Remote ID'), contentPadding: const EdgeInsets.symmetric( horizontal: 15, vertical: 13)), - // controller: _idController, controller: fieldTextEditingController, inputFormatters: [IDTextInputFormatter()], + onChanged: (v) { + _idController.id = v; + }, onSubmitted: (s) { - onConnect(); + if (s == '') { + return; + } + try { + final id = int.parse(s); + _idController.id = s; + onConnect(); + } catch (_) { + return; + } }, )); }, @@ -349,8 +365,10 @@ class _ConnectionPageState extends State color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6)); final child = GestureDetector( onTap: () { - _idController.id = peer.id; - onConnect(); + setState(() { + _idController.id = peer.id; + FocusScope.of(context).unfocus(); + }); }, child: Container( From 8127ce18a3b7f42e666a2a3079f9d89974768518 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Sun, 15 Oct 2023 04:53:57 +0530 Subject: [PATCH 007/114] optimise autocomplete Signed-off-by: Sahil Yeole --- .../lib/desktop/pages/connection_page.dart | 95 ++++++++++--------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index db233fdbb..8ca3c549a 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -152,9 +152,57 @@ class _ConnectionPageState extends State connect(context, id, isFileTransfer: isFileTransfer); } + void getAllPeers(){ + peers.clear(); + Map recentPeers = jsonDecode(bind.mainLoadRecentPeersSync()); + Map favPeers = jsonDecode(bind.mainLoadFavPeersSync()); + Map lanPeers = jsonDecode(bind.mainLoadLanPeersSync()); + Map abPeers = jsonDecode(bind.mainLoadAbSync()); + Map groupPeers = jsonDecode(bind.mainLoadGroupSync()); + + Map combinedPeers = {}; + + void mergePeers(Map peers) { + if (peers.containsKey("peers")) { + dynamic peerData = peers["peers"]; + + if (peerData is String) { + try { + peerData = jsonDecode(peerData); + } catch (e) { + print("Error decoding peers: $e"); + return; + } + } + + if (peerData is List) { + for (var peer in peerData) { + if (peer is Map && peer.containsKey("id")) { + String id = peer["id"]; + if (id != null && !combinedPeers.containsKey(id)) { + combinedPeers[id] = peer; + } + } + } + } + } + } + + mergePeers(recentPeers); + mergePeers(favPeers); + mergePeers(lanPeers); + mergePeers(abPeers); + mergePeers(groupPeers); + + for (var peer in combinedPeers.values) { + peers.add(Peer.fromJson(peer)); + } + } + /// UI for the remote ID TextField. - /// Search for a peer and connect to it if the id exists. + /// Search for a peer. Widget _buildRemoteIDTextField(BuildContext context) { + getAllPeers(); var w = Container( width: 320 + 20 * 2, padding: const EdgeInsets.fromLTRB(20, 24, 20, 22), @@ -188,51 +236,6 @@ class _ConnectionPageState extends State return const Iterable.empty(); } else { - peers.clear(); - Map recentPeers = jsonDecode(bind.mainLoadRecentPeersSync()); - Map favPeers = jsonDecode(bind.mainLoadFavPeersSync()); - Map lanPeers = jsonDecode(bind.mainLoadLanPeersSync()); - Map abPeers = jsonDecode(bind.mainLoadAbSync()); - Map groupPeers = jsonDecode(bind.mainLoadGroupSync()); - - Map combinedPeers = {}; - - void mergePeers(Map peers) { - if (peers.containsKey("peers")) { - dynamic peerData = peers["peers"]; - - if (peerData is String) { - try { - peerData = jsonDecode(peerData); - } catch (e) { - print("Error decoding peers: $e"); - return; - } - } - - if (peerData is List) { - for (var peer in peerData) { - if (peer is Map && peer.containsKey("id")) { - String id = peer["id"]; - if (id != null && !combinedPeers.containsKey(id)) { - combinedPeers[id] = peer; - } - } - } - } - } - } - - mergePeers(recentPeers); - mergePeers(favPeers); - mergePeers(lanPeers); - mergePeers(abPeers); - mergePeers(groupPeers); - - for (var peer in combinedPeers.values) { - peers.add(Peer.fromJson(peer)); - } - if (textEditingValue.text.contains(" ")) { textEditingValue = TextEditingValue( text: textEditingValue.text.replaceAll(" ", ""), From 2d6322f7993e7fac262ad81e87625a35dc35dfe0 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Sun, 15 Oct 2023 04:59:03 +0530 Subject: [PATCH 008/114] remove extra parameter from peer tile Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 8ca3c549a..f4f92b88f 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -322,7 +322,7 @@ class _ConnectionPageState extends State ), child: ListView( children: options - .map((peer) => _buildPeerTile(context, peer, null)) + .map((peer) => _buildPeerTile(context, peer)) .toList() ), ), @@ -359,7 +359,7 @@ class _ConnectionPageState extends State } Widget _buildPeerTile( - BuildContext context, Peer peer, Rx? deco) { + BuildContext context, Peer peer) { final double _tileRadius = 5; final name = '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; @@ -444,14 +444,7 @@ class _ConnectionPageState extends State ? '${translate('Tags')}: ${peer.tags.join(', ')}' : '', child: Stack(children: [ - deco == null - ? child - : Obx( - () => Container( - foregroundDecoration: deco.value, - child: child, - ), - ), + child, if (colors.isNotEmpty) Positioned( top: 5, From 4f4498666e78cc413d46123caf2a6bf4149d581e Mon Sep 17 00:00:00 2001 From: dignow Date: Mon, 16 Oct 2023 23:19:07 +0800 Subject: [PATCH 009/114] fix, remove warns, misspellings Signed-off-by: dignow --- flutter/lib/models/chat_model.dart | 10 +++++----- flutter/lib/models/model.dart | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/flutter/lib/models/chat_model.dart b/flutter/lib/models/chat_model.dart index 77eeb3a7e..93cdbbed5 100644 --- a/flutter/lib/models/chat_model.dart +++ b/flutter/lib/models/chat_model.dart @@ -103,7 +103,7 @@ class ChatModel with ChangeNotifier { void setOverlayState(BlockableOverlayState blockableOverlayState) { _blockableOverlayState = blockableOverlayState; - _blockableOverlayState!.addMiddleBlockedListener((v) { + _blockableOverlayState.addMiddleBlockedListener((v) { if (!v) { isWindowFocus.value = false; if (isWindowFocus.value) { @@ -197,9 +197,9 @@ class ChatModel with ChangeNotifier { showChatWindowOverlay({Offset? chatInitPos}) { if (chatWindowOverlayEntry != null) return; isWindowFocus.value = true; - _blockableOverlayState?.setMiddleBlocked(true); + _blockableOverlayState.setMiddleBlocked(true); - final overlayState = _blockableOverlayState?.state; + final overlayState = _blockableOverlayState.state; if (overlayState == null) return; if (isMobile && !gFFI.chatModel.currentKey.isOut && // not in remote page @@ -212,7 +212,7 @@ class ChatModel with ChangeNotifier { onPointerDown: (_) { if (!isWindowFocus.value) { isWindowFocus.value = true; - _blockableOverlayState?.setMiddleBlocked(true); + _blockableOverlayState.setMiddleBlocked(true); } }, child: DraggableChatWindow( @@ -228,7 +228,7 @@ class ChatModel with ChangeNotifier { hideChatWindowOverlay() { if (chatWindowOverlayEntry != null) { - _blockableOverlayState?.setMiddleBlocked(false); + _blockableOverlayState.setMiddleBlocked(false); chatWindowOverlayEntry!.remove(); chatWindowOverlayEntry = null; return; diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index d257f3290..56e18d309 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -689,12 +689,12 @@ class FfiModel with ChangeNotifier { sessionId: sessionId, arg: 'view-only')); } if (connType == ConnType.defaultConn) { - final platformDdditions = evt['platform_additions']; - if (platformDdditions != null && platformDdditions != '') { + final platformAdditions = evt['platform_additions']; + if (platformAdditions != null && platformAdditions != '') { try { - _pi.platformDdditions = json.decode(platformDdditions); + _pi.platformAdditions = json.decode(platformAdditions); } catch (e) { - debugPrint('Failed to decode platformDdditions $e'); + debugPrint('Failed to decode platformAdditions $e'); } } } @@ -2203,13 +2203,13 @@ class PeerInfo with ChangeNotifier { List displays = []; Features features = Features(); List resolutions = []; - Map platformDdditions = {}; + Map platformAdditions = {}; RxInt displaysCount = 0.obs; RxBool isSet = false.obs; - bool get isWayland => platformDdditions['is_wayland'] == true; - bool get isHeadless => platformDdditions['headless'] == true; + bool get isWayland => platformAdditions['is_wayland'] == true; + bool get isHeadless => platformAdditions['headless'] == true; bool get isSupportMultiDisplay => isDesktop && isSupportMultiUiSession; From 4a42e3ef1bbc58b809260d0f18ffdf398f5a90b3 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Mon, 16 Oct 2023 23:06:14 +0530 Subject: [PATCH 010/114] add padding autocomplete Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index f4f92b88f..0e43b7ba4 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -309,7 +309,7 @@ class _ConnectionPageState extends State double maxHeight = 0; for (var peer in options) { if (maxHeight < 200) - maxHeight += 47; + maxHeight += 52; } return Align( alignment: Alignment.topLeft, @@ -320,10 +320,13 @@ class _ConnectionPageState extends State maxHeight: maxHeight, maxWidth: 320, ), - child: ListView( - children: options - .map((peer) => _buildPeerTile(context, peer)) - .toList() + child: Padding( + padding: const EdgeInsets.only(top: 5), + child: ListView( + children: options + .map((peer) => _buildPeerTile(context, peer)) + .toList() + ), ), ), ), From 26982787ee643811fb0d738921527ac6d2e3a56a Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Mon, 16 Oct 2023 23:36:43 +0530 Subject: [PATCH 011/114] make getAllPeers async Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 0e43b7ba4..1f221aa5e 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -152,13 +152,13 @@ class _ConnectionPageState extends State connect(context, id, isFileTransfer: isFileTransfer); } - void getAllPeers(){ - peers.clear(); - Map recentPeers = jsonDecode(bind.mainLoadRecentPeersSync()); - Map favPeers = jsonDecode(bind.mainLoadFavPeersSync()); - Map lanPeers = jsonDecode(bind.mainLoadLanPeersSync()); - Map abPeers = jsonDecode(bind.mainLoadAbSync()); - Map groupPeers = jsonDecode(bind.mainLoadGroupSync()); + Future getAllPeers() async { + peers.clear(); + Map recentPeers = jsonDecode(await bind.mainLoadRecentPeersSync()); + Map favPeers = jsonDecode(await bind.mainLoadFavPeersSync()); + Map lanPeers = jsonDecode(await bind.mainLoadLanPeersSync()); + Map abPeers = jsonDecode(await bind.mainLoadAbSync()); + Map groupPeers = jsonDecode(await bind.mainLoadGroupSync()); Map combinedPeers = {}; @@ -170,7 +170,7 @@ class _ConnectionPageState extends State try { peerData = jsonDecode(peerData); } catch (e) { - print("Error decoding peers: $e"); + debugPrint("Error decoding peers: $e"); return; } } From 182f2ae26e8ad6a9b655ed54b71c0e659ed1a59f Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 17 Oct 2023 01:34:00 +0530 Subject: [PATCH 012/114] add search for alias Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 1f221aa5e..78f7844a9 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -247,6 +247,7 @@ class _ConnectionPageState extends State peer.id.toLowerCase().contains(textEditingValue.text.toLowerCase()) || peer.username.toLowerCase().contains(textEditingValue.text.toLowerCase()) || peer.hostname.toLowerCase().contains(textEditingValue.text.toLowerCase()) || + peer.alias.toLowerCase().contains(textEditingValue.text.toLowerCase()) || peer.platform.toLowerCase().contains(textEditingValue.text.toLowerCase())) .toList(); } From 8b0b45e08990b3a6ae4442d8eeec0278280764b9 Mon Sep 17 00:00:00 2001 From: Ibnul Mutaki Date: Tue, 17 Oct 2023 07:55:26 +0700 Subject: [PATCH 013/114] improve ID lang trans --- src/lang/id.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lang/id.rs b/src/lang/id.rs index 2f37c3f07..892381374 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -52,7 +52,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Home", ""), ("Audio Input", "Input Audio"), ("Enhancements", "Peningkatan"), - ("Hardware Codec", "Codec Perangkat Keras"), + ("Hardware Codec", "Kodek Perangkat Keras"), ("Adaptive bitrate", "Kecepatan Bitrate Adaptif"), ("ID Server", "Server ID"), ("Relay Server", "Server Relay"), @@ -352,7 +352,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Dark", "Gelap"), ("Light", "Terang"), ("Follow System", "Ikuti Sistem"), - ("Enable hardware codec", "Aktifkan codec perangkat keras"), + ("Enable hardware codec", "Aktifkan kodek perangkat keras"), ("Unlock Security Settings", "Buka Keamanan Pengaturan"), ("Enable Audio", "Aktifkan Audio"), ("Unlock Network Settings", "Buka Keamanan Pengaturan Jaringan"), @@ -369,7 +369,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Unpin Toolbar", "Batal sematkan Toolbar"), ("Recording", "Perekaman"), ("Directory", "Direktori"), - ("Automatically record incoming sessions", "Secara otomatis merekam sesi masuk"), + ("Automatically record incoming sessions", "Otomatis merekam sesi masuk"), ("Change", "Ubah"), ("Start session recording", "Mulai sesi perekaman"), ("Stop session recording", "Hentikan sesi perekaman"), @@ -444,7 +444,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Default View Style", "Gaya Tampilan Default"), ("Default Scroll Style", "Gaya Scroll Default"), ("Default Image Quality", "Kualitas Gambar Default"), - ("Default Codec", "Codec default"), + ("Default Codec", "Kodek default"), ("Bitrate", "Bitrate"), ("FPS", "FPS"), ("Auto", "Otomatis"), @@ -454,9 +454,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Stop voice call", "Hentikan panggilan suara"), ("relay_hint_tip", "Tidak memungkinkan untuk terhubung secara langsung; anda bisa mencoba terhubung via relay. Selain itu, jika ingin menggunakan relay pada percobaan pertama, silahkan tambah akhiran \"/r\" pada ID atau pilih \"Selalu terhubung via relay\" di pilihan sesi terbaru."), ("Reconnect", "Menyambungkan ulang"), - ("Codec", "Codec"), + ("Codec", "Kodek"), ("Resolution", "Resolusi"), - ("No transfers in progress", "Tidak ada transfer data yang sedang berlangsung"), + ("No transfers in progress", "Tidak ada proses transfer data"), ("Set one-time password length", "Atur panjang kata sandi sekali pakai"), ("install_cert_tip", "Install sertifikat RustDesk"), ("confirm_install_cert_tip", "Ini adalah sertifikat pengujian RustDesk, yang dapat dipercaya. Sertifikat ini akan digunakan untuk menginstal driver RustDesk saat diperlukan"), @@ -541,7 +541,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("HSV Color", "Warna HSV"), ("Installation Successful!", "Instalasi berhasil!"), ("Installation failed!", "Instalasi gagal!"), - ("Reverse mouse wheel", "Balikkan arah scroll mouse!"), + ("Reverse mouse wheel", "Balikkan arah scroll mouse"), ("{} sessions", "sesi {}"), ("scam_title", "Kemungkinan Anda Sedang DITIPU!"), ("scam_text1", "Jika Anda sedang berbicara di telepon dengan seseorang yang TIDAK dikenal dan mereka meminta anda untuk menggunakan RustDesk, jangan lanjutkan dan segera tutup panggilan."), @@ -563,6 +563,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("No displays", "Tidak ada tampilan"), ("elevated_switch_display_msg", "Pindah ke tampilan utama, pada mode elevasi, pengggunaan lebih dari satu layar tidak diizinkan"), ("Open in new window", "Buka di jendela baru"), - ("Show displays as individual windows", "Tampilkan layar sebagai jendela terpisah"), + ("Show displays as individual windows", "Tampilkan dengan jendela terpisah"), ].iter().cloned().collect(); } From bf83d552f8fc901c1e2fe04e6cefacfac4883d61 Mon Sep 17 00:00:00 2001 From: dignow Date: Tue, 17 Oct 2023 00:30:34 +0800 Subject: [PATCH 014/114] feat, open multi windows Signed-off-by: dignow --- flutter/lib/common.dart | 112 +++++++++++++++++- flutter/lib/consts.dart | 2 + .../lib/desktop/pages/desktop_home_page.dart | 44 +++---- .../desktop/pages/desktop_setting_page.dart | 2 + .../lib/desktop/pages/remote_tab_page.dart | 39 ++++-- .../lib/desktop/widgets/remote_toolbar.dart | 34 +----- flutter/lib/main.dart | 7 +- flutter/lib/models/model.dart | 51 +++++++- flutter/lib/utils/multi_window_manager.dart | 41 +++++-- libs/hbb_common/src/config.rs | 13 ++ src/client.rs | 13 +- src/flutter_ffi.rs | 43 ++++++- src/lang/ar.rs | 1 + src/lang/ca.rs | 1 + src/lang/cn.rs | 1 + src/lang/cs.rs | 1 + src/lang/da.rs | 1 + src/lang/el.rs | 1 + src/lang/eo.rs | 1 + src/lang/es.rs | 1 + src/lang/fa.rs | 1 + src/lang/fr.rs | 1 + src/lang/hu.rs | 1 + src/lang/id.rs | 1 + src/lang/it.rs | 1 + src/lang/ja.rs | 1 + src/lang/ko.rs | 1 + src/lang/kz.rs | 1 + src/lang/lt.rs | 1 + src/lang/lv.rs | 1 + src/lang/nl.rs | 1 + src/lang/pl.rs | 1 + src/lang/pt_PT.rs | 1 + src/lang/ptbr.rs | 1 + src/lang/ro.rs | 1 + src/lang/sk.rs | 1 + src/lang/sl.rs | 1 + src/lang/sq.rs | 1 + src/lang/sr.rs | 1 + src/lang/sv.rs | 1 + src/lang/template.rs | 1 + src/lang/th.rs | 1 + src/lang/tr.rs | 1 + src/lang/tw.rs | 1 + src/lang/ua.rs | 1 + src/lang/vn.rs | 1 + src/ui_session_interface.rs | 8 ++ 47 files changed, 363 insertions(+), 80 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 1da2dc60a..a67aa27fe 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -14,8 +14,8 @@ import 'package:flutter/services.dart'; import 'package:flutter_hbb/common/formatter/id_formatter.dart'; import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart'; import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; -import 'package:flutter_hbb/models/desktop_render_texture.dart'; import 'package:flutter_hbb/main.dart'; +import 'package:flutter_hbb/models/desktop_render_texture.dart'; import 'package:flutter_hbb/models/peer_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; @@ -53,6 +53,9 @@ int androidVersion = 0; int windowsBuildNumber = 0; DesktopType? desktopType; +bool get isMainDesktopWindow => + desktopType == DesktopType.main || desktopType == DesktopType.cm; + /// Check if the app is running with single view mode. bool isSingleViewApp() { return desktopType == DesktopType.cm; @@ -1672,6 +1675,7 @@ Future _adjustRestoreMainWindowOffset( /// Note that windowId must be provided if it's subwindow Future restoreWindowPosition(WindowType type, {int? windowId, String? peerId}) async { + debugPrintStack(label: "restoreWindowPosition"); if (bind .mainGetEnv(key: "DISABLE_RUSTDESK_RESTORE_WINDOW_POSITION") .isNotEmpty) { @@ -2605,3 +2609,109 @@ bool isChooseDisplayToOpenInNewWindow(PeerInfo pi, SessionID sessionId) => pi.isSupportMultiDisplay && useTextureRender && bind.sessionGetDisplaysAsIndividualWindows(sessionId: sessionId) == 'Y'; + +Future> getScreenListWayland() async { + final screenRectList = []; + if (isMainDesktopWindow) { + for (var screen in await window_size.getScreenList()) { + final scale = kIgnoreDpi ? 1.0 : screen.scaleFactor; + double l = screen.frame.left; + double t = screen.frame.top; + double r = screen.frame.right; + double b = screen.frame.bottom; + final rect = Rect.fromLTRB(l / scale, t / scale, r / scale, b / scale); + screenRectList.add(rect); + } + } else { + final screenList = await rustDeskWinManager.call( + WindowType.Main, kWindowGetScreenList, ''); + try { + for (var screen in jsonDecode(screenList.result) as List) { + final scale = kIgnoreDpi ? 1.0 : screen['scaleFactor']; + double l = screen['frame']['l']; + double t = screen['frame']['t']; + double r = screen['frame']['r']; + double b = screen['frame']['b']; + final rect = Rect.fromLTRB(l / scale, t / scale, r / scale, b / scale); + screenRectList.add(rect); + } + } catch (e) { + debugPrint('Failed to parse screenList: $e'); + } + } + return screenRectList; +} + +Future> getScreenListNotWayland() async { + final screenRectList = []; + final displays = bind.mainGetDisplays(); + if (displays.isEmpty) { + return screenRectList; + } + try { + for (var display in jsonDecode(displays) as List) { + // to-do: scale factor ? + // final scale = kIgnoreDpi ? 1.0 : screen.scaleFactor; + double l = display['x'].toDouble(); + double t = display['y'].toDouble(); + double r = (display['x'] + display['w']).toDouble(); + double b = (display['y'] + display['h']).toDouble(); + screenRectList.add(Rect.fromLTRB(l, t, r, b)); + } + } catch (e) { + debugPrint('Failed to parse displays: $e'); + } + return screenRectList; +} + +Future> getScreenRectList() async { + return bind.mainCurrentIsWayland() + ? await getScreenListWayland() + : await getScreenListNotWayland(); +} + +openMonitorInTheSameTab(int i, FFI ffi, PeerInfo pi) { + final displays = i == kAllDisplayValue + ? List.generate(pi.displays.length, (index) => index) + : [i]; + bind.sessionSwitchDisplay( + sessionId: ffi.sessionId, value: Int32List.fromList(displays)); + ffi.ffiModel.switchToNewDisplay(i, ffi.sessionId, ffi.id); +} + +// Open new tab or window to show this monitor. +// For now just open new window. +// +// screenRect is used to move the new window to the specified screen and set fullscreen. +openMonitorInNewTabOrWindow(int i, String peerId, PeerInfo pi, + {Rect? screenRect}) { + final args = { + 'window_id': stateGlobal.windowId, + 'peer_id': peerId, + 'display': i, + 'display_count': pi.displays.length, + }; + if (screenRect != null) { + args['screen_rect'] = { + 'l': screenRect.left, + 't': screenRect.top, + 'r': screenRect.right, + 'b': screenRect.bottom, + }; + } + DesktopMultiWindow.invokeMethod( + kMainWindowId, kWindowEventOpenMonitorSession, jsonEncode(args)); +} + +tryMoveToScreenAndSetFullscreen(Rect? screenRect) async { + if (screenRect == null) { + return; + } + final frame = + Rect.fromLTWH(screenRect.left + 30, screenRect.top + 30, 600, 400); + await WindowController.fromWindowId(stateGlobal.windowId).setFrame(frame); + // An duration is needed to avoid the window being restored after fullscreen. + Future.delayed(Duration(milliseconds: 300), () async { + stateGlobal.setFullscreen(true); + }); +} diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index d92f42a10..8a562f5a1 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -29,6 +29,7 @@ const String kAppTypeDesktopPortForward = "port forward"; const String kWindowMainWindowOnTop = "main_window_on_top"; const String kWindowGetWindowInfo = "get_window_info"; +const String kWindowGetScreenList = "get_screen_list"; const String kWindowDisableGrabKeyboard = "disable_grab_keyboard"; const String kWindowActionRebuild = "rebuild"; const String kWindowEventHide = "hide"; @@ -65,6 +66,7 @@ const String kPointerEventKindTouch = "touch"; const String kPointerEventKindMouse = "mouse"; const String kKeyShowDisplaysAsIndividualWindows = 'displays_as_individual_windows'; +const String kKeyUseAllMyMonitorsWhenConnecting = 'use_all_my_monitors_when_connecting'; const String kKeyShowMonitorsToolbar = 'show_monitors_toolbar'; // the executable name of the portable version diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 8ea872c6c..a06c81ad2 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -329,8 +329,7 @@ class _DesktopHomePageState extends State "Click to download", () async { final Uri url = Uri.parse('https://rustdesk.com/download'); await launchUrl(url); - }, - closeButton: true); + }, closeButton: true); } if (systemError.isNotEmpty) { return buildInstallCard("", systemError, "", () {}); @@ -397,7 +396,6 @@ class _DesktopHomePageState extends State Widget buildInstallCard(String title, String content, String btnText, GestureTapCallback onPressed, {String? help, String? link, bool? closeButton}) { - void closeCard() { setState(() { isCardClosed = true; @@ -555,6 +553,22 @@ class _DesktopHomePageState extends State Get.put(svcStopped, tag: 'stop-service'); rustDeskWinManager.registerActiveWindowListener(onActiveWindowChanged); + screenToMap(window_size.Screen screen) => { + 'frame': { + 'l': screen.frame.left, + 't': screen.frame.top, + 'r': screen.frame.right, + 'b': screen.frame.bottom, + }, + 'visibleFrame': { + 'l': screen.visibleFrame.left, + 't': screen.visibleFrame.top, + 'r': screen.visibleFrame.right, + 'b': screen.visibleFrame.bottom, + }, + 'scaleFactor': screen.scaleFactor, + }; + rustDeskWinManager.setMethodHandler((call, fromWindowId) async { debugPrint( "[Main] call ${call.method} with args ${call.arguments} from window $fromWindowId"); @@ -563,24 +577,13 @@ class _DesktopHomePageState extends State } else if (call.method == kWindowGetWindowInfo) { final screen = (await window_size.getWindowInfo()).screen; if (screen == null) { - return ""; + return ''; } else { - return jsonEncode({ - 'frame': { - 'l': screen.frame.left, - 't': screen.frame.top, - 'r': screen.frame.right, - 'b': screen.frame.bottom, - }, - 'visibleFrame': { - 'l': screen.visibleFrame.left, - 't': screen.visibleFrame.top, - 'r': screen.visibleFrame.right, - 'b': screen.visibleFrame.bottom, - }, - 'scaleFactor': screen.scaleFactor, - }); + return jsonEncode(screenToMap(screen)); } + } else if (call.method == kWindowGetScreenList) { + return jsonEncode( + (await window_size.getScreenList()).map(screenToMap).toList()); } else if (call.method == kWindowActionRebuild) { reloadCurrentWindow(); } else if (call.method == kWindowEventShow) { @@ -613,8 +616,9 @@ class _DesktopHomePageState extends State final peerId = args['peer_id'] as String; final display = args['display'] as int; final displayCount = args['display_count'] as int; + final screenRect = args['screen_rect']; await rustDeskWinManager.openMonitorSession( - windowId, peerId, display, displayCount); + windowId, peerId, display, displayCount, screenRect); } }); _uniLinksSubscription = listenUniLinks(); diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index f74535047..517114aea 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1324,6 +1324,8 @@ class _DisplayState extends State<_Display> { if (useTextureRender) { children.add(otherRow('Show displays as individual windows', kKeyShowDisplaysAsIndividualWindows)); + children.add(otherRow('Use all my displays when connecting', + kKeyUseAllMyMonitorsWhenConnecting)); } return _Card(title: 'Other Default Options', children: children); } diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index 0cc23b39a..d2f117db5 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -48,6 +48,7 @@ class _ConnectionTabPageState extends State { late ToolbarState _toolbarState; String? peerId; + bool isScreenRectSet = false; var connectionMap = RxList.empty(growable: true); @@ -59,6 +60,9 @@ class _ConnectionTabPageState extends State { final tabWindowId = params['tab_window_id']; final display = params['display']; final displays = params['displays']; + final screenRect = parseScreenRect(params); + isScreenRectSet = screenRect != null; + tryMoveToScreenAndSetFullscreen(screenRect); if (peerId != null) { ConnectionTypeState.init(peerId!); tabController.onSelected = (id) { @@ -95,6 +99,18 @@ class _ConnectionTabPageState extends State { } } + parseScreenRect(Map params) { + Rect? screenRect; + if (params['screen_rect'] != null) { + double l = params['screen_rect']['l']; + double t = params['screen_rect']['t']; + double r = params['screen_rect']['r']; + double b = params['screen_rect']['b']; + screenRect = Rect.fromLTRB(l, t, r, b); + } + return screenRect; + } + @override void initState() { super.initState(); @@ -115,7 +131,9 @@ class _ConnectionTabPageState extends State { final tabWindowId = args['tab_window_id']; final display = args['display']; final displays = args['displays']; + final screenRect = parseScreenRect(args); windowOnTop(windowId()); + tryMoveToScreenAndSetFullscreen(screenRect); if (tabController.length == 0) { if (Platform.isMacOS && stateGlobal.closeOnFullscreen) { stateGlobal.setFullscreen(true); @@ -196,15 +214,17 @@ class _ConnectionTabPageState extends State { _update_remote_count(); return returnValue; }); - Future.delayed(Duration.zero, () { - restoreWindowPosition( - WindowType.RemoteDesktop, - windowId: windowId(), - peerId: tabController.state.value.tabs.isEmpty - ? null - : tabController.state.value.tabs[0].key, - ); - }); + if (!isScreenRectSet) { + Future.delayed(Duration.zero, () { + restoreWindowPosition( + WindowType.RemoteDesktop, + windowId: windowId(), + peerId: tabController.state.value.tabs.isEmpty + ? null + : tabController.state.value.tabs[0].key, + ); + }); + } } @override @@ -451,6 +471,7 @@ class _ConnectionTabPageState extends State { c++; } } + loopCloseWindow(); } ConnectionTypeState.delete(id); diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 92038f68b..4065ebfb2 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -1,12 +1,10 @@ import 'dart:convert'; import 'dart:async'; import 'dart:io'; -import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/common/widgets/toolbar.dart'; -import 'package:flutter_hbb/main.dart'; import 'package:flutter_hbb/models/chat_model.dart'; import 'package:flutter_hbb/models/state_model.dart'; import 'package:flutter_hbb/models/desktop_render_texture.dart'; @@ -744,42 +742,14 @@ class _MonitorMenu extends StatelessWidget { ); } - // Open new tab or window to show this monitor. - // For now just open new window. - openMonitorInNewTabOrWindow(int i, PeerInfo pi) { - if (kWindowId == null) { - // unreachable - debugPrint('openMonitorInNewTabOrWindow, unreachable! kWindowId is null'); - return; - } - DesktopMultiWindow.invokeMethod( - kMainWindowId, - kWindowEventOpenMonitorSession, - jsonEncode({ - 'window_id': kWindowId!, - 'peer_id': ffi.id, - 'display': i, - 'display_count': pi.displays.length, - })); - } - - openMonitorInTheSameTab(int i, PeerInfo pi) { - final displays = i == kAllDisplayValue - ? List.generate(pi.displays.length, (index) => index) - : [i]; - bind.sessionSwitchDisplay( - sessionId: ffi.sessionId, value: Int32List.fromList(displays)); - ffi.ffiModel.switchToNewDisplay(i, ffi.sessionId, id); - } - onPressed(int i, PeerInfo pi) { _menuDismissCallback(ffi); RxInt display = CurrentDisplayState.find(id); if (display.value != i) { if (isChooseDisplayToOpenInNewWindow(pi, ffi.sessionId)) { - openMonitorInNewTabOrWindow(i, pi); + openMonitorInNewTabOrWindow(i, ffi.id, pi); } else { - openMonitorInTheSameTab(i, pi); + openMonitorInTheSameTab(i, ffi, pi); } } } diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index ef44a3bcc..59cf97345 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -198,8 +198,11 @@ void runMultiWindow( } switch (appType) { case kAppTypeDesktopRemote: - await restoreWindowPosition(WindowType.RemoteDesktop, - windowId: kWindowId!, peerId: argument['id'] as String?); + // If screen rect is set, the window will be moved to the target screen and then set fullscreen. + if (argument['screen_rect'] == null) { + await restoreWindowPosition(WindowType.RemoteDesktop, + windowId: kWindowId!, peerId: argument['id'] as String?); + } break; case kAppTypeDesktopFileTransfer: await restoreWindowPosition(WindowType.FileTransfer, diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 56e18d309..127410761 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -227,7 +227,7 @@ class FfiModel with ChangeNotifier { }, sessionId, peerId); updatePrivacyMode(data.updatePrivacyMode, sessionId, peerId); setConnectionType(peerId, data.secure, data.direct); - await handlePeerInfo(data.peerInfo, peerId); + await handlePeerInfo(data.peerInfo, peerId, true); for (final element in data.cursorDataList) { updateLastCursorId(element); await handleCursorData(element); @@ -245,7 +245,7 @@ class FfiModel with ChangeNotifier { if (name == 'msgbox') { handleMsgBox(evt, sessionId, peerId); } else if (name == 'peer_info') { - handlePeerInfo(evt, peerId); + handlePeerInfo(evt, peerId, false); } else if (name == 'sync_peer_info') { handleSyncPeerInfo(evt, sessionId, peerId); } else if (name == 'connection_ready') { @@ -623,7 +623,7 @@ class FfiModel with ChangeNotifier { } /// Handle the peer info event based on [evt]. - handlePeerInfo(Map evt, String peerId) async { + handlePeerInfo(Map evt, String peerId, bool isCache) async { cachedPeerData.peerInfo = evt; // recent peer updated by handle_peer_info(ui_session_interface.rs) --> handle_peer_info(client.rs) --> save_config(client.rs) @@ -703,6 +703,51 @@ class FfiModel with ChangeNotifier { stateGlobal.resetLastResolutionGroupValues(peerId); notifyListeners(); + + if (!isCache) { + tryUseAllMyDisplaysWhenConnecting(peerId); + } + } + + tryUseAllMyDisplaysWhenConnecting(String peerId) async { + if (bind.mainGetUserDefaultOption( + key: kKeyUseAllMyMonitorsWhenConnecting) != + 'Y') { + return; + } + + if (!_pi.isSupportMultiDisplay || _pi.displays.length <= 1) { + return; + } + + final screenRectList = await getScreenRectList(); + if (screenRectList.length <= 1) { + return; + } + + // to-do: peer currentDisplay is the primary display, but the primary display may not be the first display. + // local primary display also may not be the first display. + // + // 0 is assumed to be the primary display here, for now. + + // move to the first display and set fullscreen + bind.sessionSwitchDisplay( + sessionId: sessionId, value: Int32List.fromList([0])); + _pi.currentDisplay = 0; + try { + CurrentDisplayState.find(peerId).value = _pi.currentDisplay; + } catch (e) { + // + } + await tryMoveToScreenAndSetFullscreen(screenRectList[0]); + + final length = _pi.displays.length < screenRectList.length + ? _pi.displays.length + : screenRectList.length; + for (var i = 1; i < length; i++) { + openMonitorInNewTabOrWindow(i, peerId, _pi, + screenRect: screenRectList[i]); + } } tryShowAndroidActionsOverlay({int delayMSecs = 10}) { diff --git a/flutter/lib/utils/multi_window_manager.dart b/flutter/lib/utils/multi_window_manager.dart index f36370e40..3c3e03627 100644 --- a/flutter/lib/utils/multi_window_manager.dart +++ b/flutter/lib/utils/multi_window_manager.dart @@ -64,13 +64,14 @@ class RustDeskMultiWindowManager { peerId, _remoteDesktopWindows, jsonEncode(params), + false, ); } // This function must be called in the main window thread. // Because the _remoteDesktopWindows is managed in that thread. - openMonitorSession( - int windowId, String peerId, int display, int displayCount) async { + openMonitorSession(int windowId, String peerId, int display, int displayCount, + dynamic screenRect) async { if (_remoteDesktopWindows.length > 1) { for (final windowId in _remoteDesktopWindows) { if (await DesktopMultiWindow.invokeMethod( @@ -94,6 +95,7 @@ class RustDeskMultiWindowManager { 'tab_window_id': windowId, 'display': display, 'displays': displays, + 'screen_rect': screenRect, }; await _newSession( false, @@ -102,21 +104,34 @@ class RustDeskMultiWindowManager { peerId, _remoteDesktopWindows, jsonEncode(params), + screenRect != null, ); } Future newSessionWindow( - WindowType type, String remoteId, String msg, List windows) async { + WindowType type, + String remoteId, + String msg, + List windows, + bool withScreenRect, + ) async { final windowController = await DesktopMultiWindow.createWindow(msg); final windowId = windowController.windowId; - windowController - ..setFrame( - const Offset(0, 0) & Size(1280 + windowId * 20, 720 + windowId * 20)) - ..center() - ..setTitle(getWindowNameWithId( + if (!withScreenRect) { + windowController + ..setFrame(const Offset(0, 0) & + Size(1280 + windowId * 20, 720 + windowId * 20)) + ..center() + ..setTitle(getWindowNameWithId( + remoteId, + overrideType: type, + )); + } else { + windowController.setTitle(getWindowNameWithId( remoteId, overrideType: type, )); + } if (Platform.isMacOS) { Future.microtask(() => windowController.show()); } @@ -132,10 +147,12 @@ class RustDeskMultiWindowManager { String remoteId, List windows, String msg, + bool withScreenRect, ) async { if (openInTabs) { if (windows.isEmpty) { - final windowId = await newSessionWindow(type, remoteId, msg, windows); + final windowId = await newSessionWindow( + type, remoteId, msg, windows, withScreenRect); return MultiWindowCallResult(windowId, null); } else { return call(type, methodName, msg); @@ -153,7 +170,8 @@ class RustDeskMultiWindowManager { } } } - final windowId = await newSessionWindow(type, remoteId, msg, windows); + final windowId = + await newSessionWindow(type, remoteId, msg, windows, withScreenRect); return MultiWindowCallResult(windowId, null); } } @@ -195,7 +213,8 @@ class RustDeskMultiWindowManager { } } - return _newSession(openInTabs, type, methodName, remoteId, windows, msg); + return _newSession( + openInTabs, type, methodName, remoteId, windows, msg, false); } Future newRemoteDesktop( diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 02f3c719e..09f5a3f35 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -290,6 +290,12 @@ pub struct PeerConfig { skip_serializing_if = "String::is_empty" )] pub displays_as_individual_windows: String, + #[serde( + default = "PeerConfig::default_use_all_my_monitors_when_connecting", + deserialize_with = "PeerConfig::deserialize_use_all_my_monitors_when_connecting", + skip_serializing_if = "String::is_empty" + )] + pub use_all_my_monitors_when_connecting: String, #[serde( default, @@ -335,6 +341,8 @@ impl Default for PeerConfig { view_only: Default::default(), reverse_mouse_wheel: Self::default_reverse_mouse_wheel(), displays_as_individual_windows: Self::default_displays_as_individual_windows(), + use_all_my_monitors_when_connecting: Self::default_use_all_my_monitors_when_connecting( + ), custom_resolutions: Default::default(), options: Self::default_options(), ui_flutter: Default::default(), @@ -1156,6 +1164,11 @@ impl PeerConfig { deserialize_displays_as_individual_windows, UserDefaultConfig::read().get("displays_as_individual_windows") ); + serde_field_string!( + default_use_all_my_monitors_when_connecting, + deserialize_use_all_my_monitors_when_connecting, + UserDefaultConfig::read().get("use_all_my_monitors_when_connecting") + ); fn default_custom_image_quality() -> Vec { let f: f64 = UserDefaultConfig::read() diff --git a/src/client.rs b/src/client.rs index 445aaf225..c2cdfc1e9 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1207,7 +1207,7 @@ impl LoginConfigHandler { self.save_config(config); } - /// Save reverse mouse wheel ("", "Y") to the current config. + /// Save "displays_as_individual_windows" ("", "Y") to the current config. /// /// # Arguments /// @@ -1218,6 +1218,17 @@ impl LoginConfigHandler { self.save_config(config); } + /// Save "use_all_my_monitors_when_connecting" ("", "Y") to the current config. + /// + /// # Arguments + /// + /// * `value` - The "use_all_my_monitors_when_connecting" value ("", "Y"). + pub fn save_use_all_my_monitors_when_connecting(&mut self, value: String) { + let mut config = self.load_config(); + config.use_all_my_monitors_when_connecting = value; + self.save_config(config); + } + /// Save scroll style to the current config. /// /// # Arguments diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index ea6ae1180..19b83590c 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -339,7 +339,9 @@ pub fn session_set_reverse_mouse_wheel(session_id: SessionID, value: String) { } } -pub fn session_get_displays_as_individual_windows(session_id: SessionID) -> SyncReturn> { +pub fn session_get_displays_as_individual_windows( + session_id: SessionID, +) -> SyncReturn> { if let Some(session) = sessions::get_session_by_session_id(&session_id) { SyncReturn(Some(session.get_displays_as_individual_windows())) } else { @@ -353,6 +355,22 @@ pub fn session_set_displays_as_individual_windows(session_id: SessionID, value: } } +pub fn session_get_use_all_my_monitors_when_connecting( + session_id: SessionID, +) -> SyncReturn> { + if let Some(session) = sessions::get_session_by_session_id(&session_id) { + SyncReturn(Some(session.get_use_all_my_monitors_when_connecting())) + } else { + SyncReturn(None) + } +} + +pub fn session_set_use_all_my_monitors_when_connecting(session_id: SessionID, value: String) { + if let Some(session) = sessions::get_session_by_session_id(&session_id) { + session.save_use_all_my_monitors_when_connecting(value); + } +} + pub fn session_get_custom_image_quality(session_id: SessionID) -> Option> { if let Some(session) = sessions::get_session_by_session_id(&session_id) { Some(session.get_custom_image_quality()) @@ -1069,6 +1087,29 @@ pub fn main_get_main_display() -> SyncReturn { SyncReturn(display_info) } +pub fn main_get_displays() -> SyncReturn { + #[cfg(target_os = "ios")] + let display_info = "".to_owned(); + #[cfg(not(target_os = "ios"))] + let mut display_info = "".to_owned(); + #[cfg(not(target_os = "ios"))] + if let Ok(displays) = crate::display_service::try_get_displays() { + let displays = displays + .iter() + .map(|d| { + HashMap::from([ + ("x", d.origin().0), + ("y", d.origin().1), + ("w", d.width() as i32), + ("h", d.height() as i32), + ]) + }) + .collect::>(); + display_info = serde_json::to_string(&displays).unwrap_or_default(); + } + SyncReturn(display_info) +} + pub fn session_add_port_forward( session_id: SessionID, local_port: i32, diff --git a/src/lang/ar.rs b/src/lang/ar.rs index e30621c21..a5568fef9 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index e70c2c044..02c0b3ca6 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index ba2796157..c6db2a09c 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "切换到主显示器,因为提权后,不支持多显示器画面。"), ("Open in new window", "在新的窗口中打开"), ("Show displays as individual windows", "在单个窗口中打开显示器"), + ("Use all my displays when connecting", "建立连接时使用我的所有显示器"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 8907e78e0..c31cfa8bf 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 9d76b8e2e..a4704d069 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index 472b494e7..309082e11 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index ccc674749..b5dbc92f3 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 1b1b83afa..870afce91 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index ff90b0430..19993de22 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 2195d4fdd..cc0442ae3 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 24ac09d05..6f6c0fb18 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 892381374..8e170cb61 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Pindah ke tampilan utama, pada mode elevasi, pengggunaan lebih dari satu layar tidak diizinkan"), ("Open in new window", "Buka di jendela baru"), ("Show displays as individual windows", "Tampilkan dengan jendela terpisah"), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index cb7ed922c..fe07c0fb8 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Passo allo schermo principale perché in modalità elevata non sono supportati più schermi."), ("Open in new window", "Apri in una nuova finestra"), ("Show displays as individual windows", "Visualizza schermi come finestre individuali"), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index eeed3e147..95c8333d3 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index dcf28718a..2f26b530a 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 43c36e32c..6b5260284 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 02d4714c2..2b325d5e0 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index 1af747f23..bd9e91e94 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Pārslēdzieties uz primāro displeju, jo paaugstinātajā režīmā netiek atbalstīti vairāki displeji."), ("Open in new window", "Atvērt jaunā logā"), ("Show displays as individual windows", "Rādīt displejus kā atsevišķus logus"), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 71d1c1107..190aa7713 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 88dc5cda5..1f8bf2e79 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Przełącz się na ekran główny, ponieważ wyświetlanie kilku ekranów nie jest obsługiwane przy podniesionych uprawnieniach."), ("Open in new window", "Otwórz w nowym oknie"), ("Show displays as individual windows", "Pokaż ekrany w osobnych oknach"), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 85863d2ae..31d9a4214 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index be4cdfd8e..7a2e8288e 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 311a13bec..faa5efb56 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 23751b734..68003f11d 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 8f84b181a..10e8d1625 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index 3d26b5635..bbccd4bde 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 03f4776b7..37ed82a3a 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index ce2dab684..ff6edc549 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 04d3d53ef..811cac31a 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 75afe0324..f66130741 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index e51cff3db..b1e79d93e 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index c70cf8f35..1da5f2e43 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 94e0bc423..7ffc00d8b 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 895e7491a..4d377a6e9 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), + ("Use all my displays when connecting", ""), ].iter().cloned().collect(); } diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 0eea85173..37e933927 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -240,6 +240,10 @@ impl Session { self.lc.read().unwrap().displays_as_individual_windows.clone() } + pub fn get_use_all_my_monitors_when_connecting(&self) -> String { + self.lc.read().unwrap().use_all_my_monitors_when_connecting.clone() + } + pub fn save_reverse_mouse_wheel(&self, value: String) { self.lc.write().unwrap().save_reverse_mouse_wheel(value); } @@ -248,6 +252,10 @@ impl Session { self.lc.write().unwrap().save_displays_as_individual_windows(value); } + pub fn save_use_all_my_monitors_when_connecting(&self, value: String) { + self.lc.write().unwrap().save_use_all_my_monitors_when_connecting(value); + } + pub fn save_view_style(&self, value: String) { self.lc.write().unwrap().save_view_style(value); } From 19945df0b3da4b8ac3cc7565239c1a40820979cf Mon Sep 17 00:00:00 2001 From: dignow Date: Tue, 17 Oct 2023 07:43:12 +0800 Subject: [PATCH 015/114] open_multi_windows, check before move and set fullscreen Signed-off-by: dignow --- flutter/lib/common.dart | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index a67aa27fe..c7c11da96 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1675,7 +1675,6 @@ Future _adjustRestoreMainWindowOffset( /// Note that windowId must be provided if it's subwindow Future restoreWindowPosition(WindowType type, {int? windowId, String? peerId}) async { - debugPrintStack(label: "restoreWindowPosition"); if (bind .mainGetEnv(key: "DISABLE_RUSTDESK_RESTORE_WINDOW_POSITION") .isNotEmpty) { @@ -2707,9 +2706,18 @@ tryMoveToScreenAndSetFullscreen(Rect? screenRect) async { if (screenRect == null) { return; } + final wc = WindowController.fromWindowId(stateGlobal.windowId); + final curFrame = await wc.getFrame(); final frame = Rect.fromLTWH(screenRect.left + 30, screenRect.top + 30, 600, 400); - await WindowController.fromWindowId(stateGlobal.windowId).setFrame(frame); + if (stateGlobal.fullscreen && + curFrame.left <= frame.left && + curFrame.top <= frame.top && + curFrame.width >= frame.width && + curFrame.height >= frame.height) { + return; + } + await wc.setFrame(frame); // An duration is needed to avoid the window being restored after fullscreen. Future.delayed(Duration(milliseconds: 300), () async { stateGlobal.setFullscreen(true); From af906fac031eb0e387cbdc00b837cb474effa38f Mon Sep 17 00:00:00 2001 From: dignow Date: Tue, 17 Oct 2023 09:36:08 +0800 Subject: [PATCH 016/114] debug, open multi windows Signed-off-by: dignow --- flutter/lib/common.dart | 12 +++++++ .../lib/desktop/pages/desktop_home_page.dart | 2 +- .../lib/desktop/pages/remote_tab_page.dart | 16 ++------- flutter/lib/models/state_model.dart | 10 +++--- flutter/lib/utils/multi_window_manager.dart | 35 +++++++++++-------- 5 files changed, 40 insertions(+), 35 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index c7c11da96..7fd80d863 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -2723,3 +2723,15 @@ tryMoveToScreenAndSetFullscreen(Rect? screenRect) async { stateGlobal.setFullscreen(true); }); } + +parseParamScreenRect(Map params) { + Rect? screenRect; + if (params['screen_rect'] != null) { + double l = params['screen_rect']['l']; + double t = params['screen_rect']['t']; + double r = params['screen_rect']['r']; + double b = params['screen_rect']['b']; + screenRect = Rect.fromLTRB(l, t, r, b); + } + return screenRect; +} diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index a06c81ad2..8633af1d3 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -616,7 +616,7 @@ class _DesktopHomePageState extends State final peerId = args['peer_id'] as String; final display = args['display'] as int; final displayCount = args['display_count'] as int; - final screenRect = args['screen_rect']; + final screenRect = parseParamScreenRect(args); await rustDeskWinManager.openMonitorSession( windowId, peerId, display, displayCount, screenRect); } diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index d2f117db5..6d28d967f 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -60,7 +60,7 @@ class _ConnectionTabPageState extends State { final tabWindowId = params['tab_window_id']; final display = params['display']; final displays = params['displays']; - final screenRect = parseScreenRect(params); + final screenRect = parseParamScreenRect(params); isScreenRectSet = screenRect != null; tryMoveToScreenAndSetFullscreen(screenRect); if (peerId != null) { @@ -99,18 +99,6 @@ class _ConnectionTabPageState extends State { } } - parseScreenRect(Map params) { - Rect? screenRect; - if (params['screen_rect'] != null) { - double l = params['screen_rect']['l']; - double t = params['screen_rect']['t']; - double r = params['screen_rect']['r']; - double b = params['screen_rect']['b']; - screenRect = Rect.fromLTRB(l, t, r, b); - } - return screenRect; - } - @override void initState() { super.initState(); @@ -131,7 +119,7 @@ class _ConnectionTabPageState extends State { final tabWindowId = args['tab_window_id']; final display = args['display']; final displays = args['displays']; - final screenRect = parseScreenRect(args); + final screenRect = parseParamScreenRect(args); windowOnTop(windowId()); tryMoveToScreenAndSetFullscreen(screenRect); if (tabController.length == 0) { diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index 2403a794c..e6744ff77 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -78,17 +78,15 @@ class StateGlobal { "fullscreen: $fullscreen, resizeEdgeSize: ${_resizeEdgeSize.value}"); _windowBorderWidth.value = fullscreen ? 0 : kWindowBorderWidth; if (procWnd) { - WindowController.fromWindowId(windowId) - .setFullscreen(_fullscreen) - .then((_) { + final wc = WindowController.fromWindowId(windowId); + wc.setFullscreen(_fullscreen).then((_) { // https://github.com/leanflutter/window_manager/issues/131#issuecomment-1111587982 if (Platform.isWindows && !v) { Future.delayed(Duration.zero, () async { - final frame = - await WindowController.fromWindowId(windowId).getFrame(); + final frame = await wc.getFrame(); final newRect = Rect.fromLTWH( frame.left, frame.top, frame.width + 1, frame.height + 1); - await WindowController.fromWindowId(windowId).setFrame(newRect); + await wc.setFrame(newRect); }); } }); diff --git a/flutter/lib/utils/multi_window_manager.dart b/flutter/lib/utils/multi_window_manager.dart index 3c3e03627..b8edeb3e4 100644 --- a/flutter/lib/utils/multi_window_manager.dart +++ b/flutter/lib/utils/multi_window_manager.dart @@ -64,14 +64,13 @@ class RustDeskMultiWindowManager { peerId, _remoteDesktopWindows, jsonEncode(params), - false, ); } // This function must be called in the main window thread. // Because the _remoteDesktopWindows is managed in that thread. openMonitorSession(int windowId, String peerId, int display, int displayCount, - dynamic screenRect) async { + Rect? screenRect) async { if (_remoteDesktopWindows.length > 1) { for (final windowId in _remoteDesktopWindows) { if (await DesktopMultiWindow.invokeMethod( @@ -95,8 +94,15 @@ class RustDeskMultiWindowManager { 'tab_window_id': windowId, 'display': display, 'displays': displays, - 'screen_rect': screenRect, }; + if (screenRect != null) { + params['screen_rect'] = { + 'l': screenRect.left, + 't': screenRect.top, + 'r': screenRect.right, + 'b': screenRect.bottom, + }; + } await _newSession( false, WindowType.RemoteDesktop, @@ -104,7 +110,7 @@ class RustDeskMultiWindowManager { peerId, _remoteDesktopWindows, jsonEncode(params), - screenRect != null, + screenRect: screenRect, ); } @@ -146,13 +152,13 @@ class RustDeskMultiWindowManager { String methodName, String remoteId, List windows, - String msg, - bool withScreenRect, - ) async { + String msg, { + Rect? screenRect, + }) async { if (openInTabs) { if (windows.isEmpty) { final windowId = await newSessionWindow( - type, remoteId, msg, windows, withScreenRect); + type, remoteId, msg, windows, screenRect != null); return MultiWindowCallResult(windowId, null); } else { return call(type, methodName, msg); @@ -161,8 +167,10 @@ class RustDeskMultiWindowManager { if (_inactiveWindows.isNotEmpty) { for (final windowId in windows) { if (_inactiveWindows.contains(windowId)) { - await restoreWindowPosition(type, - windowId: windowId, peerId: remoteId); + if (screenRect == null) { + await restoreWindowPosition(type, + windowId: windowId, peerId: remoteId); + } await DesktopMultiWindow.invokeMethod(windowId, methodName, msg); WindowController.fromWindowId(windowId).show(); registerActiveWindow(windowId); @@ -170,8 +178,8 @@ class RustDeskMultiWindowManager { } } } - final windowId = - await newSessionWindow(type, remoteId, msg, windows, withScreenRect); + final windowId = await newSessionWindow( + type, remoteId, msg, windows, screenRect != null); return MultiWindowCallResult(windowId, null); } } @@ -213,8 +221,7 @@ class RustDeskMultiWindowManager { } } - return _newSession( - openInTabs, type, methodName, remoteId, windows, msg, false); + return _newSession(openInTabs, type, methodName, remoteId, windows, msg); } Future newRemoteDesktop( From e997b148e11f70fab52bd089b851cd5d65253cc3 Mon Sep 17 00:00:00 2001 From: dignow Date: Tue, 17 Oct 2023 13:16:42 +0800 Subject: [PATCH 017/114] Change option text Signed-off-by: dignow --- flutter/lib/desktop/pages/desktop_setting_page.dart | 2 +- src/lang/ar.rs | 2 +- src/lang/ca.rs | 2 +- src/lang/cn.rs | 2 +- src/lang/cs.rs | 2 +- src/lang/da.rs | 2 +- src/lang/el.rs | 2 +- src/lang/eo.rs | 2 +- src/lang/es.rs | 2 +- src/lang/fa.rs | 2 +- src/lang/fr.rs | 2 +- src/lang/hu.rs | 2 +- src/lang/id.rs | 2 +- src/lang/it.rs | 2 +- src/lang/ja.rs | 2 +- src/lang/ko.rs | 2 +- src/lang/kz.rs | 2 +- src/lang/lt.rs | 2 +- src/lang/lv.rs | 2 +- src/lang/nl.rs | 2 +- src/lang/pl.rs | 2 +- src/lang/pt_PT.rs | 2 +- src/lang/ptbr.rs | 2 +- src/lang/ro.rs | 2 +- src/lang/sk.rs | 2 +- src/lang/sl.rs | 2 +- src/lang/sq.rs | 2 +- src/lang/sr.rs | 2 +- src/lang/sv.rs | 2 +- src/lang/template.rs | 2 +- src/lang/th.rs | 2 +- src/lang/tr.rs | 2 +- src/lang/tw.rs | 2 +- src/lang/ua.rs | 2 +- src/lang/vn.rs | 2 +- 35 files changed, 35 insertions(+), 35 deletions(-) diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 517114aea..42c75a70a 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1324,7 +1324,7 @@ class _DisplayState extends State<_Display> { if (useTextureRender) { children.add(otherRow('Show displays as individual windows', kKeyShowDisplaysAsIndividualWindows)); - children.add(otherRow('Use all my displays when connecting', + children.add(otherRow('Use all my displays for the remote session', kKeyUseAllMyMonitorsWhenConnecting)); } return _Card(title: 'Other Default Options', children: children); diff --git a/src/lang/ar.rs b/src/lang/ar.rs index a5568fef9..4b80047d5 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 02c0b3ca6..bd62b21c7 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index c6db2a09c..2893eb9a5 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "切换到主显示器,因为提权后,不支持多显示器画面。"), ("Open in new window", "在新的窗口中打开"), ("Show displays as individual windows", "在单个窗口中打开显示器"), - ("Use all my displays when connecting", "建立连接时使用我的所有显示器"), + ("Use all my displays for the remote session", "将我的所有显示器用于远程会话"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index c31cfa8bf..3ba2c4a23 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index a4704d069..2f1076fd1 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index 309082e11..940889e16 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index b5dbc92f3..8685fa567 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 870afce91..30bee3ace 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 19993de22..845cb1868 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index cc0442ae3..9f1954f7d 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 6f6c0fb18..882663b7e 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 8e170cb61..7122f7845 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Pindah ke tampilan utama, pada mode elevasi, pengggunaan lebih dari satu layar tidak diizinkan"), ("Open in new window", "Buka di jendela baru"), ("Show displays as individual windows", "Tampilkan dengan jendela terpisah"), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index fe07c0fb8..129d10eb6 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -565,6 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Passo allo schermo principale perché in modalità elevata non sono supportati più schermi."), ("Open in new window", "Apri in una nuova finestra"), ("Show displays as individual windows", "Visualizza schermi come finestre individuali"), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 95c8333d3..059b355db 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 2f26b530a..0a7affb3b 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 6b5260284..73fc04469 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 2b325d5e0..39747e0d4 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index bd9e91e94..09eef383b 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Pārslēdzieties uz primāro displeju, jo paaugstinātajā režīmā netiek atbalstīti vairāki displeji."), ("Open in new window", "Atvērt jaunā logā"), ("Show displays as individual windows", "Rādīt displejus kā atsevišķus logus"), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 190aa7713..6eee21410 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 1f8bf2e79..91c508aaa 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Przełącz się na ekran główny, ponieważ wyświetlanie kilku ekranów nie jest obsługiwane przy podniesionych uprawnieniach."), ("Open in new window", "Otwórz w nowym oknie"), ("Show displays as individual windows", "Pokaż ekrany w osobnych oknach"), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 31d9a4214..9c3c01660 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 7a2e8288e..9b052947f 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index faa5efb56..61d44813d 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 68003f11d..b124aed71 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 10e8d1625..e1bf2ab8e 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index bbccd4bde..1d9b218a6 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 37ed82a3a..754192fc3 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index ff6edc549..007e180bb 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 811cac31a..f14c3e206 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index f66130741..bb13d82b6 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index b1e79d93e..394b9bca9 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 1da5f2e43..cdc900ae2 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 7ffc00d8b..7bdea72d6 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 4d377a6e9..0e0cf6a05 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", ""), ("Open in new window", ""), ("Show displays as individual windows", ""), - ("Use all my displays when connecting", ""), + ("Use all my displays for the remote session", ""), ].iter().cloned().collect(); } From f1d3a553d172ff6e0a213823ab33ef8047d10263 Mon Sep 17 00:00:00 2001 From: dignow Date: Tue, 17 Oct 2023 13:57:06 +0800 Subject: [PATCH 018/114] open multi windows, add remote toolbar option Signed-off-by: dignow --- flutter/lib/common/widgets/toolbar.dart | 15 +++++++++++++++ flutter/lib/consts.dart | 2 +- .../lib/desktop/pages/desktop_setting_page.dart | 2 +- flutter/lib/models/model.dart | 8 ++++---- libs/hbb_common/src/config.rs | 14 +++++++------- src/client.rs | 8 ++++---- src/flutter_ffi.rs | 8 ++++---- src/ui_session_interface.rs | 8 ++++---- 8 files changed, 40 insertions(+), 25 deletions(-) diff --git a/flutter/lib/common/widgets/toolbar.dart b/flutter/lib/common/widgets/toolbar.dart index ebaff8954..757a03fec 100644 --- a/flutter/lib/common/widgets/toolbar.dart +++ b/flutter/lib/common/widgets/toolbar.dart @@ -535,5 +535,20 @@ Future> toolbarDisplayToggle( child: Text(translate('Show displays as individual windows')))); } + final screenList = await getScreenRectList(); + if (useTextureRender && pi.isSupportMultiDisplay && screenList.length > 1) { + final value = bind.sessionGetUseAllMyDisplaysForTheRemoteSession( + sessionId: ffi.sessionId) == + 'Y'; + v.add(TToggleMenu( + value: value, + onChanged: (value) { + if (value == null) return; + bind.sessionSetUseAllMyDisplaysForTheRemoteSession( + sessionId: sessionId, value: value ? 'Y' : ''); + }, + child: Text(translate('Use all my displays for the remote session')))); + } + return v; } diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 8a562f5a1..9f0a5b56f 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -66,7 +66,7 @@ const String kPointerEventKindTouch = "touch"; const String kPointerEventKindMouse = "mouse"; const String kKeyShowDisplaysAsIndividualWindows = 'displays_as_individual_windows'; -const String kKeyUseAllMyMonitorsWhenConnecting = 'use_all_my_monitors_when_connecting'; +const String kKeyUseAllMyDisplaysForTheRemoteSession = 'use_all_my_displays_for_the_remote_session'; const String kKeyShowMonitorsToolbar = 'show_monitors_toolbar'; // the executable name of the portable version diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 42c75a70a..416cbaa5e 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1325,7 +1325,7 @@ class _DisplayState extends State<_Display> { children.add(otherRow('Show displays as individual windows', kKeyShowDisplaysAsIndividualWindows)); children.add(otherRow('Use all my displays for the remote session', - kKeyUseAllMyMonitorsWhenConnecting)); + kKeyUseAllMyDisplaysForTheRemoteSession)); } return _Card(title: 'Other Default Options', children: children); } diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 127410761..fb2b96d62 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -705,13 +705,13 @@ class FfiModel with ChangeNotifier { notifyListeners(); if (!isCache) { - tryUseAllMyDisplaysWhenConnecting(peerId); + tryUseAllMyDisplaysForTheRemoteSession(peerId); } } - tryUseAllMyDisplaysWhenConnecting(String peerId) async { - if (bind.mainGetUserDefaultOption( - key: kKeyUseAllMyMonitorsWhenConnecting) != + tryUseAllMyDisplaysForTheRemoteSession(String peerId) async { + if (bind.sessionGetUseAllMyDisplaysForTheRemoteSession( + sessionId: sessionId) != 'Y') { return; } diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 09f5a3f35..82867ad73 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -291,11 +291,11 @@ pub struct PeerConfig { )] pub displays_as_individual_windows: String, #[serde( - default = "PeerConfig::default_use_all_my_monitors_when_connecting", - deserialize_with = "PeerConfig::deserialize_use_all_my_monitors_when_connecting", + default = "PeerConfig::default_use_all_my_displays_for_the_remote_session", + deserialize_with = "PeerConfig::deserialize_use_all_my_displays_for_the_remote_session", skip_serializing_if = "String::is_empty" )] - pub use_all_my_monitors_when_connecting: String, + pub use_all_my_displays_for_the_remote_session: String, #[serde( default, @@ -341,7 +341,7 @@ impl Default for PeerConfig { view_only: Default::default(), reverse_mouse_wheel: Self::default_reverse_mouse_wheel(), displays_as_individual_windows: Self::default_displays_as_individual_windows(), - use_all_my_monitors_when_connecting: Self::default_use_all_my_monitors_when_connecting( + use_all_my_displays_for_the_remote_session: Self::default_use_all_my_displays_for_the_remote_session( ), custom_resolutions: Default::default(), options: Self::default_options(), @@ -1165,9 +1165,9 @@ impl PeerConfig { UserDefaultConfig::read().get("displays_as_individual_windows") ); serde_field_string!( - default_use_all_my_monitors_when_connecting, - deserialize_use_all_my_monitors_when_connecting, - UserDefaultConfig::read().get("use_all_my_monitors_when_connecting") + default_use_all_my_displays_for_the_remote_session, + deserialize_use_all_my_displays_for_the_remote_session, + UserDefaultConfig::read().get("use_all_my_displays_for_the_remote_session") ); fn default_custom_image_quality() -> Vec { diff --git a/src/client.rs b/src/client.rs index c2cdfc1e9..da4559c99 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1218,14 +1218,14 @@ impl LoginConfigHandler { self.save_config(config); } - /// Save "use_all_my_monitors_when_connecting" ("", "Y") to the current config. + /// Save "use_all_my_displays_for_the_remote_session" ("", "Y") to the current config. /// /// # Arguments /// - /// * `value` - The "use_all_my_monitors_when_connecting" value ("", "Y"). - pub fn save_use_all_my_monitors_when_connecting(&mut self, value: String) { + /// * `value` - The "use_all_my_displays_for_the_remote_session" value ("", "Y"). + pub fn save_use_all_my_displays_for_the_remote_session(&mut self, value: String) { let mut config = self.load_config(); - config.use_all_my_monitors_when_connecting = value; + config.use_all_my_displays_for_the_remote_session = value; self.save_config(config); } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 19b83590c..fda3247b9 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -355,19 +355,19 @@ pub fn session_set_displays_as_individual_windows(session_id: SessionID, value: } } -pub fn session_get_use_all_my_monitors_when_connecting( +pub fn session_get_use_all_my_displays_for_the_remote_session( session_id: SessionID, ) -> SyncReturn> { if let Some(session) = sessions::get_session_by_session_id(&session_id) { - SyncReturn(Some(session.get_use_all_my_monitors_when_connecting())) + SyncReturn(Some(session.get_use_all_my_displays_for_the_remote_session())) } else { SyncReturn(None) } } -pub fn session_set_use_all_my_monitors_when_connecting(session_id: SessionID, value: String) { +pub fn session_set_use_all_my_displays_for_the_remote_session(session_id: SessionID, value: String) { if let Some(session) = sessions::get_session_by_session_id(&session_id) { - session.save_use_all_my_monitors_when_connecting(value); + session.save_use_all_my_displays_for_the_remote_session(value); } } diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 37e933927..991691886 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -240,8 +240,8 @@ impl Session { self.lc.read().unwrap().displays_as_individual_windows.clone() } - pub fn get_use_all_my_monitors_when_connecting(&self) -> String { - self.lc.read().unwrap().use_all_my_monitors_when_connecting.clone() + 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() } pub fn save_reverse_mouse_wheel(&self, value: String) { @@ -252,8 +252,8 @@ impl Session { self.lc.write().unwrap().save_displays_as_individual_windows(value); } - pub fn save_use_all_my_monitors_when_connecting(&self, value: String) { - self.lc.write().unwrap().save_use_all_my_monitors_when_connecting(value); + 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); } pub fn save_view_style(&self, value: String) { From f9f463e7995a0a9fa52586dd032766ccd3e9cba4 Mon Sep 17 00:00:00 2001 From: dignow Date: Tue, 17 Oct 2023 14:29:14 +0800 Subject: [PATCH 019/114] fix, use RxBool to sync fullscreen state (remote toolbar) Signed-off-by: dignow --- flutter/lib/common.dart | 4 ++-- flutter/lib/consts.dart | 3 ++- .../lib/desktop/widgets/remote_toolbar.dart | 16 +++++++-------- flutter/lib/models/state_model.dart | 20 +++++++++---------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 7fd80d863..545b8a238 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1494,7 +1494,7 @@ Future saveWindowPosition(WindowType type, {int? windowId}) async { late Offset position; late Size sz; late bool isMaximized; - bool isFullscreen = stateGlobal.fullscreen || + bool isFullscreen = stateGlobal.fullscreen.isTrue || (Platform.isMacOS && stateGlobal.closeOnFullscreen); setFrameIfMaximized() { if (isMaximized) { @@ -2710,7 +2710,7 @@ tryMoveToScreenAndSetFullscreen(Rect? screenRect) async { final curFrame = await wc.getFrame(); final frame = Rect.fromLTWH(screenRect.left + 30, screenRect.top + 30, 600, 400); - if (stateGlobal.fullscreen && + if (stateGlobal.fullscreen.isTrue && curFrame.left <= frame.left && curFrame.top <= frame.top && curFrame.width >= frame.width && diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 9f0a5b56f..e4d777ccb 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/models/state_model.dart'; +import 'package:get/get.dart'; const double kDesktopRemoteTabBarHeight = 28.0; const int kInvalidWindowId = -1; @@ -88,7 +89,7 @@ const double kDesktopFileTransferHeaderHeight = 25.0; EdgeInsets get kDragToResizeAreaPadding => !kUseCompatibleUiMode && Platform.isLinux - ? stateGlobal.fullscreen || stateGlobal.isMaximized.value + ? stateGlobal.fullscreen.isTrue || stateGlobal.isMaximized.value ? EdgeInsets.zero : EdgeInsets.all(5.0) : EdgeInsets.zero; diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 4065ebfb2..7439ed6c8 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -351,7 +351,6 @@ class _RemoteToolbarState extends State { int get windowId => stateGlobal.windowId; - bool get isFullscreen => stateGlobal.fullscreen; void _setFullscreen(bool v) { stateGlobal.setFullscreen(v); setState(() {}); @@ -797,7 +796,7 @@ class ScreenAdjustor { required this.cbExitFullscreen, }); - bool get isFullscreen => stateGlobal.fullscreen; + bool get isFullscreen => stateGlobal.fullscreen.isTrue; int get windowId => stateGlobal.windowId; adjustWindow(BuildContext context) { @@ -951,7 +950,6 @@ class _DisplayMenuState extends State<_DisplayMenu> { cbExitFullscreen: () => widget.setFullscreen(false), ); - bool get isFullscreen => stateGlobal.fullscreen; int get windowId => stateGlobal.windowId; Map get perms => widget.ffi.ffiModel.permissions; PeerInfo get pi => widget.ffi.ffiModel.pi; @@ -2060,21 +2058,21 @@ class _DraggableShowHideState extends State<_DraggableShowHide> { mainAxisSize: MainAxisSize.min, children: [ _buildDraggable(context), - TextButton( + Obx(()=>TextButton( onPressed: () { - widget.setFullscreen(!isFullscreen); + widget.setFullscreen(!isFullscreen.value); setState(() {}); }, child: Tooltip( - message: translate(isFullscreen ? 'Exit Fullscreen' : 'Fullscreen'), + message: translate(isFullscreen.isTrue ? 'Exit Fullscreen' : 'Fullscreen'), child: Icon( - isFullscreen ? Icons.fullscreen_exit : Icons.fullscreen, + isFullscreen.isTrue ? Icons.fullscreen_exit : Icons.fullscreen, size: iconSize, ), ), - ), + )), Offstage( - offstage: !isFullscreen, + offstage: !isFullscreen.value, child: TextButton( onPressed: () => widget.setMinimize(), child: Tooltip( diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index e6744ff77..82176c1a0 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -11,7 +11,7 @@ enum SvcStatus { notReady, connecting, ready } class StateGlobal { int _windowId = -1; bool grabKeyboard = false; - bool _fullscreen = false; + RxBool _fullscreen = false.obs; bool _isMinimized = false; final RxBool isMaximized = false.obs; final RxBool _showTabBar = true.obs; @@ -26,9 +26,9 @@ class StateGlobal { final Map> _lastResolutionGroupValues = {}; int get windowId => _windowId; - bool get fullscreen => _fullscreen; + RxBool get fullscreen => _fullscreen; bool get isMinimized => _isMinimized; - double get tabBarHeight => fullscreen ? 0 : kDesktopRemoteTabBarHeight; + double get tabBarHeight => fullscreen.isTrue ? 0 : kDesktopRemoteTabBarHeight; RxBool get showTabBar => _showTabBar; RxDouble get resizeEdgeSize => _resizeEdgeSize; RxDouble get windowBorderWidth => _windowBorderWidth; @@ -51,7 +51,7 @@ class StateGlobal { setWindowId(int id) => _windowId = id; setMaximized(bool v) { - if (!_fullscreen) { + if (!_fullscreen.isTrue) { if (isMaximized.value != v) { isMaximized.value = v; _resizeEdgeSize.value = @@ -66,20 +66,20 @@ class StateGlobal { setMinimized(bool v) => _isMinimized = v; setFullscreen(bool v, {bool procWnd = true}) { - if (_fullscreen != v) { - _fullscreen = v; - _showTabBar.value = !_fullscreen; - _resizeEdgeSize.value = fullscreen + if (_fullscreen.value != v) { + _fullscreen.value = v; + _showTabBar.value = !_fullscreen.value; + _resizeEdgeSize.value = fullscreen.isTrue ? kFullScreenEdgeSize : isMaximized.isTrue ? kMaximizeEdgeSize : kWindowEdgeSize; print( "fullscreen: $fullscreen, resizeEdgeSize: ${_resizeEdgeSize.value}"); - _windowBorderWidth.value = fullscreen ? 0 : kWindowBorderWidth; + _windowBorderWidth.value = fullscreen.isTrue ? 0 : kWindowBorderWidth; if (procWnd) { final wc = WindowController.fromWindowId(windowId); - wc.setFullscreen(_fullscreen).then((_) { + wc.setFullscreen(_fullscreen.isTrue).then((_) { // https://github.com/leanflutter/window_manager/issues/131#issuecomment-1111587982 if (Platform.isWindows && !v) { Future.delayed(Duration.zero, () async { From b2404809fc98579ab19a5a49a5cfca3e6250338f Mon Sep 17 00:00:00 2001 From: dignow Date: Tue, 17 Oct 2023 14:31:04 +0800 Subject: [PATCH 020/114] trivial, add final Signed-off-by: dignow --- flutter/lib/models/state_model.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index 82176c1a0..4afd77db2 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -11,7 +11,7 @@ enum SvcStatus { notReady, connecting, ready } class StateGlobal { int _windowId = -1; bool grabKeyboard = false; - RxBool _fullscreen = false.obs; + final RxBool _fullscreen = false.obs; bool _isMinimized = false; final RxBool isMaximized = false.obs; final RxBool _showTabBar = true.obs; From fdfeec54d72903c14967af7c43ca6af7a9abbeba Mon Sep 17 00:00:00 2001 From: dignow Date: Tue, 17 Oct 2023 14:42:35 +0800 Subject: [PATCH 021/114] Remove the unnecessary setState, as RxBool is used Signed-off-by: dignow --- .../lib/desktop/widgets/remote_toolbar.dart | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 7439ed6c8..88638f0b1 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -353,7 +353,8 @@ class _RemoteToolbarState extends State { void _setFullscreen(bool v) { stateGlobal.setFullscreen(v); - setState(() {}); + // stateGlobal.fullscreen is RxBool now, no need to call setState. + // setState(() {}); } RxBool get show => widget.state.show; @@ -2058,32 +2059,34 @@ class _DraggableShowHideState extends State<_DraggableShowHide> { mainAxisSize: MainAxisSize.min, children: [ _buildDraggable(context), - Obx(()=>TextButton( - onPressed: () { - widget.setFullscreen(!isFullscreen.value); - setState(() {}); - }, - child: Tooltip( - message: translate(isFullscreen.isTrue ? 'Exit Fullscreen' : 'Fullscreen'), - child: Icon( - isFullscreen.isTrue ? Icons.fullscreen_exit : Icons.fullscreen, - size: iconSize, - ), - ), - )), - Offstage( - offstage: !isFullscreen.value, - child: TextButton( - onPressed: () => widget.setMinimize(), - child: Tooltip( - message: translate('Minimize'), - child: Icon( - Icons.remove, - size: iconSize, + Obx(() => TextButton( + onPressed: () { + widget.setFullscreen(!isFullscreen.value); + }, + child: Tooltip( + message: translate( + isFullscreen.isTrue ? 'Exit Fullscreen' : 'Fullscreen'), + child: Icon( + isFullscreen.isTrue + ? Icons.fullscreen_exit + : Icons.fullscreen, + size: iconSize, + ), ), - ), - ), - ), + )), + Obx(() => Offstage( + offstage: isFullscreen.isFalse, + child: TextButton( + onPressed: () => widget.setMinimize(), + child: Tooltip( + message: translate('Minimize'), + child: Icon( + Icons.remove, + size: iconSize, + ), + ), + ), + )), TextButton( onPressed: () => setState(() { widget.show.value = !widget.show.value; From ad5a173f3f4ba85862c267c291a7b92833207e76 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:39:55 +0200 Subject: [PATCH 022/114] Update Italian language --- src/lang/it.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/it.rs b/src/lang/it.rs index 129d10eb6..617e0f0c5 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -565,6 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Passo allo schermo principale perché in modalità elevata non sono supportati più schermi."), ("Open in new window", "Apri in una nuova finestra"), ("Show displays as individual windows", "Visualizza schermi come finestre individuali"), - ("Use all my displays for the remote session", ""), + ("Use all my displays for the remote session", "Usa tutti gli schermi per la sessione remota"), ].iter().cloned().collect(); } From e0985ebb1c5931ef5fa390882b57a4c3b6aacb05 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 17 Oct 2023 18:22:27 +0530 Subject: [PATCH 023/114] add peers loading indicator Signed-off-by: Sahil Yeole --- .../lib/desktop/pages/connection_page.dart | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 78f7844a9..7c4da7d9c 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -51,6 +51,7 @@ class _ConnectionPageState extends State return list.sublist(0, n); } } + bool isPeersLoading = false; @override void initState() { @@ -152,8 +153,18 @@ class _ConnectionPageState extends State connect(context, id, isFileTransfer: isFileTransfer); } - Future getAllPeers() async { - peers.clear(); + Future _fetchPeers() async { + setState(() { + isPeersLoading = true; + }); + await Future.delayed(Duration(milliseconds: 100)); + await _getAllPeers(); + setState(() { + isPeersLoading = false; + }); + } + + Future _getAllPeers() async { Map recentPeers = jsonDecode(await bind.mainLoadRecentPeersSync()); Map favPeers = jsonDecode(await bind.mainLoadFavPeersSync()); Map lanPeers = jsonDecode(await bind.mainLoadLanPeersSync()); @@ -194,15 +205,17 @@ class _ConnectionPageState extends State mergePeers(abPeers); mergePeers(groupPeers); + List parsedPeers = []; + for (var peer in combinedPeers.values) { - peers.add(Peer.fromJson(peer)); + parsedPeers.add(Peer.fromJson(peer)); } + peers = parsedPeers; } /// UI for the remote ID TextField. /// Search for a peer. Widget _buildRemoteIDTextField(BuildContext context) { - getAllPeers(); var w = Container( width: 320 + 20 * 2, padding: const EdgeInsets.fromLTRB(20, 24, 20, 22), @@ -235,6 +248,22 @@ class _ConnectionPageState extends State if (textEditingValue.text == '') { return const Iterable.empty(); } + else if (peers.isEmpty) { + Peer emptyPeer = Peer( + id: '', + username: '', + hostname: '', + alias: '', + platform: '', + tags: [], + hash: '', + forceAlwaysRelay: false, + rdpPort: '', + rdpUsername: '', + loginName: '', + ); + return [emptyPeer]; + } else { if (textEditingValue.text.contains(" ")) { textEditingValue = TextEditingValue( @@ -261,6 +290,9 @@ class _ConnectionPageState extends State fieldTextEditingController.text = _idController.text; fieldFocusNode.addListener(() { _idInputFocused.value = fieldFocusNode.hasFocus; + if (fieldFocusNode.hasFocus && !isPeersLoading){ + _fetchPeers(); + } // select all to faciliate removing text, just following the behavior of address input of chrome _idController.selection = TextSelection( baseOffset: 0, extentOffset: _idController.value.text.length); @@ -310,8 +342,7 @@ class _ConnectionPageState extends State double maxHeight = 0; for (var peer in options) { if (maxHeight < 200) - maxHeight += 52; - } + maxHeight += 50; }; return Align( alignment: Alignment.topLeft, child: Material( @@ -321,7 +352,16 @@ class _ConnectionPageState extends State maxHeight: maxHeight, maxWidth: 320, ), - child: Padding( + child: peers.isEmpty && isPeersLoading + ? Container( + height: 80, + child: Center( + child: CircularProgressIndicator( + strokeWidth: 2, + ), + ) + ) + : Padding( padding: const EdgeInsets.only(top: 5), child: ListView( children: options From c00d4c1a7bb1989df98acc276e697c9f05203a3c Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 17 Oct 2023 18:23:44 +0530 Subject: [PATCH 024/114] update _fetchPeers Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 7c4da7d9c..f9984b955 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -157,11 +157,11 @@ class _ConnectionPageState extends State setState(() { isPeersLoading = true; }); - await Future.delayed(Duration(milliseconds: 100)); - await _getAllPeers(); - setState(() { - isPeersLoading = false; - }); + await Future.delayed(Duration(milliseconds: 100)); + await _getAllPeers(); + setState(() { + isPeersLoading = false; + }); } Future _getAllPeers() async { From 1ad740800b49e5266f02c40a238ca18d2e419035 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 17 Oct 2023 18:35:38 +0530 Subject: [PATCH 025/114] remove spaces only if number Signed-off-by: Sahil Yeole --- .../lib/desktop/pages/connection_page.dart | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index f9984b955..944fd0370 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -265,20 +265,21 @@ class _ConnectionPageState extends State return [emptyPeer]; } else { - if (textEditingValue.text.contains(" ")) { - textEditingValue = TextEditingValue( - text: textEditingValue.text.replaceAll(" ", ""), - selection: textEditingValue.selection, - ); - } + String textWithoutSpaces = textEditingValue.text.replaceAll(" ", ""); + if (int.tryParse(textWithoutSpaces) != null) { + textEditingValue = TextEditingValue( + text: textWithoutSpaces, + selection: textEditingValue.selection, + ); + } - return peers.where((peer) => - peer.id.toLowerCase().contains(textEditingValue.text.toLowerCase()) || - peer.username.toLowerCase().contains(textEditingValue.text.toLowerCase()) || - peer.hostname.toLowerCase().contains(textEditingValue.text.toLowerCase()) || - peer.alias.toLowerCase().contains(textEditingValue.text.toLowerCase()) || - peer.platform.toLowerCase().contains(textEditingValue.text.toLowerCase())) - .toList(); + return peers.where((peer) => + peer.id.toLowerCase().contains(textEditingValue.text.toLowerCase()) || + peer.username.toLowerCase().contains(textEditingValue.text.toLowerCase()) || + peer.hostname.toLowerCase().contains(textEditingValue.text.toLowerCase()) || + peer.alias.toLowerCase().contains(textEditingValue.text.toLowerCase()) || + peer.platform.toLowerCase().contains(textEditingValue.text.toLowerCase())) + .toList(); } }, From 9e2c9cbba93f6ddb86417fa9ea8ba3637ec6de69 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 17 Oct 2023 18:57:53 +0530 Subject: [PATCH 026/114] add border radius Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 944fd0370..db0aaf801 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -346,12 +346,14 @@ class _ConnectionPageState extends State maxHeight += 50; }; return Align( alignment: Alignment.topLeft, - child: Material( + child: ClipRRect( + borderRadius: BorderRadius.circular(5), + child: Material( elevation: 4, child: ConstrainedBox( constraints: BoxConstraints( maxHeight: maxHeight, - maxWidth: 320, + maxWidth: 319, ), child: peers.isEmpty && isPeersLoading ? Container( @@ -371,7 +373,7 @@ class _ConnectionPageState extends State ), ), ), - ), + )), ); }, ) From 2e829956f411bc59f119b59846b7368ae242b199 Mon Sep 17 00:00:00 2001 From: 21pages Date: Tue, 17 Oct 2023 18:49:34 +0800 Subject: [PATCH 027/114] android write rust log to ExternalStorage/RustDesk/Logs Signed-off-by: 21pages --- libs/hbb_common/src/config.rs | 11 +++++++++-- src/flutter_ffi.rs | 13 +++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 82867ad73..6f7bebdc0 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -341,8 +341,8 @@ impl Default for PeerConfig { view_only: Default::default(), reverse_mouse_wheel: Self::default_reverse_mouse_wheel(), displays_as_individual_windows: Self::default_displays_as_individual_windows(), - use_all_my_displays_for_the_remote_session: Self::default_use_all_my_displays_for_the_remote_session( - ), + use_all_my_displays_for_the_remote_session: + Self::default_use_all_my_displays_for_the_remote_session(), custom_resolutions: Default::default(), options: Self::default_options(), ui_flutter: Default::default(), @@ -623,6 +623,13 @@ impl Config { std::fs::create_dir_all(&path).ok(); return path; } + #[cfg(target_os = "android")] + { + let mut path = Self::get_home(); + path.push(format!("{}/Logs", *APP_NAME.read().unwrap())); + std::fs::create_dir_all(&path).ok(); + return path; + } if let Some(path) = Self::path("").parent() { let mut path: PathBuf = path.into(); path.push("log"); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index fda3247b9..14cc32978 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -39,11 +39,15 @@ fn initialize(app_dir: &str) { *config::APP_DIR.write().unwrap() = app_dir.to_owned(); #[cfg(target_os = "android")] { + // flexi_logger can't work when android_logger initialized. + #[cfg(debug_assertions)] android_logger::init_once( android_logger::Config::default() .with_max_level(log::LevelFilter::Debug) // limit log level .with_tag("ffi"), // logs will show under mytag tag ); + #[cfg(not(debug_assertions))] + hbb_common::init_log(false, ""); #[cfg(feature = "mediacodec")] scrap::mediacodec::check_mediacodec(); crate::common::test_rendezvous_server(); @@ -359,13 +363,18 @@ pub fn session_get_use_all_my_displays_for_the_remote_session( session_id: SessionID, ) -> SyncReturn> { if let Some(session) = sessions::get_session_by_session_id(&session_id) { - SyncReturn(Some(session.get_use_all_my_displays_for_the_remote_session())) + SyncReturn(Some( + session.get_use_all_my_displays_for_the_remote_session(), + )) } else { SyncReturn(None) } } -pub fn session_set_use_all_my_displays_for_the_remote_session(session_id: SessionID, value: String) { +pub fn session_set_use_all_my_displays_for_the_remote_session( + session_id: SessionID, + value: String, +) { if let Some(session) = sessions::get_session_by_session_id(&session_id) { session.save_use_all_my_displays_for_the_remote_session(value); } From 149d57150c732d0927e87f3ee95a73c767973cf9 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 17 Oct 2023 21:29:05 +0530 Subject: [PATCH 028/114] attempt fix text selection Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index db0aaf801..604cd3f93 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -69,12 +69,6 @@ class _ConnectionPageState extends State _updateTimer = periodic_immediate(Duration(seconds: 1), () async { updateStatus(); }); - _idFocusNode.addListener(() { - _idInputFocused.value = _idFocusNode.hasFocus; - // select all to faciliate removing text, just following the behavior of address input of chrome - _idController.selection = TextSelection( - baseOffset: 0, extentOffset: _idController.value.text.length); - }); Get.put(_idController); windowManager.addListener(this); } @@ -289,14 +283,16 @@ class _ConnectionPageState extends State VoidCallback onFieldSubmitted, ) { fieldTextEditingController.text = _idController.text; - fieldFocusNode.addListener(() { + fieldFocusNode.addListener(() async { _idInputFocused.value = fieldFocusNode.hasFocus; if (fieldFocusNode.hasFocus && !isPeersLoading){ _fetchPeers(); } - // select all to faciliate removing text, just following the behavior of address input of chrome - _idController.selection = TextSelection( - baseOffset: 0, extentOffset: _idController.value.text.length); + // select all to facilitate removing text, just following the behavior of address input of chrome + final textLength = fieldTextEditingController.value.text.length; + await Future.delayed(Duration(milliseconds: 200)); + fieldTextEditingController.selection = TextSelection.collapsed(offset: textLength); + fieldTextEditingController.selection = TextSelection(baseOffset: 0, extentOffset: textLength); }); return Obx(() => TextField( From 5a89aa3b329425320e1b867f7dbae2b3eb4d9584 Mon Sep 17 00:00:00 2001 From: Kleofass Date: Tue, 17 Oct 2023 23:58:54 +0300 Subject: [PATCH 029/114] Update lv.rs --- src/lang/lv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/lv.rs b/src/lang/lv.rs index 09eef383b..6dd5a2b0b 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Pārslēdzieties uz primāro displeju, jo paaugstinātajā režīmā netiek atbalstīti vairāki displeji."), ("Open in new window", "Atvērt jaunā logā"), ("Show displays as individual windows", "Rādīt displejus kā atsevišķus logus"), - ("Use all my displays for the remote session", ""), + ("Use all my displays for the remote session", "Izmantot visus manus displejus attālajai sesijai"), ].iter().cloned().collect(); } From c4f09b5598af48bf9682e0c5e29253a61a1360cc Mon Sep 17 00:00:00 2001 From: dignow Date: Tue, 17 Oct 2023 23:31:50 +0800 Subject: [PATCH 030/114] fix, change display resolution Signed-off-by: dignow --- flutter/lib/models/model.dart | 2 +- src/server/connection.rs | 13 +-- src/server/display_service.rs | 155 ++++++++++++++++++++++++---------- src/server/video_service.rs | 121 ++++++++------------------ 4 files changed, 148 insertions(+), 143 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index fb2b96d62..f3d9899e1 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -2282,7 +2282,7 @@ class PeerInfo with ChangeNotifier { if (currentDisplay == kAllDisplayValue) { return null; } - if (currentDisplay > 0 && currentDisplay < displays.length) { + if (currentDisplay >= 0 && currentDisplay < displays.length) { return displays[currentDisplay]; } else { return null; diff --git a/src/server/connection.rs b/src/server/connection.rs index 5f9502397..db594fbcd 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -611,7 +611,7 @@ impl Connection { _ => {}, } } - Some(message::Union::PeerInfo(_)) => { + Some(message::Union::PeerInfo(..)) => { conn.refresh_video_display(None); } _ => {} @@ -1132,11 +1132,13 @@ impl Connection { self.send(msg_out).await; } - match super::display_service::get_displays().await { + match super::display_service::update_get_sync_displays().await { Err(err) => { res.set_error(format!("{}", err)); } Ok(displays) => { + // For compatibility with old versions, we need to send the displays to the peer. + // But the displays may be updated later, before creating the video capturer. pi.displays = displays.clone(); pi.current_display = self.display_idx as _; res.set_peer_info(pi); @@ -2139,13 +2141,6 @@ impl Connection { ..Default::default() }); } - - // send display changed message - if let Some(msg_out) = - video_service::make_display_changed_msg(self.display_idx, None) - { - self.send(msg_out).await; - } } } } diff --git a/src/server/display_service.rs b/src/server/display_service.rs index dd4410312..a6d744694 100644 --- a/src/server/display_service.rs +++ b/src/server/display_service.rs @@ -5,6 +5,12 @@ use crate::virtual_display_manager; use hbb_common::get_version_number; use hbb_common::protobuf::MessageField; use scrap::Display; +#[cfg(target_os = "linux")] +use std::sync::atomic::{AtomicBool, Ordering}; + +// https://github.com/rustdesk/rustdesk/discussions/6042, avoiding dbus call +#[cfg(target_os = "linux")] +pub(super) static IS_X11: AtomicBool = AtomicBool::new(false); pub const NAME: &'static str = "display"; @@ -19,6 +25,59 @@ lazy_static::lazy_static! { // Initial primary display index. // It should only be updated when the rustdesk server is started, and should not be updated when displays changed. pub static ref PRIMARY_DISPLAY_IDX: usize = get_primary(); + static ref SYNC_DISPLAYS: Arc> = Default::default(); +} + +#[derive(Default)] +struct SyncDisplaysInfo { + displays: Vec, + is_synced: bool, +} + +impl SyncDisplaysInfo { + fn check_changed(&mut self, displays: Vec) { + if self.displays.len() != displays.len() { + self.displays = displays; + self.is_synced = false; + return; + } + for (i, d) in displays.iter().enumerate() { + if d != &self.displays[i] { + self.displays = displays; + self.is_synced = false; + return; + } + } + } + + fn get_update_sync_displays(&mut self) -> Option> { + if self.is_synced { + return None; + } + self.is_synced = true; + Some(self.displays.clone()) + } +} + +pub(super) fn check_display_changed( + idx: usize, + (x, y, w, h): (i32, i32, usize, usize), +) -> Option { + #[cfg(target_os = "linux")] + { + // wayland do not support changing display for now + if !IS_X11.load(Ordering::SeqCst) { + return None; + } + } + + let lock = SYNC_DISPLAYS.lock().unwrap(); + let d = lock.displays.get(idx)?; + if !(d.x == x && d.y == y && d.width == w as i32 && d.height == h as i32) { + Some(d.clone()) + } else { + None + } } #[inline] @@ -74,45 +133,27 @@ pub fn is_privacy_mode_supported() -> bool { return false; } -#[derive(Default)] -struct StateDisplay { - synced_displays: Vec, -} - -impl super::service::Reset for StateDisplay { - fn reset(&mut self) { - self.synced_displays.clear(); - } -} - pub fn new() -> GenericService { - let svc = EmptyExtraFieldService::new(NAME.to_owned(), false); - GenericService::repeat::(&svc.clone(), 300, run); + let svc = EmptyExtraFieldService::new(NAME.to_owned(), true); + GenericService::run(&svc.clone(), run); svc.sp } -fn check_get_displays_changed_msg(last_synced_displays: &mut Vec) -> Option { - let displays = try_get_displays().ok()?; - if displays.len() == last_synced_displays.len() { - return None; - } +fn displays_to_msg(displays: Vec) -> Message { + let mut pi = PeerInfo { + ..Default::default() + }; + pi.displays = displays.clone(); + pi.current_display = 0; + let mut msg_out = Message::new(); + msg_out.set_peer_info(pi); + msg_out +} - // Display to DisplayInfo - let displays = to_display_info(&displays); - if last_synced_displays.len() == 0 { - *last_synced_displays = displays; - None - } else { - let mut pi = PeerInfo { - ..Default::default() - }; - pi.displays = displays.clone(); - pi.current_display = 0; - let mut msg_out = Message::new(); - msg_out.set_peer_info(pi); - *last_synced_displays = displays; - Some(msg_out) - } +fn check_get_displays_changed_msg() -> Option { + check_update_displays(try_get_displays().ok()?); + let displays = SYNC_DISPLAYS.lock().unwrap().get_update_sync_displays()?; + Some(displays_to_msg(displays)) } #[cfg(all(windows, feature = "virtual_display_driver"))] @@ -120,11 +161,28 @@ pub fn try_plug_out_virtual_display() { let _res = virtual_display_manager::plug_out_headless(); } -fn run(sp: EmptyExtraFieldService, state: &mut StateDisplay) -> ResultType<()> { - if let Some(msg_out) = check_get_displays_changed_msg(&mut state.synced_displays) { - sp.send(msg_out); - log::info!("Displays changed"); +fn run(sp: EmptyExtraFieldService) -> ResultType<()> { + #[cfg(target_os = "linux")] + { + IS_X11.store(scrap::is_x11(), Ordering::SeqCst); } + + while sp.ok() { + sp.snapshot(|sps| { + if sps.has_subscribes() { + SYNC_DISPLAYS.lock().unwrap().is_synced = false; + bail!("new subscriber"); + } + Ok(()) + })?; + + if let Some(msg_out) = check_get_displays_changed_msg() { + sp.send(msg_out); + log::info!("Displays changed"); + } + std::thread::sleep(Duration::from_millis(300)); + } + Ok(()) } @@ -167,8 +225,11 @@ pub(super) fn get_original_resolution( .into() } -pub fn to_display_info(all: &Vec) -> Vec { - all.iter() +// Display to DisplayInfo +// The DisplayInfo is be sent to the peer. +fn check_update_displays(all: Vec) { + let displays = all + .iter() .map(|d| { let display_name = d.name(); let original_resolution = get_original_resolution(&display_name, d.width(), d.height()); @@ -184,32 +245,34 @@ pub fn to_display_info(all: &Vec) -> Vec { ..Default::default() } }) - .collect::>() + .collect::>(); + SYNC_DISPLAYS.lock().unwrap().check_changed(displays); } pub fn is_inited_msg() -> Option { #[cfg(target_os = "linux")] - if !scrap::is_x11() { + if !IS_X11.load(Ordering::SeqCst) { return super::wayland::is_inited(); } None } -pub async fn get_displays() -> ResultType> { +pub async fn update_get_sync_displays() -> ResultType> { #[cfg(target_os = "linux")] { - if !scrap::is_x11() { + if !IS_X11.load(Ordering::SeqCst) { return super::wayland::get_displays().await; } } - Ok(to_display_info(&try_get_displays()?)) + check_update_displays(try_get_displays()?); + Ok(SYNC_DISPLAYS.lock().unwrap().displays.clone()) } #[inline] pub fn get_primary() -> usize { #[cfg(target_os = "linux")] { - if !scrap::is_x11() { + if !IS_X11.load(Ordering::SeqCst) { return match super::wayland::get_primary() { Ok(n) => n, Err(_) => 0, diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 1dd793fc3..ca5204c78 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -18,7 +18,11 @@ // to-do: // https://slhck.info/video/2017/03/01/rate-control.html -use super::{service::ServiceTmpl, video_qos::VideoQoS, *}; +#[cfg(target_os = "linux")] +use super::display_service::IS_X11; +use super::{display_service::check_display_changed, service::ServiceTmpl, video_qos::VideoQoS, *}; +#[cfg(target_os = "linux")] +use crate::common::SimpleCallOnReturn; #[cfg(windows)] use crate::{platform::windows::is_process_consent_running, privacy_win_mag}; use hbb_common::{ @@ -38,7 +42,7 @@ use scrap::{ CodecName, Display, TraitCapturer, }; #[cfg(target_os = "linux")] -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::Ordering; #[cfg(windows)] use std::sync::Once; use std::{ @@ -49,7 +53,6 @@ use std::{ }; pub const NAME: &'static str = "video"; -pub const OPTION_DISPLAY_CHANGED: &'static str = "changed"; pub const OPTION_REFRESH: &'static str = "refresh"; lazy_static::lazy_static! { @@ -63,10 +66,6 @@ lazy_static::lazy_static! { pub static ref IS_FOREGROUND_WINDOW_ELEVATED: Arc> = Default::default(); } -// https://github.com/rustdesk/rustdesk/discussions/6042, avoiding dbus call -#[cfg(target_os = "linux")] -static IS_X11: AtomicBool = AtomicBool::new(false); - #[inline] pub fn notify_video_frame_fetched(conn_id: i32, frame_tm: Option) { FRAME_FETCHED_NOTIFIER.0.send((conn_id, frame_tm)).ok(); @@ -165,35 +164,6 @@ pub fn new(idx: usize) -> GenericService { vs.sp } -fn check_display_changed( - last_n: usize, - last_current: usize, - last_width: usize, - last_height: usize, -) -> bool { - #[cfg(target_os = "linux")] - { - // wayland do not support changing display for now - if !IS_X11.load(Ordering::SeqCst) { - return false; - } - } - - let displays = match try_get_displays() { - Ok(d) => d, - _ => return false, - }; - - let n = displays.len(); - if n != last_n { - return true; - }; - match displays.get(last_current) { - Some(d) => d.width() != last_width || d.height() != last_height, - None => true, - } -} - // Capturer object is expensive, avoiding to create it frequently. fn create_capturer( privacy_mode_id: i32, @@ -327,7 +297,6 @@ pub(super) struct CapturerInfo { pub origin: (i32, i32), pub width: usize, pub height: usize, - pub ndisplay: usize, pub current: usize, pub privacy_mode_id: i32, pub _capturer_privacy_mode_id: i32, @@ -419,7 +388,6 @@ fn get_capturer( origin, width, height, - ndisplay, current, privacy_mode_id, _capturer_privacy_mode_id: capturer_privacy_mode_id, @@ -431,16 +399,21 @@ fn run(vs: VideoService) -> ResultType<()> { #[cfg(not(any(target_os = "android", target_os = "ios")))] let _wake_lock = get_wake_lock(); - #[cfg(target_os = "linux")] - { - IS_X11.store(scrap::is_x11(), Ordering::SeqCst); - } - + // Wayland only support one video capturer for now. It is ok to call ensure_inited() here. + // // ensure_inited() is needed because clear() may be called. // to-do: wayland ensure_inited should pass current display index. // But for now, we do not support multi-screen capture on wayland. #[cfg(target_os = "linux")] super::wayland::ensure_inited()?; + #[cfg(target_os = "linux")] + let wayland_call_on_ret = SimpleCallOnReturn { + b: true, + f: Box::new(|| { + super::wayland::clear(); + }), + }; + #[cfg(windows)] let last_portable_service_running = crate::portable_service::client::running(); #[cfg(not(windows))] @@ -471,16 +444,6 @@ fn run(vs: VideoService) -> ResultType<()> { c.set_use_yuv(encoder.use_yuv()); VIDEO_QOS.lock().unwrap().store_bitrate(encoder.bitrate()); - if sp.is_option_true(OPTION_DISPLAY_CHANGED) { - log::debug!("Broadcasting display changed"); - broadcast_display_changed( - display_idx, - &sp, - Some((c.name.clone(), c.origin.clone(), c.width, c.height)), - ); - sp.set_option_bool(OPTION_DISPLAY_CHANGED, false); - } - if sp.is_option_true(OPTION_REFRESH) { sp.set_option_bool(OPTION_REFRESH, false); } @@ -518,7 +481,7 @@ fn run(vs: VideoService) -> ResultType<()> { } drop(video_qos); - if sp.is_option_true(OPTION_DISPLAY_CHANGED) || sp.is_option_true(OPTION_REFRESH) { + if sp.is_option_true(OPTION_REFRESH) { bail!("SWITCH"); } if codec_name != Encoder::negotiated_codec() { @@ -540,12 +503,11 @@ fn run(vs: VideoService) -> ResultType<()> { let now = time::Instant::now(); if last_check_displays.elapsed().as_millis() > 1000 { last_check_displays = now; - - // Capturer on macos does not return Err event the solution is changed. - #[cfg(target_os = "macos")] - if check_display_changed(c.ndisplay, c.current, c.width, c.height) { - sp.set_option_bool(OPTION_DISPLAY_CHANGED, true); - log::info!("Displays changed"); + if let Some(display) = + check_display_changed(c.current, (c.origin.0, c.origin.1, c.width, c.height)) + { + log::info!("Display {} changed", display); + broadcast_display_changed(display_idx, &sp, &c.name, display); bail!("SWITCH"); } } @@ -624,21 +586,12 @@ fn run(vs: VideoService) -> ResultType<()> { } } Err(err) => { - if check_display_changed(c.ndisplay, c.current, c.width, c.height) { - log::info!("Displays changed"); - #[cfg(target_os = "linux")] - super::wayland::clear(); - sp.set_option_bool(OPTION_DISPLAY_CHANGED, true); - bail!("SWITCH"); - } - #[cfg(windows)] if !c.is_gdi() { c.set_gdi(); log::info!("dxgi error, fall back to gdi: {:?}", err); continue; } - return Err(err.into()); } _ => { @@ -671,9 +624,6 @@ fn run(vs: VideoService) -> ResultType<()> { } } - #[cfg(target_os = "linux")] - super::wayland::clear(); - Ok(()) } @@ -892,9 +842,10 @@ fn get_wake_lock() -> crate::platform::WakeLock { fn broadcast_display_changed( display_idx: usize, sp: &GenericService, - display_meta: Option<(String, (i32, i32), usize, usize)>, + name: &str, + display: DisplayInfo, ) { - if let Some(msg_out) = make_display_changed_msg(display_idx, display_meta) { + if let Some(msg_out) = make_display_changed_msg(display_idx, name, display) { sp.send(msg_out); } } @@ -913,34 +864,30 @@ fn get_display_info_simple_meta(display_idx: usize) -> Option<(String, (i32, i32 } } -pub fn make_display_changed_msg( +fn make_display_changed_msg( display_idx: usize, - display_meta: Option<(String, (i32, i32), usize, usize)>, + name: &str, + display: DisplayInfo, ) -> Option { let mut misc = Misc::new(); - let (name, origin, width, height) = match display_meta { - Some(d) => d, - None => get_display_info_simple_meta(display_idx)?, - }; - let original_resolution = display_service::get_original_resolution(&name, width, height); misc.set_switch_display(SwitchDisplay { display: display_idx as _, - x: origin.0, - y: origin.1, - width: width as _, - height: height as _, + x: display.x, + y: display.y, + width: display.width, + height: display.height, cursor_embedded: display_service::capture_cursor_embedded(), #[cfg(not(any(target_os = "android", target_os = "ios")))] resolutions: Some(SupportedResolutions { resolutions: if name.is_empty() { vec![] } else { - crate::platform::resolutions(&name) + crate::platform::resolutions(name) }, ..SupportedResolutions::default() }) .into(), - original_resolution, + original_resolution: display.original_resolution, ..Default::default() }); let mut msg_out = Message::new(); From a32e740242339a078d1e30f68d28a828c0a9ba24 Mon Sep 17 00:00:00 2001 From: dignow Date: Wed, 18 Oct 2023 08:07:00 +0800 Subject: [PATCH 031/114] fix build linux Signed-off-by: dignow --- src/core_main.rs | 2 +- src/server/display_service.rs | 11 ++++++++--- src/server/video_service.rs | 2 +- src/server/wayland.rs | 15 ++++++++------- src/tray.rs | 15 +++++++++------ 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/core_main.rs b/src/core_main.rs index e7bb4d0f6..f1669d36b 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -1,4 +1,4 @@ -#[cfg(not(any(target_os = "android", target_os = "ios")))] +#[cfg(windows)] use crate::client::translate; #[cfg(not(debug_assertions))] #[cfg(not(any(target_os = "android", target_os = "ios")))] diff --git a/src/server/display_service.rs b/src/server/display_service.rs index a6d744694..878526872 100644 --- a/src/server/display_service.rs +++ b/src/server/display_service.rs @@ -151,7 +151,7 @@ fn displays_to_msg(displays: Vec) -> Message { } fn check_get_displays_changed_msg() -> Option { - check_update_displays(try_get_displays().ok()?); + check_update_displays(&try_get_displays().ok()?); let displays = SYNC_DISPLAYS.lock().unwrap().get_update_sync_displays()?; Some(displays_to_msg(displays)) } @@ -225,9 +225,14 @@ pub(super) fn get_original_resolution( .into() } +#[cfg(target_os = "linux")] +pub(super) fn get_sync_displays() -> Vec { + SYNC_DISPLAYS.lock().unwrap().displays.clone() +} + // Display to DisplayInfo // The DisplayInfo is be sent to the peer. -fn check_update_displays(all: Vec) { +pub(super) fn check_update_displays(all: &Vec) { let displays = all .iter() .map(|d| { @@ -264,7 +269,7 @@ pub async fn update_get_sync_displays() -> ResultType> { return super::wayland::get_displays().await; } } - check_update_displays(try_get_displays()?); + check_update_displays(&try_get_displays()?); Ok(SYNC_DISPLAYS.lock().unwrap().displays.clone()) } diff --git a/src/server/video_service.rs b/src/server/video_service.rs index ca5204c78..25b08bb3e 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -407,7 +407,7 @@ fn run(vs: VideoService) -> ResultType<()> { #[cfg(target_os = "linux")] super::wayland::ensure_inited()?; #[cfg(target_os = "linux")] - let wayland_call_on_ret = SimpleCallOnReturn { + let _wayland_call_on_ret = SimpleCallOnReturn { b: true, f: Box::new(|| { super::wayland::clear(); diff --git a/src/server/wayland.rs b/src/server/wayland.rs index f26b27b20..2be67bc32 100644 --- a/src/server/wayland.rs +++ b/src/server/wayland.rs @@ -84,7 +84,6 @@ impl TraitCapturer for CapturerPtr { struct CapDisplayInfo { rects: Vec<((i32, i32), usize, usize)>, displays: Vec, - num: usize, primary: usize, current: usize, capturer: CapturerPtr, @@ -146,7 +145,8 @@ pub(super) async fn check_init() -> ResultType<()> { let num = all.len(); let primary = super::display_service::get_primary_2(&all); let current = primary; - let mut displays = super::display_service::to_display_info(&all); + super::display_service::check_update_displays(&all); + let mut displays = super::display_service::get_sync_displays(); for display in displays.iter_mut() { display.cursor_embedded = is_cursor_embedded(); } @@ -173,12 +173,15 @@ pub(super) async fn check_init() -> ResultType<()> { Some(result) if !result.is_empty() => { let resolution: Vec<&str> = result.split(" ").collect(); let w: i32 = resolution[0].parse().unwrap_or(origin.0 + width as i32); - let h: i32 = resolution[2].trim_end_matches(",").parse().unwrap_or(origin.1 + height as i32); + let h: i32 = resolution[2] + .trim_end_matches(",") + .parse() + .unwrap_or(origin.1 + height as i32); (w, h) } - _ => (origin.0 + width as i32, origin.1 + height as i32) + _ => (origin.0 + width as i32, origin.1 + height as i32), }; - + minx = 0; maxx = max_width; miny = 0; @@ -191,7 +194,6 @@ pub(super) async fn check_init() -> ResultType<()> { let cap_display_info = Box::into_raw(Box::new(CapDisplayInfo { rects, displays, - num, primary, current, capturer, @@ -273,7 +275,6 @@ pub(super) fn get_capturer() -> ResultType { origin: rect.0, width: rect.1, height: rect.2, - ndisplay: cap_display_info.num, current: cap_display_info.current, privacy_mode_id: 0, _capturer_privacy_mode_id: 0, diff --git a/src/tray.rs b/src/tray.rs index 7b05be101..221a8a7fe 100644 --- a/src/tray.rs +++ b/src/tray.rs @@ -1,9 +1,12 @@ -use crate::{client::translate, ipc::Data}; -use hbb_common::{allow_err, log, tokio}; -use std::{ - sync::{Arc, Mutex}, - time::Duration, -}; +use crate::client::translate; +#[cfg(windows)] +use crate::ipc::Data; +#[cfg(windows)] +use hbb_common::tokio; +use hbb_common::{allow_err, log}; +use std::sync::{Arc, Mutex}; +#[cfg(windows)] +use std::time::Duration; pub fn start_tray() { allow_err!(make_tray()); From c1b865d00e95bb63921b42d914b5a8307373785b Mon Sep 17 00:00:00 2001 From: dignow Date: Wed, 18 Oct 2023 09:59:02 +0800 Subject: [PATCH 032/114] fix, change_display_resolution, add comments Signed-off-by: dignow --- flutter/lib/models/model.dart | 13 ++++++------- src/server/display_service.rs | 12 ++++++++++++ src/server/video_service.rs | 34 +++++++++++++++++----------------- src/server/wayland.rs | 3 +++ 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index f3d9899e1..ce4cbe523 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -430,14 +430,12 @@ class FfiModel with ChangeNotifier { Map evt, SessionID sessionId, String peerId) { final curDisplay = int.parse(evt['display']); - // The message should be handled by the another UI session. - if (isChooseDisplayToOpenInNewWindow(_pi, sessionId)) { - if (curDisplay != _pi.currentDisplay) { - return; - } - } - if (_pi.currentDisplay != kAllDisplayValue) { + if (bind.peerGetDefaultSessionsCount(id: peerId) > 1) { + if (curDisplay != _pi.currentDisplay) { + return; + } + } _pi.currentDisplay = curDisplay; } @@ -825,6 +823,7 @@ class FfiModel with ChangeNotifier { } _pi.displays = newDisplays; _pi.displaysCount.value = _pi.displays.length; + if (_pi.currentDisplay == kAllDisplayValue) { updateCurDisplay(sessionId); // to-do: What if the displays are changed? diff --git a/src/server/display_service.rs b/src/server/display_service.rs index 878526872..eb9b4272b 100644 --- a/src/server/display_service.rs +++ b/src/server/display_service.rs @@ -59,7 +59,10 @@ impl SyncDisplaysInfo { } } +// This function is really useful, though a duplicate check if display changed. +// Because the video server will send the supported resolutions of the {idx} display to the subscribers. pub(super) fn check_display_changed( + ndisplay: usize, idx: usize, (x, y, w, h): (i32, i32, usize, usize), ) -> Option { @@ -72,7 +75,14 @@ pub(super) fn check_display_changed( } let lock = SYNC_DISPLAYS.lock().unwrap(); + // If plugging out a monitor && lock.displays.get(idx) is None. + // 1. The client version < 1.2.4. The client side has to reconnect. + // 2. The client version > 1.2.4, The client side can handle the case becuase sync peer info message will be sent. + // But it is acceptable to for the user to reconnect manually, becuase the monitor is unplugged. let d = lock.displays.get(idx)?; + if ndisplay != lock.displays.len() { + return Some(d.clone()); + } if !(d.x == x && d.y == y && d.width == w as i32 && d.height == h as i32) { Some(d.clone()) } else { @@ -144,6 +154,8 @@ fn displays_to_msg(displays: Vec) -> Message { ..Default::default() }; pi.displays = displays.clone(); + // current_display should not be used in server. + // It is set to 0 for compatibility with old clients. pi.current_display = 0; let mut msg_out = Message::new(); msg_out.set_peer_info(pi); diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 25b08bb3e..664ca6628 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -297,6 +297,7 @@ pub(super) struct CapturerInfo { pub origin: (i32, i32), pub width: usize, pub height: usize, + pub ndisplay: usize, pub current: usize, pub privacy_mode_id: i32, pub _capturer_privacy_mode_id: i32, @@ -388,6 +389,7 @@ fn get_capturer( origin, width, height, + ndisplay, current, privacy_mode_id, _capturer_privacy_mode_id: capturer_privacy_mode_id, @@ -503,9 +505,11 @@ fn run(vs: VideoService) -> ResultType<()> { let now = time::Instant::now(); if last_check_displays.elapsed().as_millis() > 1000 { last_check_displays = now; - if let Some(display) = - check_display_changed(c.current, (c.origin.0, c.origin.1, c.width, c.height)) - { + if let Some(display) = check_display_changed( + c.ndisplay, + c.current, + (c.origin.0, c.origin.1, c.width, c.height), + ) { log::info!("Display {} changed", display); broadcast_display_changed(display_idx, &sp, &c.name, display); bail!("SWITCH"); @@ -586,6 +590,16 @@ fn run(vs: VideoService) -> ResultType<()> { } } Err(err) => { + if let Some(display) = check_display_changed( + c.ndisplay, + c.current, + (c.origin.0, c.origin.1, c.width, c.height), + ) { + log::info!("Display {} changed", display); + broadcast_display_changed(display_idx, &sp, &c.name, display); + bail!("SWITCH"); + } + #[cfg(windows)] if !c.is_gdi() { c.set_gdi(); @@ -850,20 +864,6 @@ fn broadcast_display_changed( } } -fn get_display_info_simple_meta(display_idx: usize) -> Option<(String, (i32, i32), usize, usize)> { - let displays = display_service::try_get_displays().ok()?; - if let Some(display) = displays.get(display_idx) { - Some(( - display.name(), - display.origin(), - display.width(), - display.height(), - )) - } else { - None - } -} - fn make_display_changed_msg( display_idx: usize, name: &str, diff --git a/src/server/wayland.rs b/src/server/wayland.rs index 2be67bc32..02e83fdc2 100644 --- a/src/server/wayland.rs +++ b/src/server/wayland.rs @@ -84,6 +84,7 @@ impl TraitCapturer for CapturerPtr { struct CapDisplayInfo { rects: Vec<((i32, i32), usize, usize)>, displays: Vec, + num: usize, primary: usize, current: usize, capturer: CapturerPtr, @@ -194,6 +195,7 @@ pub(super) async fn check_init() -> ResultType<()> { let cap_display_info = Box::into_raw(Box::new(CapDisplayInfo { rects, displays, + num, primary, current, capturer, @@ -275,6 +277,7 @@ pub(super) fn get_capturer() -> ResultType { origin: rect.0, width: rect.1, height: rect.2, + ndisplay: cap_display_info.num, current: cap_display_info.current, privacy_mode_id: 0, _capturer_privacy_mode_id: 0, From 21f7d6c9b9c6be0810f18d0592e632fcb9c7f400 Mon Sep 17 00:00:00 2001 From: dignow Date: Wed, 18 Oct 2023 10:45:46 +0800 Subject: [PATCH 033/114] fix/change_display_resolution, send switch display msg Signed-off-by: dignow --- src/server/connection.rs | 6 ++++++ src/server/display_service.rs | 4 ++++ src/server/video_service.rs | 33 ++++++++++++++++++--------------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/server/connection.rs b/src/server/connection.rs index db594fbcd..1b005ea5e 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -2142,6 +2142,12 @@ impl Connection { }); } } + + // Send display changed message. + // For compatibility with old versions ( < 1.2.4 ). + if let Some(msg_out) = video_service::make_display_changed_msg(self.display_idx, None) { + self.send(msg_out).await; + } } } diff --git a/src/server/display_service.rs b/src/server/display_service.rs index eb9b4272b..d1d14f0f9 100644 --- a/src/server/display_service.rs +++ b/src/server/display_service.rs @@ -242,6 +242,10 @@ pub(super) fn get_sync_displays() -> Vec { SYNC_DISPLAYS.lock().unwrap().displays.clone() } +pub(super) fn get_display_info(idx: usize) -> Option { + SYNC_DISPLAYS.lock().unwrap().displays.get(idx).cloned() +} + // Display to DisplayInfo // The DisplayInfo is be sent to the peer. pub(super) fn check_update_displays(all: &Vec) { diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 664ca6628..0e1c3cb23 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -20,7 +20,12 @@ #[cfg(target_os = "linux")] use super::display_service::IS_X11; -use super::{display_service::check_display_changed, service::ServiceTmpl, video_qos::VideoQoS, *}; +use super::{ + display_service::{check_display_changed, get_display_info}, + service::ServiceTmpl, + video_qos::VideoQoS, + *, +}; #[cfg(target_os = "linux")] use crate::common::SimpleCallOnReturn; #[cfg(windows)] @@ -511,7 +516,7 @@ fn run(vs: VideoService) -> ResultType<()> { (c.origin.0, c.origin.1, c.width, c.height), ) { log::info!("Display {} changed", display); - broadcast_display_changed(display_idx, &sp, &c.name, display); + broadcast_display_changed(display_idx, &sp, display); bail!("SWITCH"); } } @@ -596,7 +601,7 @@ fn run(vs: VideoService) -> ResultType<()> { (c.origin.0, c.origin.1, c.width, c.height), ) { log::info!("Display {} changed", display); - broadcast_display_changed(display_idx, &sp, &c.name, display); + broadcast_display_changed(display_idx, &sp, display); bail!("SWITCH"); } @@ -853,22 +858,20 @@ fn get_wake_lock() -> crate::platform::WakeLock { } #[inline] -fn broadcast_display_changed( - display_idx: usize, - sp: &GenericService, - name: &str, - display: DisplayInfo, -) { - if let Some(msg_out) = make_display_changed_msg(display_idx, name, display) { +fn broadcast_display_changed(display_idx: usize, sp: &GenericService, display: DisplayInfo) { + if let Some(msg_out) = make_display_changed_msg(display_idx, Some(display)) { sp.send(msg_out); } } -fn make_display_changed_msg( +pub fn make_display_changed_msg( display_idx: usize, - name: &str, - display: DisplayInfo, + opt_display: Option, ) -> Option { + let display = match opt_display { + Some(d) => d, + None => get_display_info(display_idx)?, + }; let mut misc = Misc::new(); misc.set_switch_display(SwitchDisplay { display: display_idx as _, @@ -879,10 +882,10 @@ fn make_display_changed_msg( cursor_embedded: display_service::capture_cursor_embedded(), #[cfg(not(any(target_os = "android", target_os = "ios")))] resolutions: Some(SupportedResolutions { - resolutions: if name.is_empty() { + resolutions: if display.name.is_empty() { vec![] } else { - crate::platform::resolutions(name) + crate::platform::resolutions(&display.name) }, ..SupportedResolutions::default() }) From 4d537b2a9ad8d57b670cdb7f9af6df4052a7a346 Mon Sep 17 00:00:00 2001 From: dignow Date: Wed, 18 Oct 2023 11:35:28 +0800 Subject: [PATCH 034/114] fix/change_display_resolution, send change resolution message Signed-off-by: dignow --- src/server/display_service.rs | 4 +++- src/server/video_service.rs | 42 ++++++++++++++++------------------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/server/display_service.rs b/src/server/display_service.rs index d1d14f0f9..780833f78 100644 --- a/src/server/display_service.rs +++ b/src/server/display_service.rs @@ -60,7 +60,9 @@ impl SyncDisplaysInfo { } // This function is really useful, though a duplicate check if display changed. -// Because the video server will send the supported resolutions of the {idx} display to the subscribers. +// The video server will then send the following messages to the client: +// 1. the supported resolutions of the {idx} display +// 2. the switch resolution message, so that the client can record the custom resolution. pub(super) fn check_display_changed( ndisplay: usize, idx: usize, diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 0e1c3cb23..5b7496015 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -298,7 +298,6 @@ fn check_uac_switch(privacy_mode_id: i32, capturer_privacy_mode_id: i32) -> Resu } pub(super) struct CapturerInfo { - pub name: String, pub origin: (i32, i32), pub width: usize, pub height: usize, @@ -390,7 +389,6 @@ fn get_capturer( portable_service_running, )?; Ok(CapturerInfo { - name, origin, width, height, @@ -489,6 +487,7 @@ fn run(vs: VideoService) -> ResultType<()> { drop(video_qos); if sp.is_option_true(OPTION_REFRESH) { + let _ = try_broadcast_display_changed(&sp, display_idx, &c); bail!("SWITCH"); } if codec_name != Encoder::negotiated_codec() { @@ -510,15 +509,7 @@ fn run(vs: VideoService) -> ResultType<()> { let now = time::Instant::now(); if last_check_displays.elapsed().as_millis() > 1000 { last_check_displays = now; - if let Some(display) = check_display_changed( - c.ndisplay, - c.current, - (c.origin.0, c.origin.1, c.width, c.height), - ) { - log::info!("Display {} changed", display); - broadcast_display_changed(display_idx, &sp, display); - bail!("SWITCH"); - } + try_broadcast_display_changed(&sp, display_idx, &c)?; } frame_controller.reset(); @@ -595,15 +586,7 @@ fn run(vs: VideoService) -> ResultType<()> { } } Err(err) => { - if let Some(display) = check_display_changed( - c.ndisplay, - c.current, - (c.origin.0, c.origin.1, c.width, c.height), - ) { - log::info!("Display {} changed", display); - broadcast_display_changed(display_idx, &sp, display); - bail!("SWITCH"); - } + try_broadcast_display_changed(&sp, display_idx, &c)?; #[cfg(windows)] if !c.is_gdi() { @@ -858,10 +841,23 @@ fn get_wake_lock() -> crate::platform::WakeLock { } #[inline] -fn broadcast_display_changed(display_idx: usize, sp: &GenericService, display: DisplayInfo) { - if let Some(msg_out) = make_display_changed_msg(display_idx, Some(display)) { - sp.send(msg_out); +fn try_broadcast_display_changed( + sp: &GenericService, + display_idx: usize, + cap: &CapturerInfo, +) -> ResultType<()> { + if let Some(display) = check_display_changed( + cap.ndisplay, + cap.current, + (cap.origin.0, cap.origin.1, cap.width, cap.height), + ) { + log::info!("Display {} changed", display); + if let Some(msg_out) = make_display_changed_msg(display_idx, Some(display)) { + sp.send(msg_out); + bail!("SWITCH"); + } } + Ok(()) } pub fn make_display_changed_msg( From b55c916e7719e88ba05d344218951d09d1844a6e Mon Sep 17 00:00:00 2001 From: dignow Date: Wed, 18 Oct 2023 11:39:05 +0800 Subject: [PATCH 035/114] add comments Signed-off-by: dignow --- src/server/video_service.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 5b7496015..074b041c9 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -509,6 +509,8 @@ fn run(vs: VideoService) -> ResultType<()> { let now = time::Instant::now(); if last_check_displays.elapsed().as_millis() > 1000 { last_check_displays = now; + // This check may be redundant, but it is better to be safe. + // The previous check in `sp.is_option_true(OPTION_REFRESH)` block may be enough. try_broadcast_display_changed(&sp, display_idx, &c)?; } @@ -586,6 +588,8 @@ fn run(vs: VideoService) -> ResultType<()> { } } Err(err) => { + // This check may be redundant, but it is better to be safe. + // The previous check in `sp.is_option_true(OPTION_REFRESH)` block may be enough. try_broadcast_display_changed(&sp, display_idx, &c)?; #[cfg(windows)] From ed28928c8437284fa5300851bdb5096cd93f61e2 Mon Sep 17 00:00:00 2001 From: dignow Date: Wed, 18 Oct 2023 12:06:55 +0800 Subject: [PATCH 036/114] fix build linux Signed-off-by: dignow --- src/server/wayland.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/server/wayland.rs b/src/server/wayland.rs index 02e83fdc2..38edc4472 100644 --- a/src/server/wayland.rs +++ b/src/server/wayland.rs @@ -271,9 +271,6 @@ pub(super) fn get_capturer() -> ResultType { let cap_display_info = &*cap_display_info; let rect = cap_display_info.rects[cap_display_info.current]; Ok(super::video_service::CapturerInfo { - name: cap_display_info.displays[cap_display_info.current] - .name - .clone(), origin: rect.0, width: rect.1, height: rect.2, From 997c36860459ba3e20252be96aa1070dab50b9b8 Mon Sep 17 00:00:00 2001 From: "xalt7x.service" Date: Wed, 18 Oct 2023 07:09:56 +0300 Subject: [PATCH 037/114] Update Ukrainian translation --- src/lang/ua.rs | 106 ++++++++++++++++++++++++------------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 7bdea72d6..02c4e2349 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -138,7 +138,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Please try later", "Будь ласка, спробуйте пізніше"), ("Remote desktop is offline", "Віддалена стільниця не в мережі"), ("Key mismatch", "Невідповідність ключів"), - ("Timeout", "Тайм-аут"), + ("Timeout", "Час очікування"), ("Failed to connect to relay server", "Не вдалося підключитися до сервера реле"), ("Failed to connect via rendezvous server", "Не вдалося підключитися через проміжний сервер"), ("Failed to connect via relay server", "Не вдалося підключитися через сервер реле"), @@ -223,7 +223,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Verification code", "Код підтвердження"), ("verification_tip", "Виявлено новий пристрій, код підтвердження надіслано на зареєстровану email-адресу, введіть код підтвердження для продовження авторизації."), ("Logout", "Вийти"), - ("Tags", "Ключові слова"), + ("Tags", "Теги"), ("Search ID", "Пошук за ID"), ("whitelist_sep", "Розділені комою, крапкою з комою, пробілом або новим рядком"), ("Add ID", "Додати ID"), @@ -231,7 +231,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Unselect all tags", "Скасувати вибір усіх тегів"), ("Network error", "Помилка мережі"), ("Username missed", "Імʼя користувача відсутнє"), - ("Password missed", "Забули пароль"), + ("Password missed", "Пароль відсутній"), ("Wrong credentials", "Неправильні дані"), ("The verification code is incorrect or has expired", "Код підтвердження некоректний або протермінований"), ("Edit Tag", "Редагувати тег"), @@ -269,7 +269,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Reset canvas", "Відновлення полотна"), ("No permission of file transfer", "Немає дозволу на передачу файлів"), ("Note", "Примітка"), - ("Connection", "Зʼєднання"), + ("Connection", "Підключення"), ("Share Screen", "Поділитися екраном"), ("Chat", "Чат"), ("Total", "Всього"), @@ -516,54 +516,54 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Exit", "Вийти"), ("Open", "Відкрити"), ("logout_tip", "Ви впевнені, що хочете вилогуватися?"), - ("Service", ""), - ("Start", ""), - ("Stop", ""), - ("exceed_max_devices", ""), - ("Sync with recent sessions", ""), - ("Sort tags", ""), - ("Open connection in new tab", ""), - ("Move tab to new window", ""), - ("Can not be empty", ""), - ("Already exists", ""), - ("Change Password", ""), - ("Refresh Password", ""), - ("ID", ""), - ("Grid View", ""), - ("List View", ""), - ("Select", ""), - ("Toggle Tags", ""), - ("pull_ab_failed_tip", ""), - ("push_ab_failed_tip", ""), - ("synced_peer_readded_tip", ""), - ("Change Color", ""), - ("Primary Color", ""), - ("HSV Color", ""), - ("Installation Successful!", ""), - ("Installation failed!", ""), - ("Reverse mouse wheel", ""), - ("{} sessions", ""), - ("scam_title", ""), - ("scam_text1", ""), - ("scam_text2", ""), - ("Don't show again", ""), - ("I Agree", ""), - ("Decline", ""), - ("Timeout in minutes", ""), - ("auto_disconnect_option_tip", ""), - ("Connection failed due to inactivity", ""), - ("Check for software update on startup", ""), - ("upgrade_rustdesk_server_pro_to_{}_tip", ""), - ("pull_group_failed_tip", ""), - ("Filter by intersection", ""), - ("Remove wallpaper during incoming sessions", ""), - ("Test", ""), - ("switch_display_elevated_connections_tip", ""), - ("display_is_plugged_out_msg", ""), - ("No displays", ""), - ("elevated_switch_display_msg", ""), - ("Open in new window", ""), - ("Show displays as individual windows", ""), - ("Use all my displays for the remote session", ""), + ("Service", "Служба"), + ("Start", "Запустити"), + ("Stop", "Зупинити"), + ("exceed_max_devices", "У вас максимальна кількість керованих пристроїв."), + ("Sync with recent sessions", "Синхронізація з нещодавніми сеансами"), + ("Sort tags", "Сортувати теги"), + ("Open connection in new tab", "Відкрити підключення в новій вкладці"), + ("Move tab to new window", "Перемістити вкладку до нового вікна"), + ("Can not be empty", "Не може бути порожнім"), + ("Already exists", "Вже існує"), + ("Change Password", "Змінити пароль"), + ("Refresh Password", "Оновити пароль"), + ("ID", "ID"), + ("Grid View", "Перегляд ґраткою"), + ("List View", "Перегляд списком"), + ("Select", "Вибрати"), + ("Toggle Tags", "Видимість тегів"), + ("pull_ab_failed_tip", "Не вдалося оновити адресну книгу"), + ("push_ab_failed_tip", "Не вдалося синхронізувати адресну книгу"), + ("synced_peer_readded_tip", "Пристрої з нещодавніх сеансів будуть синхронізовані з адресною книгою"), + ("Change Color", "Змінити колір"), + ("Primary Color", "Основний колір"), + ("HSV Color", "Колір HSV"), + ("Installation Successful!", "Успішне встановлення!"), + ("Installation failed!", "Невдале встановлення!"), + ("Reverse mouse wheel", "Зворотній напрям прокрутки"), + ("{} sessions", "{} сеансів"), + ("scam_title", "Вас можуть ОБМАНУТИ!"), + ("scam_text1", "Якщо ви розмовляєте по телефону з кимось, кого НЕ ЗНАЄТЕ чи кому НЕ ДОВІРЯЄТЕ, і ця особа хоче, щоб ви використали RustDesk та запустили службу, не робіть цього та негайно завершіть дзвінок."), + ("scam_text2", "Ймовірно, ви маєте справу з шахраєм, що намагається викрасти ваші гроші чи особисті дані."), + ("Don't show again", "Не показувати знову"), + ("I Agree", "Я погоджуюсь"), + ("Decline", "Я не погоджуюсь"), + ("Timeout in minutes", "Час очікування в хвилинах"), + ("auto_disconnect_option_tip", "Автоматично завершувати вхідні сеанси в разі неактивності користувача"), + ("Connection failed due to inactivity", "Автоматично відключено через неактивність"), + ("Check for software update on startup", "Перевіряти оновлення під час запуску"), + ("upgrade_rustdesk_server_pro_to_{}_tip", "Будь ласка, оновіть RustDesk Server Pro до версії {} чи новіше!"), + ("pull_group_failed_tip", "Не вдалося оновити групу"), + ("Filter by intersection", "Фільтр за збігом"), + ("Remove wallpaper during incoming sessions", "Прибирати шпалеру під час вхідних сеансів"), + ("Test", "Тест"), + ("switch_display_elevated_connections_tip", "В режимі розширених прав, коли є декілька підключень, не підтримується перемикання на неосновний дисплей. Якщо вам потрібен контроль декількох дисплеїв, будь ласка, спробуйте ще раз після встановлення"), + ("display_is_plugged_out_msg", "Дисплей відключено, перемкніться на перший дисплей"), + ("No displays", "Відсутні дисплеї"), + ("elevated_switch_display_msg", "Перемкніться на основний дисплей, оскільки в режимі розширених прав одночасне використання декілька дисплеїв не підтримуються."), + ("Open in new window", "Відкрити в новому вікні"), + ("Show displays as individual windows", "Відображати дисплеї в якості окремих вікон"), + ("Use all my displays for the remote session", "Використовувати всі мої дисплеї для віддаленого сеансу"), ].iter().cloned().collect(); } From 749241f4e54eeb118e2e8852d823f9e0fdda96e0 Mon Sep 17 00:00:00 2001 From: "xalt7x.service" Date: Wed, 18 Oct 2023 07:13:48 +0300 Subject: [PATCH 038/114] Fix typos regarding displays --- src/lang/en.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/en.rs b/src/lang/en.rs index e2495780e..56dc8a122 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -223,7 +223,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_group_failed_tip", "Failed to refresh group"), ("doc_fix_wayland", "https://rustdesk.com/docs/en/manual/linux/#x11-required"), ("switch_display_elevated_connections_tip", "Switching to non-primary display is not supported in the elevated mode when there are multiple connections. Please try again after installation if you want to control multiple displays."), - ("display_is_plugged_out_msg", "The diplay is plugged out, switch to the first display."), - ("elevated_switch_display_msg", "Switch to the primary display because multiple display is not supported in elevated mode."), + ("display_is_plugged_out_msg", "The display is plugged out, switch to the first display."), + ("elevated_switch_display_msg", "Switch to the primary display because multiple displays are not supported in elevated mode."), ].iter().cloned().collect(); } From c61fa71a7066e4320ef8f0c73b3188f3223961f0 Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 7 Aug 2023 13:31:11 +0800 Subject: [PATCH 039/114] Revert "hide recording button if using av1" This reverts commit c2023e8ca3d857180269dd05df984a684c81b4b1. --- .../lib/desktop/widgets/remote_toolbar.dart | 24 ++++++------------- libs/scrap/src/common/record.rs | 3 --- src/ui/header.tis | 2 +- src/ui/remote.tis | 1 - 4 files changed, 8 insertions(+), 22 deletions(-) diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 88638f0b1..240add919 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -478,7 +478,7 @@ class _RemoteToolbarState extends State { toolbarItems.add(_ChatMenu(id: widget.id, ffi: widget.ffi)); toolbarItems.add(_VoiceCallMenu(id: widget.id, ffi: widget.ffi)); } - toolbarItems.add(_RecordMenu(ffi: widget.ffi)); + toolbarItems.add(_RecordMenu()); toolbarItems.add(_CloseMenu(id: widget.id, ffi: widget.ffi)); return Column( mainAxisSize: MainAxisSize.min, @@ -1370,12 +1370,11 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { } for (final r in resolutions) { - if (r.width == _localResolution!.width && - r.height == _localResolution!.height) { + if (r.width == _localResolution!.width && r.height == _localResolution!.height) { return r; } } - + return null; } @@ -1646,17 +1645,16 @@ class _VoiceCallMenu extends StatelessWidget { } class _RecordMenu extends StatelessWidget { - final FFI ffi; - const _RecordMenu({Key? key, required this.ffi}) : super(key: key); + const _RecordMenu({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - var ffiModel = Provider.of(context); + var ffi = Provider.of(context); var recordingModel = Provider.of(context); final visible = - recordingModel.start || ffiModel.permissions['recording'] != false; + recordingModel.start || ffi.permissions['recording'] != false; if (!visible) return Offstage(); - final menuButton = _IconMenuButton( + return _IconMenuButton( assetName: 'assets/rec.svg', tooltip: recordingModel.start ? 'Stop session recording' @@ -1669,14 +1667,6 @@ class _RecordMenu extends StatelessWidget { ? _ToolbarTheme.hoverRedColor : _ToolbarTheme.hoverBlueColor, ); - return ChangeNotifierProvider.value( - value: ffi.qualityMonitorModel, - child: Consumer( - builder: (context, model, child) => Offstage( - // If already started, AV1->Hidden/Stop, Other->Start, same as actual - offstage: model.data.codecFormat == 'AV1', - child: menuButton, - ))); } } diff --git a/libs/scrap/src/common/record.rs b/libs/scrap/src/common/record.rs index 2893cbf18..9de70ae14 100644 --- a/libs/scrap/src/common/record.rs +++ b/libs/scrap/src/common/record.rs @@ -101,9 +101,6 @@ impl DerefMut for Recorder { impl Recorder { pub fn new(mut ctx: RecorderContext) -> ResultType { - if ctx.format == CodecFormat::AV1 { - bail!("not support av1 recording"); - } ctx.set_filename()?; let recorder = match ctx.format { CodecFormat::VP8 | CodecFormat::VP9 => Recorder { diff --git a/src/ui/header.tis b/src/ui/header.tis index a6cb2645d..838514234 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -144,7 +144,7 @@ class Header: Reactor.Component { {svg_action} {svg_display} {svg_keyboard} - {recording_enabled && qualityMonitorData[4] != "AV1" ? {recording ? svg_recording_on : svg_recording_off} : ""} + {recording_enabled ? {recording ? svg_recording_on : svg_recording_off} : ""} {this.renderKeyboardPop()} {this.renderDisplayPop()} {this.renderActionPop()} diff --git a/src/ui/remote.tis b/src/ui/remote.tis index 022d43668..a99cd188b 100644 --- a/src/ui/remote.tis +++ b/src/ui/remote.tis @@ -522,7 +522,6 @@ handler.updateQualityStatus = function(speed, fps, delay, bitrate, codec_format) bitrate ? qualityMonitorData[3] = bitrate:null; codec_format ? qualityMonitorData[4] = codec_format:null; qualityMonitor.update(); - if (codec_format) header.update(); } handler.setPermission = function(name, enabled) { From 5d95d61aefe8f94e6805b0980866ff5c558205be Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Wed, 18 Oct 2023 14:40:29 +0530 Subject: [PATCH 040/114] remove fav peers from search Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 604cd3f93..a19a70c99 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -271,8 +271,7 @@ class _ConnectionPageState extends State peer.id.toLowerCase().contains(textEditingValue.text.toLowerCase()) || peer.username.toLowerCase().contains(textEditingValue.text.toLowerCase()) || peer.hostname.toLowerCase().contains(textEditingValue.text.toLowerCase()) || - peer.alias.toLowerCase().contains(textEditingValue.text.toLowerCase()) || - peer.platform.toLowerCase().contains(textEditingValue.text.toLowerCase())) + peer.alias.toLowerCase().contains(textEditingValue.text.toLowerCase())) .toList(); } }, From 05c789ae5076484b11aad6dac26e68bff3926720 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Wed, 18 Oct 2023 16:00:50 +0530 Subject: [PATCH 041/114] remove fav peers from search Signed-off-by: Sahil Yeole --- .../lib/desktop/pages/connection_page.dart | 2 - src/flutter_ffi.rs | 47 ------------------- 2 files changed, 49 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index a19a70c99..40cb4100f 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -160,7 +160,6 @@ class _ConnectionPageState extends State Future _getAllPeers() async { Map recentPeers = jsonDecode(await bind.mainLoadRecentPeersSync()); - Map favPeers = jsonDecode(await bind.mainLoadFavPeersSync()); Map lanPeers = jsonDecode(await bind.mainLoadLanPeersSync()); Map abPeers = jsonDecode(await bind.mainLoadAbSync()); Map groupPeers = jsonDecode(await bind.mainLoadGroupSync()); @@ -194,7 +193,6 @@ class _ConnectionPageState extends State } mergePeers(recentPeers); - mergePeers(favPeers); mergePeers(lanPeers); mergePeers(abPeers); mergePeers(groupPeers); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 2a714d949..4636bca08 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -886,53 +886,6 @@ pub fn main_load_recent_peers_sync() -> SyncReturn { SyncReturn("".to_string()) } -pub fn main_load_fav_peers_sync() -> SyncReturn { - if !config::APP_DIR.read().unwrap().is_empty() { - let favs = get_fav(); - let mut recent = PeerConfig::peers(None); - let mut lan = config::LanPeers::load() - .peers - .iter() - .filter(|d| recent.iter().all(|r| r.0 != d.id)) - .map(|d| { - ( - d.id.clone(), - SystemTime::UNIX_EPOCH, - PeerConfig { - info: PeerInfoSerde { - username: d.username.clone(), - hostname: d.hostname.clone(), - platform: d.platform.clone(), - }, - ..Default::default() - }, - ) - }) - .collect(); - recent.append(&mut lan); - let peers: Vec> = recent - .into_iter() - .filter_map(|(id, _, p)| { - if favs.contains(&id) { - Some(peer_to_map(id, p)) - } else { - None - } - }) - .collect(); - - let data = HashMap::from([ - ("name", "load_fav_peers".to_owned()), - ( - "peers", - serde_json::ser::to_string(&peers).unwrap_or("".to_owned()), - ), - ]); - return SyncReturn(serde_json::ser::to_string(&data).unwrap_or("".to_owned())); - } - SyncReturn("".to_string()) -} - pub fn main_load_lan_peers_sync() -> SyncReturn { let data = HashMap::from([ ("name", "load_lan_peers".to_owned()), From 510cffb305f17088059744696e21d662415fa8dd Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 7 Aug 2023 15:18:34 +0800 Subject: [PATCH 042/114] av1 record, set zero codec private Signed-off-by: 21pages --- Cargo.lock | 10 ++++------ libs/scrap/Cargo.toml | 2 +- libs/scrap/src/common/record.rs | 29 +++++++++++++++++++++++++---- src/server/video_service.rs | 6 ++---- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 519476e93..b606cdb21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6712,18 +6712,16 @@ dependencies = [ [[package]] name = "webm" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb047148a12ef1fd8ab26302bca7e82036f005c3073b48e17cc1b44ec577136" +version = "1.1.0" +source = "git+https://github.com/21pages/rust-webm#d2c4d3ac133c7b0e4c0f656da710b48391981e64" dependencies = [ "webm-sys", ] [[package]] name = "webm-sys" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ded6ec82ccf51fe265b0b2b1579cac839574ed910c17baac58e807f8a9de7f3" +version = "1.0.4" +source = "git+https://github.com/21pages/rust-webm#d2c4d3ac133c7b0e4c0f656da710b48391981e64" dependencies = [ "cc", ] diff --git a/libs/scrap/Cargo.toml b/libs/scrap/Cargo.toml index 4956403a9..d8b176597 100644 --- a/libs/scrap/Cargo.toml +++ b/libs/scrap/Cargo.toml @@ -19,7 +19,7 @@ cfg-if = "1.0" num_cpus = "1.15" lazy_static = "1.4" hbb_common = { path = "../hbb_common" } -webm = "1.0" +webm = { git = "https://github.com/21pages/rust-webm" } [dependencies.winapi] version = "0.3" diff --git a/libs/scrap/src/common/record.rs b/libs/scrap/src/common/record.rs index 9de70ae14..09d5efd3f 100644 --- a/libs/scrap/src/common/record.rs +++ b/libs/scrap/src/common/record.rs @@ -51,7 +51,10 @@ impl RecorderContext { + &self.id.clone() + &chrono::Local::now().format("_%Y%m%d%H%M%S_").to_string() + &self.format.to_string() - + if self.format == CodecFormat::VP9 || self.format == CodecFormat::VP8 { + + if self.format == CodecFormat::VP9 + || self.format == CodecFormat::VP8 + || self.format == CodecFormat::AV1 + { ".webm" } else { ".mp4" @@ -103,7 +106,7 @@ impl Recorder { pub fn new(mut ctx: RecorderContext) -> ResultType { ctx.set_filename()?; let recorder = match ctx.format { - CodecFormat::VP8 | CodecFormat::VP9 => Recorder { + CodecFormat::VP8 | CodecFormat::VP9 | CodecFormat::AV1 => Recorder { inner: Box::new(WebmRecorder::new(ctx.clone())?), ctx, }, @@ -122,7 +125,9 @@ impl Recorder { fn change(&mut self, mut ctx: RecorderContext) -> ResultType<()> { ctx.set_filename()?; self.inner = match ctx.format { - CodecFormat::VP8 | CodecFormat::VP9 => Box::new(WebmRecorder::new(ctx.clone())?), + CodecFormat::VP8 | CodecFormat::VP9 | CodecFormat::AV1 => { + Box::new(WebmRecorder::new(ctx.clone())?) + } #[cfg(feature = "hwcodec")] _ => Box::new(HwRecorder::new(ctx.clone())?), #[cfg(not(feature = "hwcodec"))] @@ -161,6 +166,15 @@ impl Recorder { } vp9s.frames.iter().map(|f| self.write_video(f)).count(); } + video_frame::Union::Av1s(av1s) => { + if self.ctx.format != CodecFormat::AV1 { + self.change(RecorderContext { + format: CodecFormat::AV1, + ..self.ctx.clone() + })?; + } + av1s.frames.iter().map(|f| self.write_video(f)).count(); + } #[cfg(feature = "hwcodec")] video_frame::Union::H264s(h264s) => { if self.ctx.format != CodecFormat::H264 { @@ -227,10 +241,17 @@ impl RecorderApi for WebmRecorder { None, if ctx.format == CodecFormat::VP9 { mux::VideoCodecId::VP9 - } else { + } else if ctx.format == CodecFormat::VP8 { mux::VideoCodecId::VP8 + } else { + mux::VideoCodecId::AV1 }, ); + if ctx.format == CodecFormat::AV1 { + // [129, 8, 12, 0] in 3.6.0, but zero works + let codec_private = vec![0, 0, 0, 0]; + webm.set_codec_private(vt.track_number(), &codec_private); + } Ok(WebmRecorder { vt, webm: Some(webm), diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 074b041c9..c2a9b6113 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -436,8 +436,7 @@ fn run(vs: VideoService) -> ResultType<()> { log::info!("init quality={:?}, abr enabled:{}", quality, abr); let codec_name = Encoder::negotiated_codec(); let recorder = get_recorder(c.width, c.height, &codec_name); - let last_recording = - (recorder.lock().unwrap().is_some() || video_qos.record()) && codec_name != CodecName::AV1; + let last_recording = recorder.lock().unwrap().is_some() || video_qos.record(); drop(video_qos); let encoder_cfg = get_encoder_config(&c, quality, last_recording); @@ -479,8 +478,7 @@ fn run(vs: VideoService) -> ResultType<()> { allow_err!(encoder.set_quality(quality)); video_qos.store_bitrate(encoder.bitrate()); } - let recording = (recorder.lock().unwrap().is_some() || video_qos.record()) - && codec_name != CodecName::AV1; + let recording = recorder.lock().unwrap().is_some() || video_qos.record(); if recording != last_recording { bail!("SWITCH"); } From fe3924b432032033d71f666f97177d7c4cc4dbe5 Mon Sep 17 00:00:00 2001 From: dignow Date: Wed, 18 Oct 2023 20:50:20 +0800 Subject: [PATCH 043/114] try stop video capturing, on close window Signed-off-by: dignow --- src/flutter.rs | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/flutter.rs b/src/flutter.rs index a9cd98149..9d304af8b 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -1377,6 +1377,9 @@ pub fn get_cur_session() -> Option { // sessions mod is used to avoid the big lock of sessions' map. pub mod sessions { + #[cfg(feature = "flutter_texture_render")] + use std::collections::HashSet; + use super::*; lazy_static::lazy_static! { @@ -1441,12 +1444,44 @@ pub mod sessions { let mut remove_peer_key = None; for (peer_key, s) in SESSIONS.write().unwrap().iter_mut() { let mut write_lock = s.ui_handler.session_handlers.write().unwrap(); - if write_lock.remove(id).is_some() { + let remove_ret = write_lock.remove(id); + #[cfg(not(feature = "flutter_texture_render"))] + if remove_ret.is_some() { if write_lock.is_empty() { remove_peer_key = Some(peer_key.clone()); } break; } + #[cfg(feature = "flutter_texture_render")] + match remove_ret { + Some(_) => { + if write_lock.is_empty() { + remove_peer_key = Some(peer_key.clone()); + } else { + // Set capture displays if some are not used any more. + let mut remains_displays = HashSet::new(); + for (_, h) in write_lock.iter() { + remains_displays.extend( + h.renderer + .map_display_sessions + .read() + .unwrap() + .keys() + .cloned(), + ); + } + if !remains_displays.is_empty() { + s.capture_displays( + vec![], + vec![], + remains_displays.iter().map(|d| *d as i32).collect(), + ); + } + } + break; + } + None => {} + } } SESSIONS.write().unwrap().remove(&remove_peer_key?) } From 9acddede65453fb3c9a6dbf5554cde8b3c816487 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Thu, 19 Oct 2023 04:29:51 +0530 Subject: [PATCH 044/114] fix remote home button Signed-off-by: Sahil Yeole --- flutter/lib/models/file_model.dart | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index 108c76f1e..9a9c0f491 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -375,8 +375,14 @@ class FileController { history.add(directory.value.path); } - void goToHomeDirectory() { - openDirectory(homePath); + void goToHomeDirectory() async { + if (isLocal) { + openDirectory(homePath); + return; + } + final homeDir = (await bind.sessionGetPeerOption( + sessionId: sessionId, name: "remote_home_dir")); + openDirectory(homeDir); } void goBack() { @@ -403,7 +409,7 @@ class FileController { } // TODO deprecated this - void initDirAndHome(Map evt) { + void initDirAndHome(Map evt) async { try { final fd = FileDirectory.fromJson(jsonDecode(evt['value'])); fd.format(options.value.isWindows, sort: sortBy.value); @@ -423,6 +429,14 @@ class FileController { } } else if (options.value.home.isEmpty) { options.value.home = fd.path; + + final homeDir = ( await bind.sessionGetPeerOption( + sessionId: sessionId, name: "remote_home_dir")); + + if (homeDir.isEmpty){ + bind.sessionPeerOption( + sessionId: sessionId, name: "remote_home_dir", value: fd.path); + } debugPrint("init remote home: ${fd.path}"); directory.value = fd; } From 80951a8e6ef9bdfbd8087486a11f0cc011f2d6ab Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 19 Oct 2023 07:50:59 +0800 Subject: [PATCH 045/114] open individual window, add offset Signed-off-by: dignow --- flutter/lib/common.dart | 26 +++++++++++++------ .../lib/desktop/pages/remote_tab_page.dart | 9 ++++--- flutter/lib/main.dart | 9 +++++-- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 545b8a238..9a22a8f89 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1673,8 +1673,10 @@ Future _adjustRestoreMainWindowOffset( /// Restore window position and size on start /// Note that windowId must be provided if it's subwindow +// +// display is used to set the offset of the window in individual display mode. Future restoreWindowPosition(WindowType type, - {int? windowId, String? peerId}) async { + {int? windowId, String? peerId, int? display}) async { if (bind .mainGetEnv(key: "DISABLE_RUSTDESK_RESTORE_WINDOW_POSITION") .isNotEmpty) { @@ -1710,14 +1712,22 @@ Future restoreWindowPosition(WindowType type, debugPrint("no window position saved, ignoring position restoration"); return false; } - if (type == WindowType.RemoteDesktop && - !isRemotePeerPos && - windowId != null) { - if (lpos.offsetWidth != null) { - lpos.offsetWidth = lpos.offsetWidth! + windowId * 20; + if (type == WindowType.RemoteDesktop) { + if (!isRemotePeerPos && windowId != null) { + if (lpos.offsetWidth != null) { + lpos.offsetWidth = lpos.offsetWidth! + windowId * 20; + } + if (lpos.offsetHeight != null) { + lpos.offsetHeight = lpos.offsetHeight! + windowId * 20; + } } - if (lpos.offsetHeight != null) { - lpos.offsetHeight = lpos.offsetHeight! + windowId * 20; + if (display != null) { + if (lpos.offsetWidth != null) { + lpos.offsetWidth = lpos.offsetWidth! + display * 30; + } + if (lpos.offsetHeight != null) { + lpos.offsetHeight = lpos.offsetHeight! + display * 30; + } } } diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index 6d28d967f..d785a9464 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -48,7 +48,8 @@ class _ConnectionTabPageState extends State { late ToolbarState _toolbarState; String? peerId; - bool isScreenRectSet = false; + bool _isScreenRectSet = false; + int? _display; var connectionMap = RxList.empty(growable: true); @@ -61,7 +62,8 @@ class _ConnectionTabPageState extends State { final display = params['display']; final displays = params['displays']; final screenRect = parseParamScreenRect(params); - isScreenRectSet = screenRect != null; + _isScreenRectSet = screenRect != null; + _display = display as int?; tryMoveToScreenAndSetFullscreen(screenRect); if (peerId != null) { ConnectionTypeState.init(peerId!); @@ -202,7 +204,7 @@ class _ConnectionTabPageState extends State { _update_remote_count(); return returnValue; }); - if (!isScreenRectSet) { + if (!_isScreenRectSet) { Future.delayed(Duration.zero, () { restoreWindowPosition( WindowType.RemoteDesktop, @@ -210,6 +212,7 @@ class _ConnectionTabPageState extends State { peerId: tabController.state.value.tabs.isEmpty ? null : tabController.state.value.tabs[0].key, + display: _display, ); }); } diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 59cf97345..83a633061 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -200,8 +200,13 @@ void runMultiWindow( case kAppTypeDesktopRemote: // If screen rect is set, the window will be moved to the target screen and then set fullscreen. if (argument['screen_rect'] == null) { - await restoreWindowPosition(WindowType.RemoteDesktop, - windowId: kWindowId!, peerId: argument['id'] as String?); + // int? display = argument['display'] as int?; + await restoreWindowPosition( + WindowType.RemoteDesktop, + windowId: kWindowId!, + peerId: argument['id'] as String?, + display: argument['display'] as int?, + ); } break; case kAppTypeDesktopFileTransfer: From 2e85d4b55afed3baff2948bb8914ca0c0004baef Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 19 Oct 2023 07:55:55 +0800 Subject: [PATCH 046/114] add comment Signed-off-by: dignow --- flutter/lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 83a633061..d7dd5acee 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -200,7 +200,7 @@ void runMultiWindow( case kAppTypeDesktopRemote: // If screen rect is set, the window will be moved to the target screen and then set fullscreen. if (argument['screen_rect'] == null) { - // int? display = argument['display'] as int?; + // display can be used to control the offset of the window. await restoreWindowPosition( WindowType.RemoteDesktop, windowId: kWindowId!, From 7a5bc864fa357c9b2729868ee525d5c56fdaf216 Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 18 Oct 2023 22:39:28 +0800 Subject: [PATCH 047/114] fix client side record Signed-off-by: 21pages --- flutter/lib/common/widgets/toolbar.dart | 5 +- flutter/lib/desktop/pages/remote_page.dart | 3 +- .../lib/desktop/widgets/remote_toolbar.dart | 8 +- flutter/lib/mobile/pages/remote_page.dart | 4 +- flutter/lib/models/model.dart | 79 +++++++++++-------- libs/scrap/src/common/record.rs | 48 ++++++++--- src/client.rs | 8 +- src/server/connection.rs | 3 +- src/ui/header.tis | 14 +++- src/ui/remote.rs | 6 ++ 10 files changed, 119 insertions(+), 59 deletions(-) diff --git a/flutter/lib/common/widgets/toolbar.dart b/flutter/lib/common/widgets/toolbar.dart index 757a03fec..28b10785b 100644 --- a/flutter/lib/common/widgets/toolbar.dart +++ b/flutter/lib/common/widgets/toolbar.dart @@ -224,11 +224,8 @@ List toolbarControls(BuildContext context, String id, FFI ffi) { )); } // record - var codecFormat = ffi.qualityMonitorModel.data.codecFormat; if (!isDesktop && - (ffi.recordingModel.start || - (perms["recording"] != false && - (codecFormat == "VP8" || codecFormat == "VP9")))) { + (ffi.recordingModel.start || (perms["recording"] != false))) { v.add(TTextMenu( child: Row( children: [ diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index abbb8785d..cb9cf49c9 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -677,7 +677,8 @@ class _ImagePaintState extends State { } else { final key = cache.updateGetKey(scale); if (!cursor.cachedKeys.contains(key)) { - debugPrint("Register custom cursor with key $key (${cache.hotx},${cache.hoty})"); + debugPrint( + "Register custom cursor with key $key (${cache.hotx},${cache.hoty})"); // [Safety] // It's ok to call async registerCursor in current synchronous context, // because activating the cursor is also an async call and will always diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 240add919..fd4fcc434 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -1370,11 +1370,12 @@ class _ResolutionsMenuState extends State<_ResolutionsMenu> { } for (final r in resolutions) { - if (r.width == _localResolution!.width && r.height == _localResolution!.height) { + if (r.width == _localResolution!.width && + r.height == _localResolution!.height) { return r; } } - + return null; } @@ -1652,7 +1653,8 @@ class _RecordMenu extends StatelessWidget { var ffi = Provider.of(context); var recordingModel = Provider.of(context); final visible = - recordingModel.start || ffi.permissions['recording'] != false; + (recordingModel.start || ffi.permissions['recording'] != false) && + ffi.pi.currentDisplay != kAllDisplayValue; if (!visible) return Offstage(); return _IconMenuButton( assetName: 'assets/rec.svg', diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 249355012..ff71c9347 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -763,7 +763,9 @@ void showOptions( children.add(InkWell( onTap: () { if (i == cur) return; - bind.sessionSwitchDisplay(sessionId: gFFI.sessionId, value: Int32List.fromList([i])); + gFFI.recordingModel.onClose(); + bind.sessionSwitchDisplay( + sessionId: gFFI.sessionId, value: Int32List.fromList([i])); gFFI.dialogManager.dismissAll(); }, child: Ink( diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index ce4cbe523..433d3c2d4 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -860,6 +860,8 @@ class FfiModel with ChangeNotifier { // Directly switch to the new display without waiting for the response. 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. + parent.target?.recordingModel.onClose(); // no need to wait for the response pi.currentDisplay = display; updateCurDisplay(sessionId); @@ -868,7 +870,6 @@ class FfiModel with ChangeNotifier { } catch (e) { // } - parent.target?.recordingModel.onSwitchDisplay(); } updateBlockInputState(Map evt, String peerId) { @@ -1850,57 +1851,67 @@ class RecordingModel with ChangeNotifier { int? width = parent.target?.canvasModel.getDisplayWidth(); int? height = parent.target?.canvasModel.getDisplayHeight(); if (sessionId == null || width == null || height == null) return; - final currentDisplay = parent.target?.ffiModel.pi.currentDisplay; - if (currentDisplay != kAllDisplayValue) { - bind.sessionRecordScreen( - sessionId: sessionId, - start: true, - display: currentDisplay!, - width: width, - height: height); - } + final pi = parent.target?.ffiModel.pi; + if (pi == null) return; + final currentDisplay = pi.currentDisplay; + if (currentDisplay == kAllDisplayValue) return; + bind.sessionRecordScreen( + sessionId: sessionId, + start: true, + display: currentDisplay, + width: width, + height: height); } toggle() async { if (isIOS) return; final sessionId = parent.target?.sessionId; if (sessionId == null) return; + final pi = parent.target?.ffiModel.pi; + if (pi == null) return; + final currentDisplay = pi.currentDisplay; + if (currentDisplay == kAllDisplayValue) return; _start = !_start; notifyListeners(); - await bind.sessionRecordStatus(sessionId: sessionId, status: _start); + await _sendStatusMessage(sessionId, pi, _start); if (_start) { - final pi = parent.target?.ffiModel.pi; - if (pi != null) { - sessionRefreshVideo(sessionId, pi); + sessionRefreshVideo(sessionId, pi); + if (versionCmp(pi.version, '1.2.4') >= 0) { + // will not receive SwitchDisplay since 1.2.4 + onSwitchDisplay(); } } else { - final currentDisplay = parent.target?.ffiModel.pi.currentDisplay; - if (currentDisplay != kAllDisplayValue) { - bind.sessionRecordScreen( - sessionId: sessionId, - start: false, - display: currentDisplay!, - width: 0, - height: 0); - } - } - } - - onClose() { - if (isIOS) return; - final sessionId = parent.target?.sessionId; - if (sessionId == null) return; - _start = false; - final currentDisplay = parent.target?.ffiModel.pi.currentDisplay; - if (currentDisplay != kAllDisplayValue) { bind.sessionRecordScreen( sessionId: sessionId, start: false, - display: currentDisplay!, + display: currentDisplay, width: 0, height: 0); } } + + onClose() async { + if (isIOS) return; + final sessionId = parent.target?.sessionId; + if (sessionId == null) return; + if (!_start) return; + _start = false; + final pi = parent.target?.ffiModel.pi; + if (pi == null) return; + final currentDisplay = pi.currentDisplay; + if (currentDisplay == kAllDisplayValue) return; + await _sendStatusMessage(sessionId, pi, false); + bind.sessionRecordScreen( + sessionId: sessionId, + start: false, + display: currentDisplay, + width: 0, + height: 0); + } + + _sendStatusMessage(SessionID sessionId, PeerInfo pi, bool status) async { + await bind.sessionRecordStatus(sessionId: sessionId, status: status); + } } class ElevationModel with ChangeNotifier { diff --git a/libs/scrap/src/common/record.rs b/libs/scrap/src/common/record.rs index 09d5efd3f..3c0ee2a95 100644 --- a/libs/scrap/src/common/record.rs +++ b/libs/scrap/src/common/record.rs @@ -49,8 +49,8 @@ impl RecorderContext { } let file = if self.server { "s" } else { "c" }.to_string() + &self.id.clone() - + &chrono::Local::now().format("_%Y%m%d%H%M%S_").to_string() - + &self.format.to_string() + + &chrono::Local::now().format("_%Y%m%d%H%M%S%3f_").to_string() + + &self.format.to_string().to_lowercase() + if self.format == CodecFormat::VP9 || self.format == CodecFormat::VP8 || self.format == CodecFormat::AV1 @@ -86,6 +86,7 @@ pub enum RecordState { pub struct Recorder { pub inner: Box, ctx: RecorderContext, + pts: Option, } impl Deref for Recorder { @@ -109,11 +110,13 @@ impl Recorder { CodecFormat::VP8 | CodecFormat::VP9 | CodecFormat::AV1 => Recorder { inner: Box::new(WebmRecorder::new(ctx.clone())?), ctx, + pts: None, }, #[cfg(feature = "hwcodec")] _ => Recorder { inner: Box::new(HwRecorder::new(ctx.clone())?), ctx, + pts: None, }, #[cfg(not(feature = "hwcodec"))] _ => bail!("unsupported codec type"), @@ -134,6 +137,7 @@ impl Recorder { _ => bail!("unsupported codec type"), }; self.ctx = ctx; + self.pts = None; self.send_state(RecordState::NewFile(self.ctx.filename.clone())); Ok(()) } @@ -155,7 +159,10 @@ impl Recorder { ..self.ctx.clone() })?; } - vp8s.frames.iter().map(|f| self.write_video(f)).count(); + for f in vp8s.frames.iter() { + self.check_pts(f.pts)?; + self.write_video(f); + } } video_frame::Union::Vp9s(vp9s) => { if self.ctx.format != CodecFormat::VP9 { @@ -164,7 +171,10 @@ impl Recorder { ..self.ctx.clone() })?; } - vp9s.frames.iter().map(|f| self.write_video(f)).count(); + for f in vp9s.frames.iter() { + self.check_pts(f.pts)?; + self.write_video(f); + } } video_frame::Union::Av1s(av1s) => { if self.ctx.format != CodecFormat::AV1 { @@ -173,7 +183,10 @@ impl Recorder { ..self.ctx.clone() })?; } - av1s.frames.iter().map(|f| self.write_video(f)).count(); + for f in av1s.frames.iter() { + self.check_pts(f.pts)?; + self.write_video(f); + } } #[cfg(feature = "hwcodec")] video_frame::Union::H264s(h264s) => { @@ -183,8 +196,9 @@ impl Recorder { ..self.ctx.clone() })?; } - if self.ctx.format == CodecFormat::H264 { - h264s.frames.iter().map(|f| self.write_video(f)).count(); + for f in h264s.frames.iter() { + self.check_pts(f.pts)?; + self.write_video(f); } } #[cfg(feature = "hwcodec")] @@ -195,8 +209,9 @@ impl Recorder { ..self.ctx.clone() })?; } - if self.ctx.format == CodecFormat::H265 { - h265s.frames.iter().map(|f| self.write_video(f)).count(); + for f in h265s.frames.iter() { + self.check_pts(f.pts)?; + self.write_video(f); } } _ => bail!("unsupported frame type"), @@ -205,6 +220,17 @@ impl Recorder { Ok(()) } + fn check_pts(&mut self, pts: i64) -> ResultType<()> { + // https://stackoverflow.com/questions/76379101/how-to-create-one-playable-webm-file-from-two-different-video-tracks-with-same-c + let old_pts = self.pts; + self.pts = Some(pts); + if old_pts.clone().unwrap_or_default() > pts { + log::info!("pts {:?}->{}, change record filename", old_pts, pts); + self.change(self.ctx.clone())?; + } + Ok(()) + } + fn send_state(&self, state: RecordState) { self.ctx.tx.as_ref().map(|tx| tx.send(state)); } @@ -250,7 +276,9 @@ impl RecorderApi for WebmRecorder { if ctx.format == CodecFormat::AV1 { // [129, 8, 12, 0] in 3.6.0, but zero works let codec_private = vec![0, 0, 0, 0]; - webm.set_codec_private(vt.track_number(), &codec_private); + if !webm.set_codec_private(vt.track_number(), &codec_private) { + bail!("Failed to set codec private"); + } } Ok(WebmRecorder { vt, diff --git a/src/client.rs b/src/client.rs index da4559c99..5a3c35467 100644 --- a/src/client.rs +++ b/src/client.rs @@ -999,16 +999,19 @@ pub struct VideoHandler { pub rgb: ImageRgb, recorder: Arc>>, record: bool, + _display: usize, // useful for debug } impl VideoHandler { /// Create a new video handler. - pub fn new() -> Self { + pub fn new(_display: usize) -> Self { + log::info!("new video handler for display #{_display}"); VideoHandler { decoder: Decoder::new(), rgb: ImageRgb::new(ImageFormat::ARGB, crate::DST_STRIDE_RGBA), recorder: Default::default(), record: false, + _display, } } @@ -1900,7 +1903,7 @@ where if handler_controller_map.len() <= display { for _i in handler_controller_map.len()..=display { handler_controller_map.push(VideoHandlerController { - handler: VideoHandler::new(), + handler: VideoHandler::new(_i), count: 0, duration: std::time::Duration::ZERO, skip_beginning: 0, @@ -1960,6 +1963,7 @@ where } } MediaData::RecordScreen(start, display, w, h, id) => { + log::info!("record screen command: start:{start}, display:{display}"); if handler_controller_map.len() == 1 { // Compatible with the sciter version(single ui session). // For the sciter version, there're no multi-ui-sessions for one connection. diff --git a/src/server/connection.rs b/src/server/connection.rs index 1b005ea5e..86096288d 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -2104,7 +2104,7 @@ impl Connection { display, video_service::OPTION_REFRESH, super::service::SERVICE_OPTION_VALUE_TRUE, - ) + ); }); } @@ -2145,6 +2145,7 @@ impl Connection { // Send display changed message. // For compatibility with old versions ( < 1.2.4 ). + // sciter need it in new version if let Some(msg_out) = video_service::make_display_changed_msg(self.display_idx, None) { self.send(msg_out).await; } diff --git a/src/ui/header.tis b/src/ui/header.tis index 838514234..029dd2629 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -299,14 +299,22 @@ class Header: Reactor.Component { header.update(); handler.record_status(recording); // 0 is just a dummy value. It will be ignored by the handler. - if (recording) + if (recording) { handler.refresh_video(0); - else - handler.record_screen(false, 0, display_width, display_height); + if (handler.version_cmp(pi.version, '1.2.4') >= 0) handler.record_screen(recording, pi.current_display, display_width, display_height); + } + else { + handler.record_screen(recording, pi.current_display, display_width, display_height); + } } event click $(#screen) (_, me) { if (pi.current_display == me.index) return; + if (recording) { + recording = false; + handler.record_screen(false, pi.current_display, display_width, display_height); + handler.record_status(false); + } handler.switch_display(me.index); } diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 71ef8f84d..bb01ef9f4 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -243,6 +243,7 @@ impl InvokeUiSession for SciterHandler { pi_sciter.set_item("sas_enabled", pi.sas_enabled); pi_sciter.set_item("displays", Self::make_displays_array(&pi.displays)); pi_sciter.set_item("current_display", pi.current_display); + pi_sciter.set_item("version", pi.version.clone()); self.call("updatePi", &make_args!(pi_sciter)); } @@ -469,6 +470,7 @@ impl sciter::EventHandler for SciterSession { fn restart_remote_device(); fn request_voice_call(); fn close_voice_call(); + fn version_cmp(String, String); } } @@ -757,6 +759,10 @@ impl SciterSession { log::error!("Failed to spawn IP tunneling: {}", err); } } + + fn version_cmp(&self, v1: String, v2: String) -> i32 { + (hbb_common::get_version_number(&v1) - hbb_common::get_version_number(&v2)) as i32 + } } pub fn make_fd(id: i32, entries: &Vec, only_count: bool) -> Value { From fb12ba8a2b85fb04d264d85043a4be021293fd9a Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 19 Oct 2023 12:21:35 +0800 Subject: [PATCH 048/114] Change the offset depending on the platform Signed-off-by: dignow --- flutter/lib/common.dart | 8 ++++---- flutter/lib/consts.dart | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 9a22a8f89..c6b613475 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1715,18 +1715,18 @@ Future restoreWindowPosition(WindowType type, if (type == WindowType.RemoteDesktop) { if (!isRemotePeerPos && windowId != null) { if (lpos.offsetWidth != null) { - lpos.offsetWidth = lpos.offsetWidth! + windowId * 20; + lpos.offsetWidth = lpos.offsetWidth! + windowId * kNewWindowOffset; } if (lpos.offsetHeight != null) { - lpos.offsetHeight = lpos.offsetHeight! + windowId * 20; + lpos.offsetHeight = lpos.offsetHeight! + windowId * kNewWindowOffset; } } if (display != null) { if (lpos.offsetWidth != null) { - lpos.offsetWidth = lpos.offsetWidth! + display * 30; + lpos.offsetWidth = lpos.offsetWidth! + display * kNewWindowOffset; } if (lpos.offsetHeight != null) { - lpos.offsetHeight = lpos.offsetHeight! + display * 30; + lpos.offsetHeight = lpos.offsetHeight! + display * kNewWindowOffset; } } } diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index e4d777ccb..e3339c1ec 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -66,8 +66,10 @@ const int kWindowMainId = 0; const String kPointerEventKindTouch = "touch"; const String kPointerEventKindMouse = "mouse"; -const String kKeyShowDisplaysAsIndividualWindows = 'displays_as_individual_windows'; -const String kKeyUseAllMyDisplaysForTheRemoteSession = 'use_all_my_displays_for_the_remote_session'; +const String kKeyShowDisplaysAsIndividualWindows = + 'displays_as_individual_windows'; +const String kKeyUseAllMyDisplaysForTheRemoteSession = + 'use_all_my_displays_for_the_remote_session'; const String kKeyShowMonitorsToolbar = 'show_monitors_toolbar'; // the executable name of the portable version @@ -87,6 +89,14 @@ const int kDesktopMaxDisplaySize = 3840; const double kDesktopFileTransferRowHeight = 30.0; const double kDesktopFileTransferHeaderHeight = 25.0; +double kNewWindowOffset = Platform.isWindows + ? 56.0 + : Platform.isLinux + ? 50.0 + : Platform.isMacOS + ? 30.0 + : 50.0; + EdgeInsets get kDragToResizeAreaPadding => !kUseCompatibleUiMode && Platform.isLinux ? stateGlobal.fullscreen.isTrue || stateGlobal.isMaximized.value From 2a280463822ca8d84bfef65d811ca31f1ab72c7e Mon Sep 17 00:00:00 2001 From: solokot Date: Thu, 19 Oct 2023 14:44:42 +0300 Subject: [PATCH 049/114] Update ru.rs --- src/lang/ru.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 9d3872871..af7bf5cf3 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Переключитесь на основной дисплей, поскольку в режиме повышенных прав несколько дисплеев не поддерживаются."), ("Open in new window", "Открыть в новом окне"), ("Show displays as individual windows", "Показывать дисплеи в отдельных окнах"), + ("Use all my displays for the remote session", "Использовать все мои дисплеи для удалённого сеанса"), ].iter().cloned().collect(); } From 1b22bf0e082ff566ebd8304065e837e6a37b3532 Mon Sep 17 00:00:00 2001 From: flusheDData <116861809+flusheDData@users.noreply.github.com> Date: Thu, 19 Oct 2023 18:32:06 +0200 Subject: [PATCH 050/114] Update es.rs New terms added --- src/lang/es.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/lang/es.rs b/src/lang/es.rs index 30bee3ace..1ea917d13 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -555,15 +555,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Comprobar actualización al iniciar"), ("upgrade_rustdesk_server_pro_to_{}_tip", "¡Por favor, actualiza RustDesk Server Pro a la versión {} o superior"), ("pull_group_failed_tip", "No se ha podido refrescar el grupo"), - ("Filter by intersection", ""), - ("Remove wallpaper during incoming sessions", ""), - ("Test", ""), - ("switch_display_elevated_connections_tip", ""), - ("display_is_plugged_out_msg", ""), - ("No displays", ""), - ("elevated_switch_display_msg", ""), - ("Open in new window", ""), - ("Show displays as individual windows", ""), - ("Use all my displays for the remote session", ""), + ("Filter by intersection", "Filtrar por intersección"), + ("Remove wallpaper during incoming sessions", "Quitar el fonde de pantalla durante sesiones entrantes"), + ("Test", "Probar"), + ("switch_display_elevated_connections_tip", "Cambiar a una pantalla no principal no está soportado en el modo elevado cuando hay múltiples conexiones. Por favor, inténtalo de nuevo tras la instalación si quieres controlar múltiples pantallas."), + ("display_is_plugged_out_msg", "La pantalla está desconectada, cambia a la principal."), + ("No displays", "No hay pantallas"), + ("elevated_switch_display_msg", "Cambiar a la pantalla principal porque mútliples pantallas no están soportadas en modo elevado.""), + ("Open in new window", "Abrir en una nueva ventana"), + ("Show displays as individual windows", "Mostrar pantallas como ventanas individuales"), + ("Use all my displays for the remote session", "Usar todas mis pantallas para la sesión remota"), ].iter().cloned().collect(); } From e08da096dd7f2722c7bba6183dcd697cd367af5e Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Thu, 19 Oct 2023 23:45:48 +0530 Subject: [PATCH 051/114] remove home dir peer option Signed-off-by: Sahil Yeole --- flutter/lib/models/file_model.dart | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index 9a9c0f491..108c76f1e 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -375,14 +375,8 @@ class FileController { history.add(directory.value.path); } - void goToHomeDirectory() async { - if (isLocal) { - openDirectory(homePath); - return; - } - final homeDir = (await bind.sessionGetPeerOption( - sessionId: sessionId, name: "remote_home_dir")); - openDirectory(homeDir); + void goToHomeDirectory() { + openDirectory(homePath); } void goBack() { @@ -409,7 +403,7 @@ class FileController { } // TODO deprecated this - void initDirAndHome(Map evt) async { + void initDirAndHome(Map evt) { try { final fd = FileDirectory.fromJson(jsonDecode(evt['value'])); fd.format(options.value.isWindows, sort: sortBy.value); @@ -429,14 +423,6 @@ class FileController { } } else if (options.value.home.isEmpty) { options.value.home = fd.path; - - final homeDir = ( await bind.sessionGetPeerOption( - sessionId: sessionId, name: "remote_home_dir")); - - if (homeDir.isEmpty){ - bind.sessionPeerOption( - sessionId: sessionId, name: "remote_home_dir", value: fd.path); - } debugPrint("init remote home: ${fd.path}"); directory.value = fd; } From 8207908d9e054696e9e1a8b5150cee0a3ce19694 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Fri, 20 Oct 2023 00:14:14 +0530 Subject: [PATCH 052/114] fix remote home button Signed-off-by: Sahil Yeole --- flutter/lib/models/file_model.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/flutter/lib/models/file_model.dart b/flutter/lib/models/file_model.dart index 108c76f1e..ae1d9b701 100644 --- a/flutter/lib/models/file_model.dart +++ b/flutter/lib/models/file_model.dart @@ -261,6 +261,7 @@ class FileController { required this.getOtherSideDirectoryData}); String get homePath => options.value.home; + void set homePath(String path) => options.value.home = path; OverlayDialogManager? get dialogManager => rootState.target?.dialogManager; String get shortPath { @@ -376,6 +377,11 @@ class FileController { } void goToHomeDirectory() { + if (isLocal) { + openDirectory(homePath); + return; + } + homePath = ""; openDirectory(homePath); } From 4dcc368378d99a697eb3db98079a730fb5e27ce2 Mon Sep 17 00:00:00 2001 From: Mr-Update <37781396+Mr-Update@users.noreply.github.com> Date: Thu, 19 Oct 2023 20:50:08 +0200 Subject: [PATCH 053/114] Update de.rs --- src/lang/de.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lang/de.rs b/src/lang/de.rs index b67ef32b3..6324a2a61 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -564,5 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Wechseln Sie zur primären Anzeige, da die Mehrfachanzeige im erweiterten Modus nicht unterstützt wird."), ("Open in new window", "In einem neuen Fenster öffnen"), ("Show displays as individual windows", "Anzeigen als einzelne Fenster darstellen"), + ("Use all my displays for the remote session", "Alle meine Anzeigen für die Fernsitzung verwenden"), ].iter().cloned().collect(); } From cfc0925e75a031849e8d309d7558dbee3f8a899d Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Fri, 20 Oct 2023 01:35:54 +0530 Subject: [PATCH 054/114] reduce toLowerCase Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 40cb4100f..0eca17eac 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -258,6 +258,7 @@ class _ConnectionPageState extends State } else { String textWithoutSpaces = textEditingValue.text.replaceAll(" ", ""); + String textToFind = textWithoutSpaces.toLowerCase(); if (int.tryParse(textWithoutSpaces) != null) { textEditingValue = TextEditingValue( text: textWithoutSpaces, @@ -266,10 +267,10 @@ class _ConnectionPageState extends State } return peers.where((peer) => - peer.id.toLowerCase().contains(textEditingValue.text.toLowerCase()) || - peer.username.toLowerCase().contains(textEditingValue.text.toLowerCase()) || - peer.hostname.toLowerCase().contains(textEditingValue.text.toLowerCase()) || - peer.alias.toLowerCase().contains(textEditingValue.text.toLowerCase())) + peer.id.toLowerCase().contains(textToFind) || + peer.username.toLowerCase().contains(textToFind) || + peer.hostname.toLowerCase().contains(textToFind) || + peer.alias.toLowerCase().contains(textToFind)) .toList(); } }, From f4b0b39beb77b0d07d1114ae06a290438bcfcbd4 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Fri, 20 Oct 2023 02:40:54 +0530 Subject: [PATCH 055/114] show id if alias exists Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 0eca17eac..b6ac07672 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -457,6 +457,16 @@ class _ConnectionPageState extends State overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.titleSmall, )), + !peer.alias.isEmpty? + Padding( + padding: const EdgeInsets.only(left: 5, right: 5), + child: Text( + "(${peer.id})", + style: greyStyle, + overflow: TextOverflow.ellipsis, + ) + ) + : Container(), ]).marginOnly(top: 2), Align( alignment: Alignment.centerLeft, From 76665419052cf6fdded49d94d930fde5aa1f13b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Krawaczy=C5=84ski?= Date: Thu, 19 Oct 2023 23:13:00 +0200 Subject: [PATCH 056/114] Rename entrypoint to entrypoint.sh Rename entrypoint to entrypoint.sh which is correct with shebang of the file. --- entrypoint => entrypoint.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename entrypoint => entrypoint.sh (100%) diff --git a/entrypoint b/entrypoint.sh similarity index 100% rename from entrypoint rename to entrypoint.sh From c055ba2985516927a348900a8215983d536d1a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Krawaczy=C5=84ski?= Date: Thu, 19 Oct 2023 23:19:34 +0200 Subject: [PATCH 057/114] Update Dockerfile --- Dockerfile | 55 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8e44adb74..3aa093e01 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,54 @@ -FROM debian +FROM debian:bullseye-slim WORKDIR / -RUN apt update -y && apt install -y g++ gcc git curl nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake unzip zip sudo libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev cmake ninja-build && rm -rf /var/lib/apt/lists/* +ARG DEBIAN_FRONTEND=noninteractive +RUN apt update -y && \ + apt install --yes --no-install-recommends \ + g++ \ + gcc \ + git \ + curl \ + nasm \ + yasm \ + libgtk-3-dev \ + clang \ + libxcb-randr0-dev \ + libxdo-dev \ + libxfixes-dev \ + libxcb-shape0-dev \ + libxcb-xfixes0-dev \ + libasound2-dev \ + libpulse-dev \ + make \ + cmake \ + unzip \ + zip \ + sudo \ + libgstreamer1.0-dev \ + libgstreamer-plugins-base1.0-dev \ + ca-certificates \ + ninja-build && \ + rm -rf /var/lib/apt/lists/* -RUN git clone --branch 2023.04.15 --depth=1 https://github.com/microsoft/vcpkg -RUN /vcpkg/bootstrap-vcpkg.sh -disableMetrics -RUN /vcpkg/vcpkg --disable-metrics install libvpx libyuv opus aom +RUN git clone --branch 2023.04.15 --depth=1 https://github.com/microsoft/vcpkg && \ + /vcpkg/bootstrap-vcpkg.sh -disableMetrics && \ + /vcpkg/vcpkg --disable-metrics install libvpx libyuv opus aom + +RUN groupadd -r user && \ + useradd -r -g user user --home /home/user && \ + mkdir -p /home/user/rustdesk && \ + chown -R user: /home/user && \ + echo "user ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/user -RUN groupadd -r user && useradd -r -g user user --home /home/user && mkdir -p /home/user && chown user /home/user && echo "user ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/user WORKDIR /home/user RUN curl -LO https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so + USER user -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh -RUN chmod +x rustup.sh -RUN ./rustup.sh -y +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh && \ + chmod +x rustup.sh && \ + ./rustup.sh -y USER root ENV HOME=/home/user -COPY ./entrypoint / -ENTRYPOINT ["/entrypoint"] +COPY ./entrypoint.sh / +ENTRYPOINT ["/entrypoint.sh"] From 763467058b99acf98394ba78457f3f2502d33593 Mon Sep 17 00:00:00 2001 From: Ibnul Mutaki Date: Fri, 20 Oct 2023 04:33:16 +0700 Subject: [PATCH 058/114] improve ID trans --- src/lang/id.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/id.rs b/src/lang/id.rs index 7122f7845..21ba8a86a 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -564,6 +564,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Pindah ke tampilan utama, pada mode elevasi, pengggunaan lebih dari satu layar tidak diizinkan"), ("Open in new window", "Buka di jendela baru"), ("Show displays as individual windows", "Tampilkan dengan jendela terpisah"), - ("Use all my displays for the remote session", ""), + ("Use all my displays for the remote session", "Gunakan semua layar untuk sesi remote"), ].iter().cloned().collect(); } From e8c4615ff6781f06bbdb4df8819bdcf459454f9f Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Fri, 20 Oct 2023 04:34:50 +0530 Subject: [PATCH 059/114] improve text selection Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index b6ac07672..0b15404ca 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -12,6 +12,7 @@ import 'package:get/get.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:window_manager/window_manager.dart'; import 'package:flutter_hbb/models/peer_model.dart'; +import 'package:flutter/scheduler.dart'; import '../../common.dart'; import '../../common/formatter/id_formatter.dart'; @@ -287,10 +288,13 @@ class _ConnectionPageState extends State _fetchPeers(); } // select all to facilitate removing text, just following the behavior of address input of chrome - final textLength = fieldTextEditingController.value.text.length; - await Future.delayed(Duration(milliseconds: 200)); - fieldTextEditingController.selection = TextSelection.collapsed(offset: textLength); - fieldTextEditingController.selection = TextSelection(baseOffset: 0, extentOffset: textLength); + SchedulerBinding.instance.addPostFrameCallback((_) { + final textLength = fieldTextEditingController.value.text.length; + Future.delayed(Duration(milliseconds: 150) , () { + fieldTextEditingController.selection = TextSelection.collapsed(offset: textLength); + fieldTextEditingController.selection = TextSelection(baseOffset: 0, extentOffset: textLength); + }); + }); }); return Obx(() => TextField( From 00555a8e9e9a381833a2530729887d70f3b946e2 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Fri, 20 Oct 2023 04:44:53 +0530 Subject: [PATCH 060/114] fix text selection Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 0b15404ca..e714d979f 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -287,15 +287,10 @@ class _ConnectionPageState extends State if (fieldFocusNode.hasFocus && !isPeersLoading){ _fetchPeers(); } - // select all to facilitate removing text, just following the behavior of address input of chrome - SchedulerBinding.instance.addPostFrameCallback((_) { - final textLength = fieldTextEditingController.value.text.length; - Future.delayed(Duration(milliseconds: 150) , () { - fieldTextEditingController.selection = TextSelection.collapsed(offset: textLength); - fieldTextEditingController.selection = TextSelection(baseOffset: 0, extentOffset: textLength); - }); - }); }); + final textLength = fieldTextEditingController.value.text.length; + // select all to facilitate removing text, just following the behavior of address input of chrome + fieldTextEditingController.selection = TextSelection(baseOffset: 0, extentOffset: textLength); return Obx(() => TextField( maxLength: 90, From 4651d9df68fef8c185bcbaf4b726c563036ec2af Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Fri, 20 Oct 2023 04:50:07 +0530 Subject: [PATCH 061/114] fix textToFind Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index e714d979f..beae21d8b 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -259,13 +259,13 @@ class _ConnectionPageState extends State } else { String textWithoutSpaces = textEditingValue.text.replaceAll(" ", ""); - String textToFind = textWithoutSpaces.toLowerCase(); if (int.tryParse(textWithoutSpaces) != null) { textEditingValue = TextEditingValue( text: textWithoutSpaces, selection: textEditingValue.selection, ); } + String textToFind = textEditingValue.text.toLowerCase(); return peers.where((peer) => peer.id.toLowerCase().contains(textToFind) || From 7136400a33a02f9a3d712d1de0e9789a56f07b8e Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Fri, 20 Oct 2023 05:11:07 +0530 Subject: [PATCH 062/114] remove scheduler import Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index beae21d8b..859fd0d70 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -12,7 +12,6 @@ import 'package:get/get.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:window_manager/window_manager.dart'; import 'package:flutter_hbb/models/peer_model.dart'; -import 'package:flutter/scheduler.dart'; import '../../common.dart'; import '../../common/formatter/id_formatter.dart'; From 676b02c8dec0dcfe6f5e76b281e511e5f848b2e9 Mon Sep 17 00:00:00 2001 From: dignow Date: Fri, 20 Oct 2023 09:15:53 +0800 Subject: [PATCH 063/114] fix, macos, close sessions, confirm dialog and then hide Signed-off-by: dignow --- flutter/lib/common.dart | 2 +- .../lib/desktop/pages/remote_tab_page.dart | 5 +- .../lib/desktop/widgets/remote_toolbar.dart | 3 +- .../lib/desktop/widgets/tabbar_widget.dart | 50 +++++++++++-------- flutter/lib/models/state_model.dart | 2 +- 5 files changed, 36 insertions(+), 26 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index c6b613475..834b3bec3 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1495,7 +1495,7 @@ Future saveWindowPosition(WindowType type, {int? windowId}) async { late Size sz; late bool isMaximized; bool isFullscreen = stateGlobal.fullscreen.isTrue || - (Platform.isMacOS && stateGlobal.closeOnFullscreen); + (Platform.isMacOS && stateGlobal.closeOnFullscreen == true); setFrameIfMaximized() { if (isMaximized) { final pos = bind.getLocalFlutterOption(k: kWindowPrefix + type.name); diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index d785a9464..3b56ef4cc 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -125,9 +125,12 @@ class _ConnectionTabPageState extends State { windowOnTop(windowId()); tryMoveToScreenAndSetFullscreen(screenRect); if (tabController.length == 0) { - if (Platform.isMacOS && stateGlobal.closeOnFullscreen) { + // Show the hidden window. + if (Platform.isMacOS && stateGlobal.closeOnFullscreen == true) { stateGlobal.setFullscreen(true); } + // Reset the state + stateGlobal.closeOnFullscreen = null; } ConnectionTypeState.init(id); _toolbarState.setShow( diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index fd4fcc434..1cfa36145 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -20,7 +20,6 @@ import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:window_size/window_size.dart' as window_size; import '../../common.dart'; -import '../../common/widgets/dialog.dart'; import '../../models/model.dart'; import '../../models/platform_model.dart'; import '../../common/shared_state.dart'; @@ -1683,7 +1682,7 @@ class _CloseMenu extends StatelessWidget { return _IconMenuButton( assetName: 'assets/close.svg', tooltip: 'Close', - onPressed: () => clientClose(ffi.sessionId, ffi.dialogManager), + onPressed: () => closeConnection(id: id), color: _ToolbarTheme.redColor, hoverColor: _ToolbarTheme.hoverRedColor, ); diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 5ce5601a0..8973ed777 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -581,18 +581,14 @@ class WindowActionPanelState extends State mainWindowClose() async => await windowManager.hide(); notMainWindowClose(WindowController controller) async { await controller.hide(); - await Future.wait([ - rustDeskWinManager - .call(WindowType.Main, kWindowEventHide, {"id": kWindowId!}), - widget.onClose?.call() ?? Future.microtask(() => null) - ]); + await rustDeskWinManager + .call(WindowType.Main, kWindowEventHide, {"id": kWindowId!}); } macOSWindowClose( - Future Function() restoreFunc, - Future Function() checkFullscreen, - Future Function() closeFunc) async { - await restoreFunc(); + Future Function() checkFullscreen, + Future Function() closeFunc, + ) async { _macOSCheckRestoreCounter = 0; _macOSCheckRestoreTimer = Timer.periodic(Duration(milliseconds: 30), (timer) async { @@ -612,26 +608,38 @@ class WindowActionPanelState extends State } // macOS specific workaround, the window is not hiding when in fullscreen. if (Platform.isMacOS && await windowManager.isFullScreen()) { - stateGlobal.closeOnFullscreen = true; + stateGlobal.closeOnFullscreen ??= true; + await windowManager.setFullScreen(false); await macOSWindowClose( - () async => await windowManager.setFullScreen(false), - () async => await windowManager.isFullScreen(), - mainWindowClose); + () async => await windowManager.isFullScreen(), + mainWindowClose, + ); } else { - stateGlobal.closeOnFullscreen = false; + stateGlobal.closeOnFullscreen ??= false; await mainWindowClose(); } } else { // it's safe to hide the subwindow final controller = WindowController.fromWindowId(kWindowId!); - if (Platform.isMacOS && await controller.isFullScreen()) { - stateGlobal.closeOnFullscreen = true; - await macOSWindowClose( - () async => await controller.setFullscreen(false), - () async => await controller.isFullScreen(), - () async => await notMainWindowClose(controller)); + if (Platform.isMacOS) { + // onWindowClose() maybe called multiple times as loopCloseWindow() in remote_tab_page.dart. + // use ??= to make sure the value is set on first call. + + if (await widget.onClose?.call() ?? true) { + if (await controller.isFullScreen()) { + stateGlobal.closeOnFullscreen ??= true; + await controller.setFullscreen(false); + stateGlobal.setFullscreen(false, procWnd: false); + await macOSWindowClose( + () async => await controller.isFullScreen(), + () async => await notMainWindowClose(controller), + ); + } else { + stateGlobal.closeOnFullscreen ??= false; + await notMainWindowClose(controller); + } + } } else { - stateGlobal.closeOnFullscreen = false; await notMainWindowClose(controller); } } diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index 4afd77db2..c80c3551e 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -20,7 +20,7 @@ class StateGlobal { final RxBool showRemoteToolBar = false.obs; final svcStatus = SvcStatus.notReady.obs; // Only used for macOS - bool closeOnFullscreen = false; + bool? closeOnFullscreen; // Use for desktop -> remote toolbar -> resolution final Map> _lastResolutionGroupValues = {}; From 738a1a330c263cfb54083d7d773c4994121bd4f6 Mon Sep 17 00:00:00 2001 From: dignow Date: Fri, 20 Oct 2023 09:17:10 +0800 Subject: [PATCH 064/114] change comment Signed-off-by: dignow --- flutter/lib/desktop/widgets/tabbar_widget.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 8973ed777..08b0ce277 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -622,7 +622,7 @@ class WindowActionPanelState extends State // it's safe to hide the subwindow final controller = WindowController.fromWindowId(kWindowId!); if (Platform.isMacOS) { - // onWindowClose() maybe called multiple times as loopCloseWindow() in remote_tab_page.dart. + // onWindowClose() maybe called multiple times because of loopCloseWindow() in remote_tab_page.dart. // use ??= to make sure the value is set on first call. if (await widget.onClose?.call() ?? true) { From d8f808bf38c3b4df114e2df5177db168a84b0232 Mon Sep 17 00:00:00 2001 From: RustDesk <71636191+rustdesk@users.noreply.github.com> Date: Fri, 20 Oct 2023 13:59:48 +0800 Subject: [PATCH 065/114] Update es.rs --- src/lang/es.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/es.rs b/src/lang/es.rs index 1ea917d13..093298835 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -561,7 +561,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("switch_display_elevated_connections_tip", "Cambiar a una pantalla no principal no está soportado en el modo elevado cuando hay múltiples conexiones. Por favor, inténtalo de nuevo tras la instalación si quieres controlar múltiples pantallas."), ("display_is_plugged_out_msg", "La pantalla está desconectada, cambia a la principal."), ("No displays", "No hay pantallas"), - ("elevated_switch_display_msg", "Cambiar a la pantalla principal porque mútliples pantallas no están soportadas en modo elevado.""), + ("elevated_switch_display_msg", "Cambiar a la pantalla principal porque mútliples pantallas no están soportadas en modo elevado."), ("Open in new window", "Abrir en una nueva ventana"), ("Show displays as individual windows", "Mostrar pantallas como ventanas individuales"), ("Use all my displays for the remote session", "Usar todas mis pantallas para la sesión remota"), From db3978fd4e0cfdcadeb588cade8dce4426e5480e Mon Sep 17 00:00:00 2001 From: FastAct <93490087+FastAct@users.noreply.github.com> Date: Fri, 20 Oct 2023 11:24:55 +0200 Subject: [PATCH 066/114] Update nl.rs --- src/lang/nl.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 6eee21410..7a8189682 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -555,15 +555,15 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Checken voor updates bij opstarten"), ("upgrade_rustdesk_server_pro_to_{}_tip", "Upgrade RustDesk Server Pro naar versie {} of nieuwer!"), ("pull_group_failed_tip", "Vernieuwen van groep mislukt"), - ("Filter by intersection", ""), - ("Remove wallpaper during incoming sessions", ""), - ("Test", ""), - ("switch_display_elevated_connections_tip", ""), - ("display_is_plugged_out_msg", ""), - ("No displays", ""), - ("elevated_switch_display_msg", ""), - ("Open in new window", ""), - ("Show displays as individual windows", ""), - ("Use all my displays for the remote session", ""), + ("Filter by intersection", "Filter op kruising"), + ("Remove wallpaper during incoming sessions", "Achtergrond verwijderen tijdens inkomende sessies"), + ("Test", "Test"), + ("switch_display_elevated_connections_tip", "Overschakelen naar een niet-hoofdbeeldscherm wordt niet ondersteund in de verhoogde modus wanneer er meerdere verbindingen zijn. Probeer het opnieuw na de installatie als je meerdere schermen wilt beheren."), + ("display_is_plugged_out_msg", "Beeldscherm is uitgeschakeld, schakel over naar het primaire beeldscherm."), + ("No displays", "Geen beeldschermen"), + ("elevated_switch_display_msg", "Schakel over naar het primaire beeldscherm, aangezien meerdere beeldschermen niet worden ondersteund in de modus met verhoogde rechten."), + ("Open in new window", "Open in een nieuw venster"), + ("Show displays as individual windows", "Beeldschermen weergeven als afzonderlijke vensters"), + ("Use all my displays for the remote session", "Gebruik al mijn beeldschermen voor de externe sessie"), ].iter().cloned().collect(); } From 869d9d487b1a6a18f20d2e671f439bf876840840 Mon Sep 17 00:00:00 2001 From: Mr-Update <37781396+Mr-Update@users.noreply.github.com> Date: Fri, 20 Oct 2023 12:06:04 +0200 Subject: [PATCH 067/114] Update de.rs --- src/lang/de.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lang/de.rs b/src/lang/de.rs index 6324a2a61..b15023495 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -440,7 +440,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Strong", "Stark"), ("Switch Sides", "Seiten wechseln"), ("Please confirm if you want to share your desktop?", "Bitte bestätigen Sie, wenn Sie Ihren Desktop freigeben möchten."), - ("Display", "Anzeige"), + ("Display", "Bildschirm"), ("Default View Style", "Standard-Ansichtsstil"), ("Default Scroll Style", "Standard-Scroll-Stil"), ("Default Image Quality", "Standard-Bildqualität"), @@ -476,7 +476,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Empty Password", "Leeres Passwort"), ("Me", "Ich"), ("identical_file_tip", "Diese Datei ist identisch mit der Datei der Gegenstelle."), - ("show_monitors_tip", "Monitore in der Symbolleiste anzeigen"), + ("show_monitors_tip", "Bildschirme in der Symbolleiste anzeigen"), ("View Mode", "Ansichtsmodus"), ("login_linux_tip", "Sie müssen sich an einem entfernten Linux-Konto anmelden, um eine X-Desktop-Sitzung zu eröffnen."), ("verify_rustdesk_password_tip", "RustDesk-Passwort bestätigen"), @@ -558,12 +558,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Filter by intersection", "Nach Schnittmenge filtern"), ("Remove wallpaper during incoming sessions", "Hintergrundbild während eingehender Sitzungen entfernen"), ("Test", "Test"), - ("switch_display_elevated_connections_tip", "Das Umschalten auf eine nicht primäre Anzeige wird mit erhöhten Rechten nicht unterstützt, wenn mehrere Verbindungen bestehen. Bitte versuchen Sie es nach der Installation erneut, wenn Sie mehrere Anzeigen steuern möchten."), - ("display_is_plugged_out_msg", "Das Anzeigegerät ist nicht angeschlossen, schalten Sie auf das erste Anzeigegerät um."), - ("No displays", "Keine Anzeigegeräte"), - ("elevated_switch_display_msg", "Wechseln Sie zur primären Anzeige, da die Mehrfachanzeige im erweiterten Modus nicht unterstützt wird."), + ("switch_display_elevated_connections_tip", "Das Umschalten auf einen sekundären Bildschirm wird mit erhöhten Rechten nicht unterstützt, wenn mehrere Verbindungen bestehen. Bitte versuchen Sie es nach der Installation erneut, wenn Sie mehrere Bildschirme steuern möchten."), + ("display_is_plugged_out_msg", "Der Bildschirm ist nicht angeschlossen, schalten Sie auf den ersten Bildschirm um."), + ("No displays", "Keine Bildschirme"), + ("elevated_switch_display_msg", "Wechseln Sie zum primären Bildschirm, da mehrere Bildschirme im erweiterten Modus nicht unterstützt werden."), ("Open in new window", "In einem neuen Fenster öffnen"), - ("Show displays as individual windows", "Anzeigen als einzelne Fenster darstellen"), - ("Use all my displays for the remote session", "Alle meine Anzeigen für die Fernsitzung verwenden"), + ("Show displays as individual windows", "Jeden Bildschirm in einem eigenen Fenster anzeigen"), + ("Use all my displays for the remote session", "Alle meine Bildschirme für die Fernsitzung verwenden"), ].iter().cloned().collect(); } From aa3c58917b8e085ac546e3791e1282f3244194da Mon Sep 17 00:00:00 2001 From: rustdesk Date: Fri, 20 Oct 2023 19:09:13 +0800 Subject: [PATCH 068/114] remove wayland related from readme --- README.md | 28 ---------------------------- docs/README-AR.md | 4 ---- docs/README-CS.md | 4 ---- docs/README-DA.md | 27 --------------------------- docs/README-DE.md | 28 ---------------------------- docs/README-EO.md | 4 ---- docs/README-ES.md | 28 ---------------------------- docs/README-FA.md | 4 ---- docs/README-FI.md | 4 ---- docs/README-FR.md | 4 ---- docs/README-GR.md | 28 ---------------------------- docs/README-HU.md | 4 ---- docs/README-ID.md | 31 ------------------------------- docs/README-IT.md | 5 ----- docs/README-JP.md | 5 ----- docs/README-KR.md | 4 ---- docs/README-ML.md | 4 ---- docs/README-NL.md | 28 ---------------------------- docs/README-PL.md | 28 ---------------------------- docs/README-PTBR.md | 4 ---- docs/README-RU.md | 4 ---- docs/README-TR.md | 28 ---------------------------- docs/README-UA.md | 4 ---- docs/README-VN.md | 4 ---- docs/README-ZH.md | 33 --------------------------------- 25 files changed, 349 deletions(-) diff --git a/README.md b/README.md index 019442872..c00bc88f0 100644 --- a/README.md +++ b/README.md @@ -135,34 +135,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Change Wayland to X11 (Xorg) - -RustDesk does not support Wayland. Check [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) to configuring Xorg as the default GNOME session. - -## Wayland support - -Wayland does not seem to provide any API for sending keypresses to other windows. Therefore, the RustDesk uses an API from a lower level, namely the `/dev/uinput` device (Linux kernel level). - -When Wayland is the controlled side, you have to start in the following way: -```bash -# Start uinput service -$ sudo rustdesk --service -$ rustdesk -``` -**Notice**: Wayland screen recording uses different interfaces. RustDesk currently only supports org.freedesktop.portal.ScreenCast. -```bash -$ dbus-send --session --print-reply \ - --dest=org.freedesktop.portal.Desktop \ - /org/freedesktop/portal/desktop \ - org.freedesktop.DBus.Properties.Get \ - string:org.freedesktop.portal.ScreenCast string:version -# Not support -Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast” -# Support -method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2 - variant uint32 4 -``` - ## How to build with Docker Begin by cloning the repository and building the Docker container: diff --git a/docs/README-AR.md b/docs/README-AR.md index 80948fb39..9b72eb18d 100644 --- a/docs/README-AR.md +++ b/docs/README-AR.md @@ -118,10 +118,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### X11 (Xorg) إلى Wayland تغيير - -افتراضية GNOME session ك Xorg إتبع [هذه](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) الخطوات لإعداد Wayland لا تدعم RustDesk - ## Docker طريقة البناء باستخدام ابدأ باستنساخ المستودع وبناء الكونتاينر: diff --git a/docs/README-CS.md b/docs/README-CS.md index 15e576c47..e7cf998f3 100644 --- a/docs/README-CS.md +++ b/docs/README-CS.md @@ -111,10 +111,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Změna z Wayland na X11 (Xorg) - -RustDesk (zatím) nepodporuje zobrazovací server Wayland. Jak nastavit Xorg jako výchozí pro relace v prostředí GNOME naleznete [zde](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/). - ## Jak sestavit prostřednictvím Docker kontejnerizace Začněte tím, že si naklonujete tento repozitář a sestavíte docker kontejner: diff --git a/docs/README-DA.md b/docs/README-DA.md index af2f5937f..e0bc11829 100644 --- a/docs/README-DA.md +++ b/docs/README-DA.md @@ -108,33 +108,6 @@ mv libsciter-gtk.so target/debug cargo run ``` -### Skift Wayland til X11 (Xorg) - -RustDesk understøtter ikke Wayland. Tjek [dette](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) for at konfigurere Xorg som standard GNOME-session. - -## Wayland-support - -Wayland ser ikke ud til at levere nogen API til at sende tastetryk til andre vinduer. Derfor bruger rustdesk et API fra et lavere niveau, nemlig `/dev/uinput`-enheden (Linux-kerneniveau). - -Når wayland er den kontrollerede side, skal du starte på følgende måde: -```bash -# Start uinput service -$ sudo rustdesk --service -$ rustdesk -``` -**Bemærk**: Wayland-skærmoptagelse bruger forskellige grænseflader. RustDesk understøtter i øjeblikket kun org.freedesktop.portal.ScreenCast. -```bash -$ dbus-send --session --print-reply \ - --dest=org.freedesktop.portal.Desktop \ - /org/freedesktop/portal/desktop \ - org.freedesktop.DBus.Properties.Get \ - string:org.freedesktop.portal.ScreenCast string:version -# Not support -Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast” -# Support -method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2 - variant uint32 4 -``` ## Sådan bygger du med Docker ```sh diff --git a/docs/README-DE.md b/docs/README-DE.md index 5ac370a87..066c13f99 100644 --- a/docs/README-DE.md +++ b/docs/README-DE.md @@ -133,34 +133,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Wayland zu X11 (Xorg) ändern - -RustDesk unterstützt Wayland nicht. Siehe [hier](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/), um Xorg als Standard-GNOME-Sitzung zu nutzen. - -## Wayland-Unterstützung - -Wayland scheint keine API für das Senden von Tastatureingaben an andere Fenster zu bieten. Daher verwendet RustDesk eine API von einer niedrigeren Ebene, nämlich dem Gerät `/dev/uinput` (Linux-Kernelebene). - -Wenn Wayland die kontrollierte Seite ist, müssen Sie wie folgt vorgehen: -```bash -# Dienst uinput starten -$ sudo rustdesk --service -$ rustdesk -``` -**Hinweis**: Die Wayland-Bildschirmaufnahme verwendet verschiedene Schnittstellen. RustDesk unterstützt derzeit nur org.freedesktop.portal.ScreenCast. -```bash -$ dbus-send --session --print-reply \ - --dest=org.freedesktop.portal.Desktop \ - /org/freedesktop/portal/desktop \ - org.freedesktop.DBus.Properties.Get \ - string:org.freedesktop.portal.ScreenCast string:version -# Keine Unterstützung -Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast” -# Unterstützung -method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2 - variant uint32 4 -``` - ## Auf Docker kompilieren Beginnen Sie damit, das Repository zu klonen und den Docker-Container zu bauen: diff --git a/docs/README-EO.md b/docs/README-EO.md index be1538089..2cfc9ee6a 100644 --- a/docs/README-EO.md +++ b/docs/README-EO.md @@ -104,10 +104,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Ŝanĝi Wayland por X11 (Xorg) - -RustDesk ne subtenas Wayland. Kontrolu [tion](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) por agordi Xorg kiel defaŭlta sesio GNOME. - ## Kiel kompili kun Docker Komencu klonante la deponejon kaj kompilu la konteneron Docker: diff --git a/docs/README-ES.md b/docs/README-ES.md index 19a7335d3..02424ec00 100644 --- a/docs/README-ES.md +++ b/docs/README-ES.md @@ -113,34 +113,6 @@ mv libsciter-gtk.so target/debug cargo run ``` -### Cambia Wayland a X11 (Xorg) - -RustDesk no soporta Wayland. Lee [esto](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) para configurar Xorg en la sesión por defecto de GNOME. - -## Soporte para Wayland - -Wayland no parece proporcionar ninguna API para enviar pulsaciones de teclas a otras ventanas. Por lo tanto, rustdesk usa una API de nivel bajo, a saber, el dispositivo `/dev/uinput` (a nivel del kernel de Linux). - -Cuando wayland esta del lado controlado, hay que iniciar de la siguiente manera: -```bash -# Empezar el servicio uinput -$ sudo rustdesk --service -$ rustdesk -``` -**Aviso**: La grabación de pantalla de Wayland utiliza diferentes interfaces. RustDesk actualmente sólo soporta org.freedesktop.portal.ScreenCast -```bash -$ dbus-send --session --print-reply \ - --dest=org.freedesktop.portal.Desktop \ - /org/freedesktop/portal/desktop \ - org.freedesktop.DBus.Properties.Get \ - string:org.freedesktop.portal.ScreenCast string:version -# No soportado -Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast” -# Soportado -method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2 - variant uint32 4 -``` - ## Como compilar con Docker Empieza clonando el repositorio y compilando el contenedor de docker: diff --git a/docs/README-FA.md b/docs/README-FA.md index 989b0047c..d07dadd09 100644 --- a/docs/README-FA.md +++ b/docs/README-FA.md @@ -112,10 +112,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### تغییر Wayland به (X11 (Xorg - -راست‌دسک از Wayland پشتیبانی نمی کند. برای جایگزنی Xorg به عنوان پیش‌فرض GNOM، [اینجا](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) را کلیک کنید. - ## نحوه ساخت با داکر این مخزن Git را دریافت کنید و کانتینر را به روش زیر بسازید diff --git a/docs/README-FI.md b/docs/README-FI.md index 195d29c84..988729a0f 100644 --- a/docs/README-FI.md +++ b/docs/README-FI.md @@ -104,10 +104,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Vaihda Wayland-ympäristö X11 (Xorg)-ympäristöön - -RustDesk ei tue Waylandia. Tarkista [tämä](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) asettamalla Xorg oletus GNOME-istuntoon. - ## Kuinka rakennetaan Dockerin kanssa Aloita kloonaamalla tietovarasto ja rakentamalla docker-säiliö: diff --git a/docs/README-FR.md b/docs/README-FR.md index 39f09a625..ea55ec468 100644 --- a/docs/README-FR.md +++ b/docs/README-FR.md @@ -104,10 +104,6 @@ mv libsciter-gtk.so target/debug Exécution du cargo ``` -### Changer Wayland en X11 (Xorg) - -RustDesk ne supporte pas Wayland. Lisez [cela](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) pour configurer Xorg comme la session GNOME par défaut. - ## Comment construire avec Docker Commencez par cloner le dépôt et construire le conteneur Docker : diff --git a/docs/README-GR.md b/docs/README-GR.md index c720dd823..f324cfa95 100644 --- a/docs/README-GR.md +++ b/docs/README-GR.md @@ -133,34 +133,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Αλλαγή του Wayland σε X11 (Xorg) - -Το RustDesk δεν υποστηρίζει το πρωτόκολλο Wayland. Διαβάστε [εδώ](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) ώστε να ορίσετε το Xorg ως το προκαθορισμένο GNOME περιβάλλον. - -## Υποστήριξη Wayland - -Το Wayland προς το παρόν δεν διαθέτει κάποιο API το οποίο να στέλνει τα πατήματα πλήκτρων στα υπόλοιπα παράθυρα. Για τον λόγο αυτό, το Rustdesk χρησιμοποιεί ένα API από κατώτερο επίπεδο, όπως το `/dev/uinput` (Linux kernel level). - -Σε περίπτωση που το Wayland είναι η ελεγχόμενη πλευρά, θα πρέπει να ξεκινήσετε με τον παρακάτω τρόπο: -```bash -# Start uinput service -$ sudo rustdesk --service -$ rustdesk -``` -**Σημείωση**: Η εγγραφή οθόνης του Wayland χρησιμοποιεί διαφορετικές διεπαφές. Το RustDesk προς το παρόν υποστηρίζει μόνο org.freedesktop.portal.ScreenCast. -```bash -$ dbus-send --session --print-reply \ - --dest=org.freedesktop.portal.Desktop \ - /org/freedesktop/portal/desktop \ - org.freedesktop.DBus.Properties.Get \ - string:org.freedesktop.portal.ScreenCast string:version -# Not support -Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast” -# Support -method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2 - variant uint32 4 -``` - ## Πως να κάνετε build στο Docker Ξεκινήστε κλωνοποιώντας το αποθετήριο και κάνοντας build το docker container: diff --git a/docs/README-HU.md b/docs/README-HU.md index 8965a9b1e..d47a775d0 100644 --- a/docs/README-HU.md +++ b/docs/README-HU.md @@ -116,10 +116,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Válts Wayland-ról X11-re (Xorg) - -A RustDesk nem támogatja a Waylendet. [Itt](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) található egy tutorial amelynek segítségével beállíthatod a Xorg-ot mint alap GNOME session. - ## Hogyan építs Dockerrel Kezdjünk a repo clónozásával, majd pedig a Docker container megépítésével: diff --git a/docs/README-ID.md b/docs/README-ID.md index 9999eb72f..be8003798 100644 --- a/docs/README-ID.md +++ b/docs/README-ID.md @@ -128,37 +128,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Mengubah Wayland ke X11 (Xorg) - -RustDesk tidak mendukung Wayland. Cek [ini](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) untuk mengonfigurasi Xorg sebagai sesi standar di GNOME. - -## Kompatibilitas dengan Wayland - -Sepertinya Wayland tidak memiliki API untuk mengirimkan ketukan tombol ke jendela lain. Maka dari itu, RustDesk menggunakan API dari level yang lebih rendah, lebih tepatnya perangkat `/dev/uinput` (linux kernel level) - -Saat Wayland menjadi sisi yang dikendalikan atau sisi yang sedang diremote, kamu harus memulai dengan cara ini - -```bash -# Start uinput service -$ sudo rustdesk --service -$ rustdesk -``` - -**Harap Diperhatikan**: Saat Perekaman layar menggunakan Wayland antarmuka (UI) yang ditampilkan akan berbeda. Untuk saat ini RustDesk hanya mendukung org.freedesktop.portal.ScreenCast. - -```bash -$ dbus-send --session --print-reply \ - --dest=org.freedesktop.portal.Desktop \ - /org/freedesktop/portal/desktop \ - org.freedesktop.DBus.Properties.Get \ - string:org.freedesktop.portal.ScreenCast string:version -# Not support -Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast” -# Support -method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2 - variant uint32 4 -``` - ## Cara Build dengan Docker Mulailah dengan melakukan kloning (clone) repositori dan build dengan docker container: diff --git a/docs/README-IT.md b/docs/README-IT.md index c1c46bfed..6cef02804 100644 --- a/docs/README-IT.md +++ b/docs/README-IT.md @@ -109,11 +109,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Cambiare Wayland in X11 (Xorg) - -RustDesk non supporta Wayland. -Controlla [qui](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) per configurare Xorg come sessione predefinita di GNOME. - ## Come compilare con Docker Clona il repository e compila i container docker: diff --git a/docs/README-JP.md b/docs/README-JP.md index 44f811eec..d822cff17 100644 --- a/docs/README-JP.md +++ b/docs/README-JP.md @@ -114,11 +114,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Wayland の場合、X11(Xorg)に変更します - -RustDeskはWaylandをサポートしていません。 - [こちら](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) を確認して、XorgをデフォルトのGNOMEセッションとして構成します。 - ## Dockerでビルドする方法 リポジトリのクローンを作成し、Dockerコンテナを構築することから始めます。 diff --git a/docs/README-KR.md b/docs/README-KR.md index dacb092e7..829f00fe9 100644 --- a/docs/README-KR.md +++ b/docs/README-KR.md @@ -112,10 +112,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Wayland 일 경우, X11(Xorg)로 변경 - -RustDesk는 Wayland를 지원하지 않습니다. [링크](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/)를 확인해서 Xorg 기본값의 GNOME 세션을 구성합니다. - ## Docker에 빌드하는 방법 레포지토리를 클론하고, Docker 컨테이너 구성하는 것으로 시작합니다. diff --git a/docs/README-ML.md b/docs/README-ML.md index a73fd7815..6aaaf6077 100644 --- a/docs/README-ML.md +++ b/docs/README-ML.md @@ -103,10 +103,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### വേലാൻഡ് X11 (Xorg) ആയി മാറ്റുക - -RustDesk Wayland-നെ പിന്തുണയ്ക്കുന്നില്ല. സ്ഥിരസ്ഥിതി ഗ്നോം സെഷനായി Xorg കോൺഫിഗർ ചെയ്യുന്നതിന് [ഇത്](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) പരിശോധിക്കുക. - ## ഡോക്കർ ഉപയോഗിച്ച് എങ്ങനെ നിർമ്മിക്കാം റെപ്പോസിറ്റോറി ക്ലോണുചെയ്‌ത് ഡോക്കർ കണ്ടെയ്‌നർ നിർമ്മിക്കുന്നതിലൂടെ ആരംഭിക്കുക: diff --git a/docs/README-NL.md b/docs/README-NL.md index bec83a285..ee5e98a85 100644 --- a/docs/README-NL.md +++ b/docs/README-NL.md @@ -130,34 +130,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Wissel van Wayland naar X11 (Xorg) - -RustDesk ondersteunt Wayland niet. Lees [hier](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) hoe je Xorg als standaardsessie kunt instellen voor GNOME. - -## Wayland support - -Wayland lijkt geen API te bieden voor het verzenden van toetsaanslagen naar andere vensters. Daarom gebruikt de rustdesk een API van een lager niveau, namelijk het `/dev/uinput` apparaat (Linux kernel niveau). - -Als wayland de gecontroleerde kant is, moet je op de volgende manier beginnen: -```bash -# Start uinput service -$ sudo rustdesk --service -$ rustdesk -``` -**Let op**: Wayland schermopname gebruikt verschillende interfaces. RustDesk ondersteunt momenteel alleen org.freedesktop.portal.ScreenCast. -```bash -$ dbus-send --session --print-reply \ - --dest=org.freedesktop.portal.Desktop \ - /org/freedesktop/portal/desktop \ - org.freedesktop.DBus.Properties.Get \ - string:org.freedesktop.portal.ScreenCast string:version -# Not support -Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast” -# Support -method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2 - variant uint32 4 -``` - ## Bouwen met Docker Begin met het klonen van de repository en het bouwen van de docker container: diff --git a/docs/README-PL.md b/docs/README-PL.md index ba27af04d..3809c58bd 100644 --- a/docs/README-PL.md +++ b/docs/README-PL.md @@ -128,34 +128,6 @@ mv libsciter-gtk.so target/debug cargo run ``` -### Zmień Wayland na X11 (Xorg) - -RustDesk nie obsługuje Waylanda. Sprawdź [tutaj](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/), jak skonfigurować Xorg jako domyślną sesję GNOME. - -## Wspracie Wayland - -Wygląda na to, że Wayland nie wspiera żadnego API do wysyłania naciśnięć klawiszy do innych okien. Dlatego rustdesk używa API z niższego poziomu, urządzenia o nazwie `/dev/uinput` (poziom jądra Linux). - -Gdy po stronie kontrolowanej pracuje Wayland, musisz uruchomić program w następujący sposób: -```bash -# Start uinput service -$ sudo rustdesk --service -$ rustdesk -``` -**Uwaga**: Nagrywanie ekranu Wayland wykorzystuje różne interfejsy. RustDesk obecnie obsługuje tylko org.freedesktop.portal.ScreenCast. -```bash -$ dbus-send --session --print-reply \ - --dest=org.freedesktop.portal.Desktop \ - /org/freedesktop/portal/desktop \ - org.freedesktop.DBus.Properties.Get \ - string:org.freedesktop.portal.ScreenCast string:version -# Not support -Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast” -# Support -method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2 - variant uint32 4 -``` - ## Jak kompilować za pomocą Dockera Rozpocznij od sklonowania repozytorium i stworzenia kontenera docker: diff --git a/docs/README-PTBR.md b/docs/README-PTBR.md index 6e6f01fce..3ae092db8 100644 --- a/docs/README-PTBR.md +++ b/docs/README-PTBR.md @@ -104,10 +104,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Mude Wayland para X11 (Xorg) - -RustDesk não suporta Wayland. Veja [esse link](https://docs.fedoraproject.org/pt_BR/quick-docs/configuring-xorg-as-default-gnome-session/) para configurar o Xorg como a sessão padrão do GNOME. - ## Como compilar com Docker Comece clonando o repositório e montando o container docker: diff --git a/docs/README-RU.md b/docs/README-RU.md index 01710f084..959c33b10 100644 --- a/docs/README-RU.md +++ b/docs/README-RU.md @@ -114,10 +114,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Смените Wayland на X11 (Xorg) - -RustDesk не поддерживает Wayland. Смотрите [этот документ](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) для настройки Xorg в качестве сеанса GNOME по умолчанию. - ## Как собрать с помощью Docker Начните с клонирования репозитория и создания docker-контейнера: diff --git a/docs/README-TR.md b/docs/README-TR.md index 590ead0df..3afae98b0 100644 --- a/docs/README-TR.md +++ b/docs/README-TR.md @@ -138,34 +138,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Wayland'ı X11 (Xorg) Olarak Değiştirme - -RustDesk, Wayland'ı desteklemez. Xorg'u GNOME oturumu olarak varsayılan olarak ayarlamak için [burayı](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) kontrol edin. - -## Wayland Desteği - -Wayland'ın diğer pencerelere tuş vuruşu göndermek için herhangi bir API sağlamadığı görünmektedir. Bu nedenle, RustDesk daha düşük bir seviyeden, yani Linux çekirdek seviyesindeki `/dev/uinput` cihazının API'sini kullanır. - -Wayland tarafı kontrol edildiğinde, aşağıdaki şekilde başlatmanız gerekir: -```bash -# uinput servisini başlatın -$ sudo rustdesk --service -$ rustdesk -``` -**Uyarı**: Wayland ekran kaydı farklı arayüzler kullanır. RustDesk şu anda yalnızca org.freedesktop.portal.ScreenCast'ı destekler. -```bash -$ dbus-send --session --print-reply \ - --dest=org.freedesktop.portal.Desktop \ - /org/freedesktop/portal/desktop \ - org.freedesktop.DBus.Properties.Get \ - string:org.freedesktop.portal.ScreenCast string:version -# Desteklenmez -Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast” -# Desteklenir -method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2 - variant uint32 4 -``` - ## Docker ile Derleme Nasıl Yapılır Öncelikle deposunu klonlayın ve Docker konteynerini oluşturun: diff --git a/docs/README-UA.md b/docs/README-UA.md index 01914cfc2..275033977 100644 --- a/docs/README-UA.md +++ b/docs/README-UA.md @@ -131,10 +131,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Змініть Wayland на X11 (Xorg) - -RustDesk не підтримує Wayland. Дивіться [цей документ](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) для налаштування Xorg як сеансу GNOME за замовчуванням. - ## Як зібрати за допомогою Docker Почніть з клонування сховища та створення docker-контейнера: diff --git a/docs/README-VN.md b/docs/README-VN.md index ea2c62ead..de6d6b800 100644 --- a/docs/README-VN.md +++ b/docs/README-VN.md @@ -116,10 +116,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### Chuyển từ Wayland sang X11 (Xorg) - -RustDesk hiện không hỗ trợ Wayland. Hãy xem [đường linh ở đây](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) cách để cài đặt Xorg làm session mặc định của GNOME. - ## Cách để build sử dụng Docker Bắt đầu bằng cách sao chép repo này về máy tính và build cái Docker cointainer: diff --git a/docs/README-ZH.md b/docs/README-ZH.md index 7967f7d30..1229f8ad5 100644 --- a/docs/README-ZH.md +++ b/docs/README-ZH.md @@ -134,39 +134,6 @@ mv libsciter-gtk.so target/debug VCPKG_ROOT=$HOME/vcpkg cargo run ``` -### 把 Wayland 修改成 X11 (Xorg) - -RustDesk 暂时不支持 Wayland,不过正在积极开发中。 -> [点我](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) -查看如何将 Xorg 设置成默认的 GNOME session. - -## Wayland 支持 - -Wayland 似乎没有提供任何将按键发送到其他窗口的 API. 因此, RustDesk 使用较低级别的 API, 即 `/dev/uinput` devices (Linux kernal level). - -当 Wayland 是受控方时,您必须以下列方式开始操作: - -```bash -# Start uinput service -$ sudo rustdesk --service -$ rustdesk -``` - -**Notice**: Wayland 屏幕录制使用不同的接口. RustDesk 目前只支持 org.freedesktop.portal.ScreenCast. - -```bash -$ dbus-send --session --print-reply \ - --dest=org.freedesktop.portal.Desktop \ - /org/freedesktop/portal/desktop \ - org.freedesktop.DBus.Properties.Get \ - string:org.freedesktop.portal.ScreenCast string:version -# Not support -Error org.freedesktop.DBus.Error.InvalidArgs: No such interface “org.freedesktop.portal.ScreenCast” -# Support -method return time=1662544486.931020 sender=:1.54 -> destination=:1.139 serial=257 reply_serial=2 - variant uint32 4 -``` - ## 使用 Docker 编译 克隆版本库并构建 Docker 容器: From 85eb82e69d084e50811b95dc34e5fbe3a21830e2 Mon Sep 17 00:00:00 2001 From: leroyloren <57643470+leroyloren@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:31:49 +0200 Subject: [PATCH 069/114] Update cs.rs --- src/lang/cs.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 3ba2c4a23..bd2b8cee3 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -556,14 +556,14 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("upgrade_rustdesk_server_pro_to_{}_tip", "Aktualizujte prosím RustDesk Server Pro na verzi {} nebo novější!"), ("pull_group_failed_tip", "Nepodařilo se obnovit skupinu"), ("Filter by intersection", ""), - ("Remove wallpaper during incoming sessions", ""), - ("Test", ""), - ("switch_display_elevated_connections_tip", ""), - ("display_is_plugged_out_msg", ""), - ("No displays", ""), - ("elevated_switch_display_msg", ""), - ("Open in new window", ""), - ("Show displays as individual windows", ""), - ("Use all my displays for the remote session", ""), + ("Remove wallpaper during incoming sessions", "Odstrait tapetu během příchozích relací"), + ("Test", "Test"), + ("switch_display_elevated_connections_tip", "Přepnutí na jinou než primární obrazovku není podporováno ve zvýšeném režimu, pokud existuje více připojení. Pokud chcete ovládat více obrazovek, zkuste to po instalaci znovu."), + ("display_is_plugged_out_msg", "Obrazovka je odpojena, přepněte na první obrazovku."), + ("No displays", "Žádné obrazovky"), + ("elevated_switch_display_msg", "Přepnout na primární obrazovku, protože více obrazovek není podporováno ve zvýšeném režimu."), + ("Open in new window", "Otevřít v novém okně"), + ("Show displays as individual windows", "Zobrazit obrazovky jako jednotlivá okna"), + ("Use all my displays for the remote session", "Použít všechny mé obrazovky pro vzdálenou relaci"), ].iter().cloned().collect(); } From 82e1fe3f8be32ac1269a223606a0c2d63a09f60e Mon Sep 17 00:00:00 2001 From: leroyloren <57643470+leroyloren@users.noreply.github.com> Date: Fri, 20 Oct 2023 14:34:12 +0200 Subject: [PATCH 070/114] Update cs.rs --- src/lang/cs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/cs.rs b/src/lang/cs.rs index bd2b8cee3..00eb95248 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -555,8 +555,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Check for software update on startup", "Kontrola aktualizace softwaru při spuštění"), ("upgrade_rustdesk_server_pro_to_{}_tip", "Aktualizujte prosím RustDesk Server Pro na verzi {} nebo novější!"), ("pull_group_failed_tip", "Nepodařilo se obnovit skupinu"), - ("Filter by intersection", ""), - ("Remove wallpaper during incoming sessions", "Odstrait tapetu během příchozích relací"), + ("Filter by intersection", "Filtrovat podle průsečíku"), + ("Remove wallpaper during incoming sessions", "Odstranit tapetu během příchozích relací"), ("Test", "Test"), ("switch_display_elevated_connections_tip", "Přepnutí na jinou než primární obrazovku není podporováno ve zvýšeném režimu, pokud existuje více připojení. Pokud chcete ovládat více obrazovek, zkuste to po instalaci znovu."), ("display_is_plugged_out_msg", "Obrazovka je odpojena, přepněte na první obrazovku."), From b3948910ff8b4d9abee83a08484819412e5d1ea3 Mon Sep 17 00:00:00 2001 From: dignow Date: Sat, 21 Oct 2023 13:10:51 +0800 Subject: [PATCH 071/114] fix is x11, on conn Signed-off-by: dignow --- src/common.rs | 18 +++++------------- src/flutter_ffi.rs | 2 +- src/platform/linux.rs | 9 +++++++++ src/server/display_service.rs | 19 ++++++------------- src/server/input_service.rs | 4 +--- src/server/video_service.rs | 12 +++++------- src/server/wayland.rs | 15 +++++++++------ 7 files changed, 36 insertions(+), 43 deletions(-) diff --git a/src/common.rs b/src/common.rs index 3b2f5ca3e..cf75fab1b 100644 --- a/src/common.rs +++ b/src/common.rs @@ -108,7 +108,7 @@ impl Drop for SimpleCallOnReturn { pub fn global_init() -> bool { #[cfg(target_os = "linux")] { - if !*IS_X11 { + if !crate::platform::linux::is_x11() { crate::server::wayland::init(); } } @@ -956,7 +956,10 @@ pub async fn post_request_sync(url: String, body: String, header: &str) -> Resul } #[inline] -pub fn make_privacy_mode_msg_with_details(state: back_notification::PrivacyModeState, details: String) -> Message { +pub fn make_privacy_mode_msg_with_details( + state: back_notification::PrivacyModeState, + details: String, +) -> Message { let mut misc = Misc::new(); let mut back_notification = BackNotification { details, @@ -990,17 +993,6 @@ pub fn get_supported_keyboard_modes(version: i64) -> Vec { .collect::>() } -#[cfg(not(target_os = "linux"))] -lazy_static::lazy_static! { - pub static ref IS_X11: bool = false; - -} - -#[cfg(target_os = "linux")] -lazy_static::lazy_static! { - pub static ref IS_X11: bool = hbb_common::platform::linux::is_x11_or_headless(); -} - pub fn make_fd_to_json(id: i32, path: String, entries: &Vec) -> String { use serde_json::json; let mut fd_json = serde_json::Map::new(); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index f1d7e5923..efd2a3e82 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1584,7 +1584,7 @@ pub fn main_is_installed() -> SyncReturn { pub fn main_start_grab_keyboard() -> SyncReturn { #[cfg(target_os = "linux")] - if !*crate::common::IS_X11 { + if !crate::platform::linux::is_x11() { return SyncReturn(false); } crate::keyboard::client::start_grab_loop(); diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 37b27cf64..87dc8d071 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -35,6 +35,10 @@ type Xdo = *const c_void; pub const PA_SAMPLE_RATE: u32 = 48000; static mut UNMODIFIED: bool = true; +lazy_static::lazy_static! { + pub static ref IS_X11: bool = hbb_common::platform::linux::is_x11_or_headless(); +} + thread_local! { static XDO: RefCell = RefCell::new(unsafe { xdo_new(std::ptr::null()) }); static DISPLAY: RefCell<*mut c_void> = RefCell::new(unsafe { XOpenDisplay(std::ptr::null())}); @@ -1360,3 +1364,8 @@ impl Drop for WallPaperRemover { } } } + +#[inline] +pub fn is_x11() -> bool { + *IS_X11 +} diff --git a/src/server/display_service.rs b/src/server/display_service.rs index 780833f78..62f5cac3d 100644 --- a/src/server/display_service.rs +++ b/src/server/display_service.rs @@ -1,16 +1,14 @@ use super::*; +#[cfg(target_os = "linux")] +use crate::platform::linux::is_x11; #[cfg(all(windows, feature = "virtual_display_driver"))] use crate::virtual_display_manager; #[cfg(windows)] use hbb_common::get_version_number; use hbb_common::protobuf::MessageField; use scrap::Display; -#[cfg(target_os = "linux")] -use std::sync::atomic::{AtomicBool, Ordering}; // https://github.com/rustdesk/rustdesk/discussions/6042, avoiding dbus call -#[cfg(target_os = "linux")] -pub(super) static IS_X11: AtomicBool = AtomicBool::new(false); pub const NAME: &'static str = "display"; @@ -71,7 +69,7 @@ pub(super) fn check_display_changed( #[cfg(target_os = "linux")] { // wayland do not support changing display for now - if !IS_X11.load(Ordering::SeqCst) { + if !is_x11() { return None; } } @@ -176,11 +174,6 @@ pub fn try_plug_out_virtual_display() { } fn run(sp: EmptyExtraFieldService) -> ResultType<()> { - #[cfg(target_os = "linux")] - { - IS_X11.store(scrap::is_x11(), Ordering::SeqCst); - } - while sp.ok() { sp.snapshot(|sps| { if sps.has_subscribes() { @@ -274,7 +267,7 @@ pub(super) fn check_update_displays(all: &Vec) { pub fn is_inited_msg() -> Option { #[cfg(target_os = "linux")] - if !IS_X11.load(Ordering::SeqCst) { + if !is_x11() { return super::wayland::is_inited(); } None @@ -283,7 +276,7 @@ pub fn is_inited_msg() -> Option { pub async fn update_get_sync_displays() -> ResultType> { #[cfg(target_os = "linux")] { - if !IS_X11.load(Ordering::SeqCst) { + if !is_x11() { return super::wayland::get_displays().await; } } @@ -295,7 +288,7 @@ pub async fn update_get_sync_displays() -> ResultType> { pub fn get_primary() -> usize { #[cfg(target_os = "linux")] { - if !IS_X11.load(Ordering::SeqCst) { + if !is_x11() { return match super::wayland::get_primary() { Ok(n) => n, Err(_) => 0, diff --git a/src/server/input_service.rs b/src/server/input_service.rs index d40bf02c1..a90a0005d 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -1,8 +1,6 @@ use super::*; #[cfg(target_os = "macos")] use crate::common::is_server; -#[cfg(target_os = "linux")] -use crate::common::IS_X11; use crate::input::*; #[cfg(target_os = "macos")] use dispatch::Queue; @@ -1152,7 +1150,7 @@ fn map_keyboard_mode(evt: &KeyEvent) { // Wayland #[cfg(target_os = "linux")] - if !*IS_X11 { + if !crate::platform::linux::is_x11() { let mut en = ENIGO.lock().unwrap(); let code = evt.chr() as u16; diff --git a/src/server/video_service.rs b/src/server/video_service.rs index c2a9b6113..d5f39a2c6 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -18,8 +18,6 @@ // to-do: // https://slhck.info/video/2017/03/01/rate-control.html -#[cfg(target_os = "linux")] -use super::display_service::IS_X11; use super::{ display_service::{check_display_changed, get_display_info}, service::ServiceTmpl, @@ -28,6 +26,8 @@ use super::{ }; #[cfg(target_os = "linux")] use crate::common::SimpleCallOnReturn; +#[cfg(target_os = "linux")] +use crate::platform::linux::is_x11; #[cfg(windows)] use crate::{platform::windows::is_process_consent_running, privacy_win_mag}; use hbb_common::{ @@ -46,8 +46,6 @@ use scrap::{ vpxcodec::{VpxEncoderConfig, VpxVideoCodecId}, CodecName, Display, TraitCapturer, }; -#[cfg(target_os = "linux")] -use std::sync::atomic::Ordering; #[cfg(windows)] use std::sync::Once; use std::{ @@ -329,7 +327,7 @@ fn get_capturer( ) -> ResultType { #[cfg(target_os = "linux")] { - if !IS_X11.load(Ordering::SeqCst) { + if !is_x11() { return super::wayland::get_capturer(); } } @@ -571,7 +569,7 @@ fn run(vs: VideoService) -> ResultType<()> { #[cfg(target_os = "linux")] { would_block_count += 1; - if !IS_X11.load(Ordering::SeqCst) { + if !is_x11() { if would_block_count >= 100 { // to-do: Unknown reason for WouldBlock 100 times (seconds = 100 * 1 / fps) // https://github.com/rustdesk/rustdesk/blob/63e6b2f8ab51743e77a151e2b7ff18816f5fa2fb/libs/scrap/src/common/wayland.rs#L81 @@ -751,7 +749,7 @@ fn handle_one_frame( pub fn is_inited_msg() -> Option { #[cfg(target_os = "linux")] - if !IS_X11.load(Ordering::SeqCst) { + if !is_x11() { return super::wayland::is_inited(); } None diff --git a/src/server/wayland.rs b/src/server/wayland.rs index 38edc4472..f869266bc 100644 --- a/src/server/wayland.rs +++ b/src/server/wayland.rs @@ -4,8 +4,11 @@ use scrap::{is_cursor_embedded, set_map_err, Capturer, Display, Frame, TraitCapt use std::io; use std::process::{Command, Output}; -use crate::client::{ - SCRAP_OTHER_VERSION_OR_X11_REQUIRED, SCRAP_UBUNTU_HIGHER_REQUIRED, SCRAP_X11_REQUIRED, +use crate::{ + client::{ + SCRAP_OTHER_VERSION_OR_X11_REQUIRED, SCRAP_UBUNTU_HIGHER_REQUIRED, SCRAP_X11_REQUIRED, + }, + platform::linux::is_x11, }; lazy_static::lazy_static! { @@ -96,7 +99,7 @@ pub(super) async fn ensure_inited() -> ResultType<()> { } pub(super) fn is_inited() -> Option { - if scrap::is_x11() { + if is_x11() { None } else { if *CAP_DISPLAY_INFO.read().unwrap() == 0 { @@ -133,7 +136,7 @@ fn get_max_desktop_resolution() -> Option { } pub(super) async fn check_init() -> ResultType<()> { - if !scrap::is_x11() { + if !is_x11() { let mut minx = 0; let mut maxx = 0; let mut miny = 0; @@ -246,7 +249,7 @@ pub(super) fn get_primary() -> ResultType { } pub fn clear() { - if scrap::is_x11() { + if is_x11() { return; } let mut write_lock = CAP_DISPLAY_INFO.write().unwrap(); @@ -261,7 +264,7 @@ pub fn clear() { } pub(super) fn get_capturer() -> ResultType { - if scrap::is_x11() { + if is_x11() { bail!("Do not call this function if not wayland"); } let addr = *CAP_DISPLAY_INFO.read().unwrap(); From c268a0ab145fabff8c08ab3a2736b54cfd730a7d Mon Sep 17 00:00:00 2001 From: 21pages Date: Sat, 21 Oct 2023 15:25:01 +0800 Subject: [PATCH 072/114] show reconnect timeout and dismiss all dialog when show reconnecting Signed-off-by: 21pages --- flutter/lib/common.dart | 82 ++++++++++++++++++++++++++++------- flutter/lib/models/model.dart | 5 ++- 2 files changed, 71 insertions(+), 16 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 834b3bec3..0ab790720 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -958,7 +958,7 @@ class CustomAlertDialog extends StatelessWidget { void msgBox(SessionID sessionId, String type, String title, String text, String link, OverlayDialogManager dialogManager, - {bool? hasCancel, ReconnectHandle? reconnect}) { + {bool? hasCancel, ReconnectHandle? reconnect, int? reconnectTimeout}) { dialogManager.dismissAll(); List buttons = []; bool hasOk = false; @@ -998,22 +998,21 @@ void msgBox(SessionID sessionId, String type, String title, String text, dialogManager.dismissAll(); })); } - if (reconnect != null && title == "Connection Error") { + if (reconnect != null && + title == "Connection Error" && + reconnectTimeout != null) { // `enabled` is used to disable the dialog button once the button is clicked. final enabled = true.obs; - final button = Obx( - () => dialogButton( - 'Reconnect', - isOutline: true, - onPressed: enabled.isTrue - ? () { - // Disable the button - enabled.value = false; - reconnect(dialogManager, sessionId, false); - } - : null, - ), - ); + final button = Obx(() => _ReconnectCountDownButton( + second: reconnectTimeout, + onPressed: enabled.isTrue + ? () { + // Disable the button + enabled.value = false; + reconnect(dialogManager, sessionId, false); + } + : null, + )); buttons.insert(0, button); } if (link.isNotEmpty) { @@ -2745,3 +2744,56 @@ parseParamScreenRect(Map params) { } return screenRect; } + +class _ReconnectCountDownButton extends StatefulWidget { + _ReconnectCountDownButton({ + Key? key, + required this.second, + required this.onPressed, + }) : super(key: key); + final VoidCallback? onPressed; + final int second; + + @override + State<_ReconnectCountDownButton> createState() => + _ReconnectCountDownButtonState(); +} + +class _ReconnectCountDownButtonState extends State<_ReconnectCountDownButton> { + late int _countdownSeconds = widget.second; + + Timer? _timer; + + @override + void initState() { + super.initState(); + _startCountdownTimer(); + } + + @override + void dispose() { + _timer?.cancel(); + super.dispose(); + } + + void _startCountdownTimer() { + _timer = Timer.periodic(Duration(seconds: 1), (timer) { + if (_countdownSeconds <= 0) { + timer.cancel(); + } else { + setState(() { + _countdownSeconds--; + }); + } + }); + } + + @override + Widget build(BuildContext context) { + return dialogButton( + '${translate('Reconnect')} (${_countdownSeconds}s)', + onPressed: widget.onPressed, + isOutline: true, + ); + } +} diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 433d3c2d4..0d257eaf0 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -512,7 +512,9 @@ class FfiModel with ChangeNotifier { String link, bool hasRetry, OverlayDialogManager dialogManager, {bool? hasCancel}) { msgBox(sessionId, type, title, text, link, dialogManager, - hasCancel: hasCancel, reconnect: reconnect); + hasCancel: hasCancel, + reconnect: reconnect, + reconnectTimeout: hasRetry ? _reconnects : null); _timer?.cancel(); if (hasRetry) { _timer = Timer(Duration(seconds: _reconnects), () { @@ -528,6 +530,7 @@ class FfiModel with ChangeNotifier { bool forceRelay) { bind.sessionReconnect(sessionId: sessionId, forceRelay: forceRelay); clearPermissions(); + dialogManager.dismissAll(); dialogManager.showLoading(translate('Connecting...'), onCancel: closeConnection); } From f531cd23ee0a68976f6d9c35ac71dd88ce362610 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sat, 21 Oct 2023 23:24:54 +0800 Subject: [PATCH 073/114] add selinux tip Signed-off-by: fufesou --- Cargo.lock | 164 +++++++++++++----- Cargo.toml | 1 + .../lib/desktop/pages/connection_page.dart | 7 +- .../lib/desktop/pages/desktop_home_page.dart | 49 ++++-- src/flutter_ffi.rs | 11 ++ src/lang/ar.rs | 1 + src/lang/ca.rs | 1 + src/lang/cn.rs | 1 + src/lang/cs.rs | 1 + src/lang/da.rs | 1 + src/lang/de.rs | 1 + src/lang/el.rs | 1 + src/lang/en.rs | 1 + src/lang/eo.rs | 1 + src/lang/es.rs | 1 + src/lang/fa.rs | 1 + src/lang/fr.rs | 1 + src/lang/hu.rs | 1 + src/lang/id.rs | 1 + src/lang/it.rs | 2 +- src/lang/ja.rs | 1 + src/lang/ko.rs | 1 + src/lang/kz.rs | 1 + src/lang/lt.rs | 1 + src/lang/lv.rs | 1 + src/lang/nl.rs | 1 + src/lang/pl.rs | 1 + src/lang/pt_PT.rs | 1 + src/lang/ptbr.rs | 1 + src/lang/ro.rs | 1 + src/lang/ru.rs | 1 + src/lang/sk.rs | 1 + src/lang/sl.rs | 1 + src/lang/sq.rs | 1 + src/lang/sr.rs | 1 + src/lang/sv.rs | 1 + src/lang/template.rs | 1 + src/lang/th.rs | 1 + src/lang/tr.rs | 1 + src/lang/tw.rs | 1 + src/lang/ua.rs | 1 + src/lang/vn.rs | 1 + src/platform/linux.rs | 8 + 43 files changed, 216 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b606cdb21..b93fa4752 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,7 +83,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8512c9117059663fb5606788fbca3619e2a91dac0e3fe516242eab1fa6be5e44" dependencies = [ "alsa-sys", - "bitflags", + "bitflags 1.3.2", "libc", "nix 0.24.3", ] @@ -375,7 +375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39991bc421ddf72f70159011b323ff49b0f783cc676a7287c59453da2e2531cf" dependencies = [ "atk-sys", - "bitflags", + "bitflags 1.3.2", "glib 0.16.7", "libc", ] @@ -466,7 +466,7 @@ version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "clap 2.34.0", @@ -489,7 +489,7 @@ version = "0.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -511,7 +511,7 @@ version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -531,7 +531,30 @@ version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ - "bitflags", + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2 1.0.63", + "quote 1.0.27", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.15", + "which", +] + +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags 2.4.1", "cexpr", "clang-sys", "lazy_static", @@ -560,6 +583,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "bitvec" version = "1.0.1" @@ -683,7 +712,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3125b15ec28b84c238f6f476c6034016a5f6cc0221cb514ca46c532139fc97d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-sys-rs", "glib 0.16.7", "libc", @@ -854,7 +883,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.3.2", "strsim 0.8.0", "textwrap 0.11.0", "unicode-width", @@ -868,7 +897,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_lex 0.2.4", "indexmap", "strsim 0.10.0", @@ -895,7 +924,7 @@ checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd" dependencies = [ "anstream", "anstyle", - "bitflags", + "bitflags 1.3.2", "clap_lex 0.4.1", "strsim 0.10.0", ] @@ -956,7 +985,7 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -974,7 +1003,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "cocoa-foundation", "core-foundation", @@ -990,7 +1019,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "core-foundation", "core-graphics-types", @@ -1144,7 +1173,7 @@ version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-graphics-types", "foreign-types", @@ -1157,7 +1186,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "foreign-types", "libc", @@ -1169,7 +1198,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb17e2d1795b1996419648915df94bc7103c28f7b48062d7acf4652fc371b2ff" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation-sys 0.6.2", "coreaudio-sys", ] @@ -1753,6 +1782,12 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + [[package]] name = "dylib_virtual_display" version = "0.1.0" @@ -1933,7 +1968,7 @@ version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", ] @@ -2331,7 +2366,7 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9cb33da481c6c040404a11f8212d193889e9b435db2c14fd86987f630d3ce1" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "gdk-pixbuf", "gdk-sys", @@ -2347,7 +2382,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3578c60dee9d029ad86593ed88cb40f35c1b83360e12498d055022385dd9a05" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gdk-pixbuf-sys", "gio", "glib 0.16.7", @@ -2466,7 +2501,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a1c84b4534a290a29160ef5c6eff2a9c95833111472e824fc5cb78b513dd092" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-io", @@ -2499,7 +2534,7 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "libgit2-sys", "log", @@ -2512,7 +2547,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-executor", @@ -2531,7 +2566,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddd4df61a866ed7259d6189b8bcb1464989a77f1d85d25d002279bbe9dd38b2f" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-executor", @@ -2632,7 +2667,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ff5d0f7ff308ae37e6eb47b6ded17785bdea06e438a708cd09e0288c1862f33" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "futures-channel", "futures-core", @@ -2656,7 +2691,7 @@ version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc80888271338c3ede875d8cafc452eb207476ff5539dcbe0018a8f5b827af0e" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-core", "futures-sink", "glib 0.10.3", @@ -2689,7 +2724,7 @@ version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bafd01c56f59cb10f4b5a10f97bb4bdf8c2b2784ae5b04da7e2d400cf6e6afcf" dependencies = [ - "bitflags", + "bitflags 1.3.2", "glib 0.10.3", "glib-sys 0.10.1", "gobject-sys 0.10.0", @@ -2730,7 +2765,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7bbb1485d87469849ec45c08e03c2f280d3ea20ff3c439d03185be54e3ce98e" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-util", "glib 0.10.3", @@ -2766,7 +2801,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4d3507d43908c866c805f74c9dd593c0ce7ba5c38e576e41846639cdcd4bee6" dependencies = [ "atk", - "bitflags", + "bitflags 1.3.2", "cairo-rs", "field-offset", "futures-channel", @@ -3140,7 +3175,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abf888f9575c290197b2c948dc9e9ff10bd1a39ad1ea8585f734585fa6b9d3f9" dependencies = [ - "bitflags", + "bitflags 1.3.2", "inotify-sys", "libc", ] @@ -3336,7 +3371,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7668b7cff6a51fe61cdde64cd27c8a220786f399501b57ebe36f7d8112fd68" dependencies = [ - "bitflags", + "bitflags 1.3.2", "serde 1.0.163", "unicode-segmentation", ] @@ -3442,7 +3477,7 @@ version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1745b20bfc194ac12ef828f144f0ec2d4a7fe993281fa3567a0bd4969aee6890" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "libpulse-sys", "num-derive", @@ -3779,7 +3814,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" dependencies = [ - "bitflags", + "bitflags 1.3.2", "jni-sys", "ndk-sys", "num_enum", @@ -3821,7 +3856,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea993e32c77d87f01236c38f572ecb6c311d592e56a06262a007fd2a6e31253c" dependencies = [ "anyhow", - "bitflags", + "bitflags 1.3.2", "byteorder", "libc", "netlink-packet-core", @@ -3857,7 +3892,7 @@ version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cc", "cfg-if 1.0.0", "libc", @@ -3870,7 +3905,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "libc", "memoffset 0.6.5", @@ -3882,7 +3917,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "libc", "memoffset 0.7.1", @@ -4121,9 +4156,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opaque-debug" @@ -4236,7 +4271,7 @@ version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdff66b271861037b89d028656184059e03b0b6ccb36003820be19f7200b1e94" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gio", "glib 0.16.7", "libc", @@ -4442,7 +4477,7 @@ version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", @@ -4456,7 +4491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg 1.1.0", - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "concurrent-queue", "libc", @@ -4935,7 +4970,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -4944,7 +4979,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -4958,6 +4993,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "reference-counted-singleton" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bfbf25d7eb88ddcbb1ec3d755d0634da8f7657b2cb8b74089121409ab8228f" + [[package]] name = "regex" version = "1.8.1" @@ -5207,6 +5248,7 @@ dependencies = [ "samplerate", "sciter-rs", "scrap", + "selinux", "serde 1.0.163", "serde_derive", "serde_json 1.0.96", @@ -5265,7 +5307,7 @@ version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -5442,7 +5484,7 @@ version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys 0.8.4", "libc", @@ -5459,6 +5501,32 @@ dependencies = [ "libc", ] +[[package]] +name = "selinux" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80b091d970bd4a17a59cb1b7c537786f2bee4292abb5ec89ee3b7f17e9077138" +dependencies = [ + "bitflags 2.4.1", + "libc", + "once_cell", + "reference-counted-singleton", + "selinux-sys", + "thiserror", +] + +[[package]] +name = "selinux-sys" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56602385930248c57e45f6174a6a48e12b723d0cc2ae8f467fcbe80c0d06f41" +dependencies = [ + "bindgen 0.66.1", + "cc", + "dunce", + "walkdir", +] + [[package]] name = "semver" version = "1.0.17" @@ -5858,7 +5926,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75182f12f490e953596550b65ee31bda7c8e043d9386174b353bda50838c3fd" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "system-configuration-sys", ] @@ -5916,7 +5984,7 @@ name = "tao" version = "0.22.2" source = "git+https://github.com/rustdesk-org/tao?branch=dev#1e5b97258cf42a30f80f85a6aa0b1a4aece1977e" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "cc", "cocoa", @@ -6935,7 +7003,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd9db37ecb5b13762d95468a2fc6009d4b2c62801243223aabd44fca13ad13c8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "widestring", "windows-sys 0.45.0", ] diff --git a/Cargo.toml b/Cargo.toml index f6c014483..711a1caca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,7 @@ dbus = "0.9" dbus-crossroads = "0.5" pam = { git="https://github.com/fufesou/pam", optional = true } users = { version = "0.11" } +selinux = "0.4.2" [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.13" diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 859fd0d70..272fd7c7b 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -37,7 +37,6 @@ class _ConnectionPageState extends State Timer? _updateTimer; final RxBool _idInputFocused = false.obs; - final FocusNode _idFocusNode = FocusNode(); var svcStopped = Get.find(tag: 'stop-service'); var svcIsUsingPublicServer = true.obs; @@ -334,8 +333,10 @@ class _ConnectionPageState extends State optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { double maxHeight = 0; for (var peer in options) { - if (maxHeight < 200) - maxHeight += 50; }; + if (maxHeight < 200) { + maxHeight += 50; + } + } return Align( alignment: Alignment.topLeft, child: ClipRRect( diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 8633af1d3..74002dfc2 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -378,16 +378,36 @@ class _DesktopHomePageState extends State // }); // } } else if (Platform.isLinux) { + final LinuxCards = []; if (bind.mainCurrentIsWayland()) { - return buildInstallCard( + LinuxCards.add(buildInstallCard( "Warning", "wayland_experiment_tip", "", () async {}, help: 'Help', - link: 'https://rustdesk.com/docs/en/manual/linux/#x11-required'); + link: 'https://rustdesk.com/docs/en/manual/linux/#x11-required')); } else if (bind.mainIsLoginWayland()) { - return buildInstallCard("Warning", + LinuxCards.add(buildInstallCard("Warning", "Login screen using Wayland is not supported", "", () async {}, help: 'Help', - link: 'https://rustdesk.com/docs/en/manual/linux/#login-screen'); + link: 'https://rustdesk.com/docs/en/manual/linux/#login-screen')); + } + if (bind.isSelinuxEnabled()) { + final keyShowSelinuxHelpTip = "show-selinux-help-tip"; + if (bind.mainGetLocalOption(key: keyShowSelinuxHelpTip) != 'N') { + LinuxCards.add(buildInstallCard( + "Warning", "selinux_tip", "", () async {}, + marginTop: LinuxCards.isEmpty ? 20.0 : 5.0, + help: 'Help', + link: + 'https://rustdesk.com/docs/en/client/linux/#permissions-issue', + closeButton: true, + closeOption: keyShowSelinuxHelpTip, + )); + } + } + if (LinuxCards.isNotEmpty) { + return Column( + children: LinuxCards, + ); } } return Container(); @@ -395,17 +415,26 @@ class _DesktopHomePageState extends State Widget buildInstallCard(String title, String content, String btnText, GestureTapCallback onPressed, - {String? help, String? link, bool? closeButton}) { - void closeCard() { - setState(() { - isCardClosed = true; - }); + {double marginTop = 20.0, String? help, String? link, bool? closeButton, String? closeOption}) { + void closeCard() async { + if (closeOption != null) { + await bind.mainSetLocalOption(key: closeOption, value: 'N'); + if (bind.mainGetLocalOption(key: closeOption) == 'N') { + setState(() { + isCardClosed = true; + }); + } + } else { + setState(() { + isCardClosed = true; + }); + } } return Stack( children: [ Container( - margin: EdgeInsets.only(top: 20), + margin: EdgeInsets.only(top: marginTop), child: Container( decoration: BoxDecoration( gradient: LinearGradient( diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index efd2a3e82..7e1aa44e4 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1935,6 +1935,17 @@ pub fn is_support_multi_ui_session(version: String) -> SyncReturn { SyncReturn(crate::common::is_support_multi_ui_session(&version)) } +pub fn is_selinux_enabled() -> SyncReturn { + #[cfg(target_os = "linux")] + { + SyncReturn(crate::platform::linux::is_selinux_enabled()) + } + #[cfg(not(target_os = "linux"))] + { + SyncReturn(false) + } +} + #[cfg(target_os = "android")] pub mod server_side { use hbb_common::{config, log}; diff --git a/src/lang/ar.rs b/src/lang/ar.rs index 4b80047d5..425f49d3a 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index bd62b21c7..8057430e5 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 2893eb9a5..0a4f5beea 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "在新的窗口中打开"), ("Show displays as individual windows", "在单个窗口中打开显示器"), ("Use all my displays for the remote session", "将我的所有显示器用于远程会话"), + ("selinux_tip", "SELinux 处于启用状态,RustDesk 可能无法正常运行。"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 00eb95248..c7e620665 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Otevřít v novém okně"), ("Show displays as individual windows", "Zobrazit obrazovky jako jednotlivá okna"), ("Use all my displays for the remote session", "Použít všechny mé obrazovky pro vzdálenou relaci"), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 2f1076fd1..634c7e8a9 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index b15023495..6b5beb305 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "In einem neuen Fenster öffnen"), ("Show displays as individual windows", "Jeden Bildschirm in einem eigenen Fenster anzeigen"), ("Use all my displays for the remote session", "Alle meine Bildschirme für die Fernsitzung verwenden"), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index 940889e16..baf16f82e 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/en.rs b/src/lang/en.rs index 56dc8a122..6dc185f99 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -225,5 +225,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("switch_display_elevated_connections_tip", "Switching to non-primary display is not supported in the elevated mode when there are multiple connections. Please try again after installation if you want to control multiple displays."), ("display_is_plugged_out_msg", "The display is plugged out, switch to the first display."), ("elevated_switch_display_msg", "Switch to the primary display because multiple displays are not supported in elevated mode."), + ("selinux_tip", "SELinux is enabled on your device, which may prevent RustDesk from running properly."), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 8685fa567..5c3c3eec1 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 093298835..426e80a8e 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Abrir en una nueva ventana"), ("Show displays as individual windows", "Mostrar pantallas como ventanas individuales"), ("Use all my displays for the remote session", "Usar todas mis pantallas para la sesión remota"), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 845cb1868..28acc2c13 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 9f1954f7d..a2bc13a77 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 882663b7e..e56cad01e 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 21ba8a86a..f0306b962 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Buka di jendela baru"), ("Show displays as individual windows", "Tampilkan dengan jendela terpisah"), ("Use all my displays for the remote session", "Gunakan semua layar untuk sesi remote"), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 617e0f0c5..738dfa79e 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -365,7 +365,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Audio Input Device", "Dispositivo ingresso audio"), ("Use IP Whitelisting", "Usa elenco IP autorizzati"), ("Network", "Rete"), - ("Enable RDP", "Abilita RDP"), ("Pin Toolbar", "Blocca barra strumenti"), ("Unpin Toolbar", "Sblocca barra strumenti"), ("Recording", "Registrazione"), @@ -566,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Apri in una nuova finestra"), ("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"), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 059b355db..51496107f 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 0a7affb3b..49cfd2931 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 73fc04469..5fc4a4795 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 39747e0d4..2c3551989 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index 6dd5a2b0b..d7783e052 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Atvērt jaunā logā"), ("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"), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 7a8189682..0365206a9 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Open in een nieuw venster"), ("Show displays as individual windows", "Beeldschermen weergeven als afzonderlijke vensters"), ("Use all my displays for the remote session", "Gebruik al mijn beeldschermen voor de externe sessie"), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 91c508aaa..f82cd4588 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Otwórz w nowym oknie"), ("Show displays as individual windows", "Pokaż ekrany w osobnych oknach"), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 9c3c01660..979add253 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 9b052947f..fac32ccf1 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 61d44813d..83392ed77 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index af7bf5cf3..82c9a9601 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Открыть в новом окне"), ("Show displays as individual windows", "Показывать дисплеи в отдельных окнах"), ("Use all my displays for the remote session", "Использовать все мои дисплеи для удалённого сеанса"), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index b124aed71..07029c213 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index e1bf2ab8e..83594ea75 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index 1d9b218a6..f9f49345d 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 754192fc3..956be5e33 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 007e180bb..7a1faa19a 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index f14c3e206..6b6f28e5f 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index bb13d82b6..89b753bc6 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 394b9bca9..b1f3f3cd2 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index cdc900ae2..cb7d7516a 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 02c4e2349..05a74f633 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Відкрити в новому вікні"), ("Show displays as individual windows", "Відображати дисплеї в якості окремих вікон"), ("Use all my displays for the remote session", "Використовувати всі мої дисплеї для віддаленого сеансу"), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 0e0cf6a05..9c259b8fa 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -565,5 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", ""), ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), + ("selinux_tip", ""), ].iter().cloned().collect(); } diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 87dc8d071..bb3474d41 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -1369,3 +1369,11 @@ impl Drop for WallPaperRemover { pub fn is_x11() -> bool { *IS_X11 } + +#[inline] +pub fn is_selinux_enabled() -> bool { + match selinux::kernel_support() { + selinux::KernelSupport::Unsupported => false, + _ => selinux::current_mode() == selinux::SELinuxMode::Enforcing, + } +} From 827c32fafd7c5373f664a9edf36dbd44fabbe885 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 22 Oct 2023 10:56:41 +0800 Subject: [PATCH 074/114] add deps Signed-off-by: fufesou --- .github/workflows/flutter-build.yml | 16 ++++++------- .../lib/desktop/pages/desktop_home_page.dart | 24 ++++++++++--------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/.github/workflows/flutter-build.yml b/.github/workflows/flutter-build.yml index 2aa6e564a..7761518e7 100644 --- a/.github/workflows/flutter-build.yml +++ b/.github/workflows/flutter-build.yml @@ -526,7 +526,7 @@ jobs: - name: Install dependencies run: | sudo apt update - sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ libc6-dev gcc-multilib g++-multilib openjdk-11-jdk-headless + sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ libc6-dev gcc-multilib g++-multilib openjdk-11-jdk-headless libselinux1-dev - name: Checkout source code uses: actions/checkout@v3 - name: Install flutter @@ -760,7 +760,7 @@ jobs: install: | apt update -y echo -e "installing deps" - apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ gcc libvpx-dev tree > /dev/null + apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ gcc libvpx-dev tree libselinux1-dev > /dev/null # we have libopus compiled by us. apt remove -y libopus-dev || true # output devs @@ -909,7 +909,7 @@ jobs: install: | apt update -y echo -e "installing deps" - apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ gcc libvpx-dev tree > /dev/null + apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ gcc libvpx-dev tree libselinux1-dev > /dev/null # we have libopus compiled by us. apt remove -y libopus-dev || true # output devs @@ -1028,7 +1028,7 @@ jobs: apt update -y apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm libclang-dev apt-get -qq install -y libdbus-1-dev pkg-config nasm yasm libglib2.0-dev libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev - apt-get -qq install -y libpulse-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvpx-dev libvdpau-dev libva-dev libpam0g-dev + apt-get -qq install -y libpulse-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvpx-dev libvdpau-dev libva-dev libpam0g-dev libselinux1-dev run: | # disable git safe.directory git config --global --add safe.directory "*" @@ -1134,7 +1134,7 @@ jobs: - name: Prepare env run: | sudo apt update -y - sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev libarchive-tools + sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev libarchive-tools libselinux1-dev mkdir -p ./target/release/ - name: Restore the rustdesk lib file @@ -1172,7 +1172,7 @@ jobs: shell: /bin/bash install: | apt update -y - apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm + apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm libselinux1-dev run: | # disable git safe.directory git config --global --add safe.directory "*" @@ -1394,7 +1394,7 @@ jobs: - name: Prepare env run: | sudo apt update -y - sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev libarchive-tools + sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev libarchive-tools libselinux1-dev mkdir -p ./target/release/ - name: Restore the rustdesk lib file @@ -1418,7 +1418,7 @@ jobs: shell: /bin/bash install: | apt update -y - apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm + apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm libselinux1-dev run: | # disable git safe.directory git config --global --add safe.directory "*" diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 74002dfc2..def0d8453 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -379,17 +379,6 @@ class _DesktopHomePageState extends State // } } else if (Platform.isLinux) { final LinuxCards = []; - if (bind.mainCurrentIsWayland()) { - LinuxCards.add(buildInstallCard( - "Warning", "wayland_experiment_tip", "", () async {}, - help: 'Help', - link: 'https://rustdesk.com/docs/en/manual/linux/#x11-required')); - } else if (bind.mainIsLoginWayland()) { - LinuxCards.add(buildInstallCard("Warning", - "Login screen using Wayland is not supported", "", () async {}, - help: 'Help', - link: 'https://rustdesk.com/docs/en/manual/linux/#login-screen')); - } if (bind.isSelinuxEnabled()) { final keyShowSelinuxHelpTip = "show-selinux-help-tip"; if (bind.mainGetLocalOption(key: keyShowSelinuxHelpTip) != 'N') { @@ -404,6 +393,19 @@ class _DesktopHomePageState extends State )); } } + if (bind.mainCurrentIsWayland()) { + LinuxCards.add(buildInstallCard( + "Warning", "wayland_experiment_tip", "", () async {}, + marginTop: LinuxCards.isEmpty ? 20.0 : 5.0, + help: 'Help', + link: 'https://rustdesk.com/docs/en/manual/linux/#x11-required')); + } else if (bind.mainIsLoginWayland()) { + LinuxCards.add(buildInstallCard("Warning", + "Login screen using Wayland is not supported", "", () async {}, + marginTop: LinuxCards.isEmpty ? 20.0 : 5.0, + help: 'Help', + link: 'https://rustdesk.com/docs/en/manual/linux/#login-screen')); + } if (LinuxCards.isNotEmpty) { return Column( children: LinuxCards, From 842255766fcffe189fc72b6b496cbe9137474557 Mon Sep 17 00:00:00 2001 From: RustDesk <71636191+rustdesk@users.noreply.github.com> Date: Sun, 22 Oct 2023 13:05:37 +0800 Subject: [PATCH 075/114] Update en.rs --- src/lang/en.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/en.rs b/src/lang/en.rs index 6dc185f99..209772ccc 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -225,6 +225,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("switch_display_elevated_connections_tip", "Switching to non-primary display is not supported in the elevated mode when there are multiple connections. Please try again after installation if you want to control multiple displays."), ("display_is_plugged_out_msg", "The display is plugged out, switch to the first display."), ("elevated_switch_display_msg", "Switch to the primary display because multiple displays are not supported in elevated mode."), - ("selinux_tip", "SELinux is enabled on your device, which may prevent RustDesk from running properly."), + ("selinux_tip", "SELinux is enabled on your device, which may prevent RustDesk from running properly as controlled side."), ].iter().cloned().collect(); } From 4633a0450cb22c777fcc14c743e789892f7ec73d Mon Sep 17 00:00:00 2001 From: RustDesk <71636191+rustdesk@users.noreply.github.com> Date: Sun, 22 Oct 2023 13:06:17 +0800 Subject: [PATCH 076/114] Update cn.rs --- src/lang/cn.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 0a4f5beea..0be9738e8 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -565,6 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "在新的窗口中打开"), ("Show displays as individual windows", "在单个窗口中打开显示器"), ("Use all my displays for the remote session", "将我的所有显示器用于远程会话"), - ("selinux_tip", "SELinux 处于启用状态,RustDesk 可能无法正常运行。"), + ("selinux_tip", "SELinux 处于启用状态,RustDesk 可能无法作为被控正常运行。"), ].iter().cloned().collect(); } From 5c23dfd63333524fb17c249db803ecaa4ca6099f Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 22 Oct 2023 14:22:15 +0800 Subject: [PATCH 077/114] selinux tip, remove rust dep 'selinux' Signed-off-by: fufesou --- .github/workflows/flutter-build.yml | 16 +- Cargo.lock | 160 +++++------------- Cargo.toml | 1 - .../lib/desktop/pages/desktop_home_page.dart | 3 +- src/flutter_ffi.rs | 4 +- src/platform/linux.rs | 18 +- 6 files changed, 72 insertions(+), 130 deletions(-) diff --git a/.github/workflows/flutter-build.yml b/.github/workflows/flutter-build.yml index 7761518e7..2aa6e564a 100644 --- a/.github/workflows/flutter-build.yml +++ b/.github/workflows/flutter-build.yml @@ -526,7 +526,7 @@ jobs: - name: Install dependencies run: | sudo apt update - sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ libc6-dev gcc-multilib g++-multilib openjdk-11-jdk-headless libselinux1-dev + sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ libc6-dev gcc-multilib g++-multilib openjdk-11-jdk-headless - name: Checkout source code uses: actions/checkout@v3 - name: Install flutter @@ -760,7 +760,7 @@ jobs: install: | apt update -y echo -e "installing deps" - apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ gcc libvpx-dev tree libselinux1-dev > /dev/null + apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ gcc libvpx-dev tree > /dev/null # we have libopus compiled by us. apt remove -y libopus-dev || true # output devs @@ -909,7 +909,7 @@ jobs: install: | apt update -y echo -e "installing deps" - apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ gcc libvpx-dev tree libselinux1-dev > /dev/null + apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libpam0g-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ gcc libvpx-dev tree > /dev/null # we have libopus compiled by us. apt remove -y libopus-dev || true # output devs @@ -1028,7 +1028,7 @@ jobs: apt update -y apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm libclang-dev apt-get -qq install -y libdbus-1-dev pkg-config nasm yasm libglib2.0-dev libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev - apt-get -qq install -y libpulse-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvpx-dev libvdpau-dev libva-dev libpam0g-dev libselinux1-dev + apt-get -qq install -y libpulse-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvpx-dev libvdpau-dev libva-dev libpam0g-dev run: | # disable git safe.directory git config --global --add safe.directory "*" @@ -1134,7 +1134,7 @@ jobs: - name: Prepare env run: | sudo apt update -y - sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev libarchive-tools libselinux1-dev + sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev libarchive-tools mkdir -p ./target/release/ - name: Restore the rustdesk lib file @@ -1172,7 +1172,7 @@ jobs: shell: /bin/bash install: | apt update -y - apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm libselinux1-dev + apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm run: | # disable git safe.directory git config --global --add safe.directory "*" @@ -1394,7 +1394,7 @@ jobs: - name: Prepare env run: | sudo apt update -y - sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev libarchive-tools libselinux1-dev + sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev libarchive-tools mkdir -p ./target/release/ - name: Restore the rustdesk lib file @@ -1418,7 +1418,7 @@ jobs: shell: /bin/bash install: | apt update -y - apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm libselinux1-dev + apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm run: | # disable git safe.directory git config --global --add safe.directory "*" diff --git a/Cargo.lock b/Cargo.lock index b93fa4752..4e34f5bb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,7 +83,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8512c9117059663fb5606788fbca3619e2a91dac0e3fe516242eab1fa6be5e44" dependencies = [ "alsa-sys", - "bitflags 1.3.2", + "bitflags", "libc", "nix 0.24.3", ] @@ -375,7 +375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39991bc421ddf72f70159011b323ff49b0f783cc676a7287c59453da2e2531cf" dependencies = [ "atk-sys", - "bitflags 1.3.2", + "bitflags", "glib 0.16.7", "libc", ] @@ -466,7 +466,7 @@ version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cexpr", "clang-sys", "clap 2.34.0", @@ -489,7 +489,7 @@ version = "0.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cexpr", "clang-sys", "lazy_static", @@ -511,7 +511,7 @@ version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cexpr", "clang-sys", "lazy_static", @@ -531,30 +531,7 @@ version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "prettyplease", - "proc-macro2 1.0.63", - "quote 1.0.27", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.15", - "which", -] - -[[package]] -name = "bindgen" -version = "0.66.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" -dependencies = [ - "bitflags 2.4.1", + "bitflags", "cexpr", "clang-sys", "lazy_static", @@ -583,12 +560,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - [[package]] name = "bitvec" version = "1.0.1" @@ -712,7 +683,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3125b15ec28b84c238f6f476c6034016a5f6cc0221cb514ca46c532139fc97d" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cairo-sys-rs", "glib 0.16.7", "libc", @@ -883,7 +854,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags 1.3.2", + "bitflags", "strsim 0.8.0", "textwrap 0.11.0", "unicode-width", @@ -897,7 +868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", - "bitflags 1.3.2", + "bitflags", "clap_lex 0.2.4", "indexmap", "strsim 0.10.0", @@ -924,7 +895,7 @@ checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd" dependencies = [ "anstream", "anstyle", - "bitflags 1.3.2", + "bitflags", "clap_lex 0.4.1", "strsim 0.10.0", ] @@ -985,7 +956,7 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -1003,7 +974,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" dependencies = [ - "bitflags 1.3.2", + "bitflags", "block", "cocoa-foundation", "core-foundation", @@ -1019,7 +990,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" dependencies = [ - "bitflags 1.3.2", + "bitflags", "block", "core-foundation", "core-graphics-types", @@ -1173,7 +1144,7 @@ version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "core-graphics-types", "foreign-types", @@ -1186,7 +1157,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "foreign-types", "libc", @@ -1198,7 +1169,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb17e2d1795b1996419648915df94bc7103c28f7b48062d7acf4652fc371b2ff" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation-sys 0.6.2", "coreaudio-sys", ] @@ -1782,12 +1753,6 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" -[[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - [[package]] name = "dylib_virtual_display" version = "0.1.0" @@ -1968,7 +1933,7 @@ version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0" dependencies = [ - "bitflags 1.3.2", + "bitflags", "libc", ] @@ -2366,7 +2331,7 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9cb33da481c6c040404a11f8212d193889e9b435db2c14fd86987f630d3ce1" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cairo-rs", "gdk-pixbuf", "gdk-sys", @@ -2382,7 +2347,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3578c60dee9d029ad86593ed88cb40f35c1b83360e12498d055022385dd9a05" dependencies = [ - "bitflags 1.3.2", + "bitflags", "gdk-pixbuf-sys", "gio", "glib 0.16.7", @@ -2501,7 +2466,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a1c84b4534a290a29160ef5c6eff2a9c95833111472e824fc5cb78b513dd092" dependencies = [ - "bitflags 1.3.2", + "bitflags", "futures-channel", "futures-core", "futures-io", @@ -2534,7 +2499,7 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" dependencies = [ - "bitflags 1.3.2", + "bitflags", "libc", "libgit2-sys", "log", @@ -2547,7 +2512,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5" dependencies = [ - "bitflags 1.3.2", + "bitflags", "futures-channel", "futures-core", "futures-executor", @@ -2566,7 +2531,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddd4df61a866ed7259d6189b8bcb1464989a77f1d85d25d002279bbe9dd38b2f" dependencies = [ - "bitflags 1.3.2", + "bitflags", "futures-channel", "futures-core", "futures-executor", @@ -2667,7 +2632,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ff5d0f7ff308ae37e6eb47b6ded17785bdea06e438a708cd09e0288c1862f33" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cfg-if 1.0.0", "futures-channel", "futures-core", @@ -2691,7 +2656,7 @@ version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc80888271338c3ede875d8cafc452eb207476ff5539dcbe0018a8f5b827af0e" dependencies = [ - "bitflags 1.3.2", + "bitflags", "futures-core", "futures-sink", "glib 0.10.3", @@ -2724,7 +2689,7 @@ version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bafd01c56f59cb10f4b5a10f97bb4bdf8c2b2784ae5b04da7e2d400cf6e6afcf" dependencies = [ - "bitflags 1.3.2", + "bitflags", "glib 0.10.3", "glib-sys 0.10.1", "gobject-sys 0.10.0", @@ -2765,7 +2730,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7bbb1485d87469849ec45c08e03c2f280d3ea20ff3c439d03185be54e3ce98e" dependencies = [ - "bitflags 1.3.2", + "bitflags", "futures-channel", "futures-util", "glib 0.10.3", @@ -2801,7 +2766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4d3507d43908c866c805f74c9dd593c0ce7ba5c38e576e41846639cdcd4bee6" dependencies = [ "atk", - "bitflags 1.3.2", + "bitflags", "cairo-rs", "field-offset", "futures-channel", @@ -3175,7 +3140,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abf888f9575c290197b2c948dc9e9ff10bd1a39ad1ea8585f734585fa6b9d3f9" dependencies = [ - "bitflags 1.3.2", + "bitflags", "inotify-sys", "libc", ] @@ -3371,7 +3336,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7668b7cff6a51fe61cdde64cd27c8a220786f399501b57ebe36f7d8112fd68" dependencies = [ - "bitflags 1.3.2", + "bitflags", "serde 1.0.163", "unicode-segmentation", ] @@ -3477,7 +3442,7 @@ version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1745b20bfc194ac12ef828f144f0ec2d4a7fe993281fa3567a0bd4969aee6890" dependencies = [ - "bitflags 1.3.2", + "bitflags", "libc", "libpulse-sys", "num-derive", @@ -3814,7 +3779,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" dependencies = [ - "bitflags 1.3.2", + "bitflags", "jni-sys", "ndk-sys", "num_enum", @@ -3856,7 +3821,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea993e32c77d87f01236c38f572ecb6c311d592e56a06262a007fd2a6e31253c" dependencies = [ "anyhow", - "bitflags 1.3.2", + "bitflags", "byteorder", "libc", "netlink-packet-core", @@ -3892,7 +3857,7 @@ version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cc", "cfg-if 1.0.0", "libc", @@ -3905,7 +3870,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cfg-if 1.0.0", "libc", "memoffset 0.6.5", @@ -3917,7 +3882,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cfg-if 1.0.0", "libc", "memoffset 0.7.1", @@ -4271,7 +4236,7 @@ version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdff66b271861037b89d028656184059e03b0b6ccb36003820be19f7200b1e94" dependencies = [ - "bitflags 1.3.2", + "bitflags", "gio", "glib 0.16.7", "libc", @@ -4477,7 +4442,7 @@ version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa" dependencies = [ - "bitflags 1.3.2", + "bitflags", "crc32fast", "fdeflate", "flate2", @@ -4491,7 +4456,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg 1.1.0", - "bitflags 1.3.2", + "bitflags", "cfg-if 1.0.0", "concurrent-queue", "libc", @@ -4970,7 +4935,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -4979,7 +4944,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -4993,12 +4958,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "reference-counted-singleton" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bfbf25d7eb88ddcbb1ec3d755d0634da8f7657b2cb8b74089121409ab8228f" - [[package]] name = "regex" version = "1.8.1" @@ -5248,7 +5207,6 @@ dependencies = [ "samplerate", "sciter-rs", "scrap", - "selinux", "serde 1.0.163", "serde_derive", "serde_json 1.0.96", @@ -5307,7 +5265,7 @@ version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", "io-lifetimes", "libc", @@ -5484,7 +5442,7 @@ version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "core-foundation-sys 0.8.4", "libc", @@ -5501,32 +5459,6 @@ dependencies = [ "libc", ] -[[package]] -name = "selinux" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80b091d970bd4a17a59cb1b7c537786f2bee4292abb5ec89ee3b7f17e9077138" -dependencies = [ - "bitflags 2.4.1", - "libc", - "once_cell", - "reference-counted-singleton", - "selinux-sys", - "thiserror", -] - -[[package]] -name = "selinux-sys" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56602385930248c57e45f6174a6a48e12b723d0cc2ae8f467fcbe80c0d06f41" -dependencies = [ - "bindgen 0.66.1", - "cc", - "dunce", - "walkdir", -] - [[package]] name = "semver" version = "1.0.17" @@ -5926,7 +5858,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75182f12f490e953596550b65ee31bda7c8e043d9386174b353bda50838c3fd" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "system-configuration-sys", ] @@ -5984,7 +5916,7 @@ name = "tao" version = "0.22.2" source = "git+https://github.com/rustdesk-org/tao?branch=dev#1e5b97258cf42a30f80f85a6aa0b1a4aece1977e" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cairo-rs", "cc", "cocoa", @@ -7003,7 +6935,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd9db37ecb5b13762d95468a2fc6009d4b2c62801243223aabd44fca13ad13c8" dependencies = [ - "bitflags 1.3.2", + "bitflags", "widestring", "windows-sys 0.45.0", ] diff --git a/Cargo.toml b/Cargo.toml index 711a1caca..f6c014483 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,7 +132,6 @@ dbus = "0.9" dbus-crossroads = "0.5" pam = { git="https://github.com/fufesou/pam", optional = true } users = { version = "0.11" } -selinux = "0.4.2" [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.13" diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index def0d8453..59118f7cd 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -379,7 +379,8 @@ class _DesktopHomePageState extends State // } } else if (Platform.isLinux) { final LinuxCards = []; - if (bind.isSelinuxEnabled()) { + if (bind.isSelinuxEnforcing()) { + // Check is SELinux enforcing, but show user a tip of is SELinux enabled for simple. final keyShowSelinuxHelpTip = "show-selinux-help-tip"; if (bind.mainGetLocalOption(key: keyShowSelinuxHelpTip) != 'N') { LinuxCards.add(buildInstallCard( diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 7e1aa44e4..9661aa8b3 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1935,10 +1935,10 @@ pub fn is_support_multi_ui_session(version: String) -> SyncReturn { SyncReturn(crate::common::is_support_multi_ui_session(&version)) } -pub fn is_selinux_enabled() -> SyncReturn { +pub fn is_selinux_enforcing() -> SyncReturn { #[cfg(target_os = "linux")] { - SyncReturn(crate::platform::linux::is_selinux_enabled()) + SyncReturn(crate::platform::linux::is_selinux_enforcing()) } #[cfg(not(target_os = "linux"))] { diff --git a/src/platform/linux.rs b/src/platform/linux.rs index bb3474d41..0d97b317a 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -1371,9 +1371,19 @@ pub fn is_x11() -> bool { } #[inline] -pub fn is_selinux_enabled() -> bool { - match selinux::kernel_support() { - selinux::KernelSupport::Unsupported => false, - _ => selinux::current_mode() == selinux::SELinuxMode::Enforcing, +pub fn is_selinux_enforcing() -> bool { + match run_cmds("getenforce") { + Ok(output) => output.trim() == "Enforcing", + Err(_) => match run_cmds("sestatus") { + Ok(output) => { + for line in output.lines() { + if line.contains("Current mode:") { + return line.contains("enforcing"); + } + } + false + } + Err(_) => false, + }, } } From 352865ddaaa6308a5e5f5face5bd534921e82a53 Mon Sep 17 00:00:00 2001 From: Mr-Update <37781396+Mr-Update@users.noreply.github.com> Date: Sun, 22 Oct 2023 09:50:27 +0200 Subject: [PATCH 078/114] Update de.rs --- src/lang/de.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/de.rs b/src/lang/de.rs index 6b5beb305..9bc00212f 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -565,6 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "In einem neuen Fenster öffnen"), ("Show displays as individual windows", "Jeden Bildschirm in einem eigenen Fenster anzeigen"), ("Use all my displays for the remote session", "Alle meine Bildschirme für die Fernsitzung verwenden"), - ("selinux_tip", ""), + ("selinux_tip", "SELinux ist auf Ihrem Gerät aktiviert, was dazu führen kann, dass RustDesk als kontrollierte Seite nicht richtig läuft."), ].iter().cloned().collect(); } From c518521d7485886d661e81bf815f326ab7c9dfb6 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 22 Oct 2023 20:35:43 +0800 Subject: [PATCH 079/114] fix, android physical mouse, click events, penetrated Signed-off-by: fufesou --- flutter/lib/mobile/pages/remote_page.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index ff71c9347..83a3f77c5 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -235,7 +235,7 @@ class _RemotePageState extends State { clientClose(sessionId, gFFI.dialogManager); return false; }, - child: getRawPointerAndKeyBody(Scaffold( + child: Scaffold( // workaround for https://github.com/rustdesk/rustdesk/issues/3131 floatingActionButtonLocation: keyboardIsVisible ? FABLocation(FloatingActionButtonLocation.endFloat, 0, -35) @@ -281,7 +281,7 @@ class _RemotePageState extends State { : Offstage(), ], )), - body: Overlay( + body: getRawPointerAndKeyBody(Overlay( initialEntries: [ OverlayEntry(builder: (context) { return Container( From c878c91e1188e3dac4239c65735e12151eee4aff Mon Sep 17 00:00:00 2001 From: Kleofass Date: Sun, 22 Oct 2023 16:51:38 +0300 Subject: [PATCH 080/114] Update lv.rs --- src/lang/lv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/lv.rs b/src/lang/lv.rs index d7783e052..47aa9c22d 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -565,6 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Atvērt jaunā logā"), ("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"), - ("selinux_tip", ""), + ("selinux_tip", "Jūsu ierīcē ir iespējots SELinux, kas var neļaut RustDesk pareizi darboties kā kontrolētajai pusei."), ].iter().cloned().collect(); } From dad209d1cde58127839f30c3953171419a0d4106 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Mon, 23 Oct 2023 03:21:54 +0530 Subject: [PATCH 081/114] feat autocomplete mobile Signed-off-by: Sahil Yeole --- flutter/lib/mobile/pages/connection_page.dart | 269 +++++++++++++++++- 1 file changed, 266 insertions(+), 3 deletions(-) diff --git a/flutter/lib/mobile/pages/connection_page.dart b/flutter/lib/mobile/pages/connection_page.dart index c9bd15709..63743638a 100644 --- a/flutter/lib/mobile/pages/connection_page.dart +++ b/flutter/lib/mobile/pages/connection_page.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:auto_size_text_field/auto_size_text_field.dart'; import 'package:flutter/material.dart'; @@ -6,10 +7,12 @@ import 'package:flutter_hbb/common/formatter/id_formatter.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:flutter_hbb/models/peer_model.dart'; import '../../common.dart'; import '../../common/widgets/login.dart'; import '../../common/widgets/peer_tab_page.dart'; +import '../../common/widgets/peer_card.dart'; import '../../consts.dart'; import '../../models/model.dart'; import '../../models/platform_model.dart'; @@ -42,6 +45,15 @@ class _ConnectionPageState extends State { /// Update url. If it's not null, means an update is available. var _updateUrl = ''; + List peers = []; + List _frontN(List list, int n) { + if (list.length <= n) { + return list; + } else { + return list.sublist(0, n); + } + } + bool isPeersLoading = false; @override void initState() { @@ -116,6 +128,64 @@ class _ConnectionPageState extends State { color: Colors.white, fontWeight: FontWeight.bold)))); } + Future _fetchPeers() async { + setState(() { + isPeersLoading = true; + }); + await Future.delayed(Duration(milliseconds: 100)); + await _getAllPeers(); + setState(() { + isPeersLoading = false; + }); + } + + Future _getAllPeers() async { + Map recentPeers = jsonDecode(await bind.mainLoadRecentPeersSync()); + Map lanPeers = jsonDecode(await bind.mainLoadLanPeersSync()); + Map abPeers = jsonDecode(await bind.mainLoadAbSync()); + Map groupPeers = jsonDecode(await bind.mainLoadGroupSync()); + + Map combinedPeers = {}; + + void mergePeers(Map peers) { + if (peers.containsKey("peers")) { + dynamic peerData = peers["peers"]; + + if (peerData is String) { + try { + peerData = jsonDecode(peerData); + } catch (e) { + debugPrint("Error decoding peers: $e"); + return; + } + } + + if (peerData is List) { + for (var peer in peerData) { + if (peer is Map && peer.containsKey("id")) { + String id = peer["id"]; + if (id != null && !combinedPeers.containsKey(id)) { + combinedPeers[id] = peer; + } + } + } + } + } + } + + mergePeers(recentPeers); + mergePeers(lanPeers); + mergePeers(abPeers); + mergePeers(groupPeers); + + List parsedPeers = []; + + for (var peer in combinedPeers.values) { + parsedPeers.add(Peer.fromJson(peer)); + } + peers = parsedPeers; + } + /// UI for the remote ID TextField. /// Search for a peer and connect to it if the id exists. Widget _buildRemoteIDTextField() { @@ -133,7 +203,61 @@ class _ConnectionPageState extends State { Expanded( child: Container( padding: const EdgeInsets.only(left: 16, right: 16), - child: AutoSizeTextField( + child: Autocomplete( + optionsBuilder: (TextEditingValue textEditingValue) { + if (textEditingValue.text == '') { + return const Iterable.empty(); + } + else if (peers.isEmpty) { + Peer emptyPeer = Peer( + id: '', + username: '', + hostname: '', + alias: '', + platform: '', + tags: [], + hash: '', + forceAlwaysRelay: false, + rdpPort: '', + rdpUsername: '', + loginName: '', + ); + return [emptyPeer]; + } + else { + String textWithoutSpaces = textEditingValue.text.replaceAll(" ", ""); + if (int.tryParse(textWithoutSpaces) != null) { + textEditingValue = TextEditingValue( + text: textWithoutSpaces, + selection: textEditingValue.selection, + ); + } + String textToFind = textEditingValue.text.toLowerCase(); + + return peers.where((peer) => + peer.id.toLowerCase().contains(textToFind) || + peer.username.toLowerCase().contains(textToFind) || + peer.hostname.toLowerCase().contains(textToFind) || + peer.alias.toLowerCase().contains(textToFind)) + .toList(); + } + }, + fieldViewBuilder: (BuildContext context, + TextEditingController fieldTextEditingController, + FocusNode fieldFocusNode, VoidCallback onFieldSubmitted) { + fieldTextEditingController.text = _idController.text; + fieldFocusNode.addListener(() async{ + _idEmpty.value = fieldTextEditingController.text.isEmpty; + if (fieldFocusNode.hasFocus && !isPeersLoading){ + _fetchPeers(); + } + }); + final textLength = fieldTextEditingController.value.text.length; + // select all to facilitate removing text, just following the behavior of address input of chrome + fieldTextEditingController.selection = TextSelection(baseOffset: 0, extentOffset: textLength); + return AutoSizeTextField( + controller: fieldTextEditingController, + focusNode: fieldFocusNode, minFontSize: 18, autocorrect: false, enableSuggestions: false, @@ -161,8 +285,36 @@ class _ConnectionPageState extends State { color: MyTheme.darkGray, ), ), - controller: _idController, inputFormatters: [IDTextInputFormatter()], + ); + }, + optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { + double maxHeight = options.length * 50; + maxHeight = maxHeight > 200 ? 200 : maxHeight; + return Align( + alignment: Alignment.topLeft, + child: ClipRRect( + borderRadius: BorderRadius.circular(5), + child: Material( + elevation: 4, + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: maxHeight, + maxWidth: 320, + ), + child: peers.isEmpty && isPeersLoading + ? Container( + height: 80, + child: Center( + child: CircularProgressIndicator( + strokeWidth: 2, + ))) + : ListView( + padding: EdgeInsets.only(top: 5), + children: options.map((peer) => _buildPeerTile(context, peer)).toList(), + )))) + ); + }, ), ), ), @@ -170,7 +322,9 @@ class _ConnectionPageState extends State { offstage: _idEmpty.value, child: IconButton( onPressed: () { - _idController.clear(); + setState(() { + _idController.clear(); + }); }, icon: Icon(Icons.clear, color: MyTheme.darkGray)), )), @@ -193,6 +347,115 @@ class _ConnectionPageState extends State { child: Container(constraints: kMobilePageConstraints, child: w)); } + Widget _buildPeerTile( + BuildContext context, Peer peer) { + final double _tileRadius = 5; + final name = + '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; + final greyStyle = TextStyle( + fontSize: 11, + color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6)); + final child = GestureDetector( + onTap: () { + setState(() { + _idController.id = peer.id; + FocusScope.of(context).unfocus(); + }); + }, + child: + Container( + height: 42, + margin: EdgeInsets.only(bottom: 5), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Container( + decoration: BoxDecoration( + color: str2color('${peer.id}${peer.platform}', 0x7f), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(_tileRadius), + bottomLeft: Radius.circular(_tileRadius), + ), + ), + alignment: Alignment.center, + width: 42, + height: null, + child: getPlatformImage(peer.platform, size: 30) + .paddingAll(6), + ), + Expanded( + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.background, + borderRadius: BorderRadius.only( + topRight: Radius.circular(_tileRadius), + bottomRight: Radius.circular(_tileRadius), + ), + ), + child: Row( + children: [ + Expanded( + child: Column( + children: [ + Row(children: [ + getOnline(8, peer.online), + Expanded( + child: Text( + peer.alias.isEmpty ? formatID(peer.id) : peer.alias, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall, + )), + !peer.alias.isEmpty? + Padding( + padding: const EdgeInsets.only(left: 5, right: 5), + child: Text( + "(${peer.id})", + style: greyStyle, + overflow: TextOverflow.ellipsis, + ) + ) + : Container(), + ]).marginOnly(top: 2), + Align( + alignment: Alignment.centerLeft, + child: Text( + name, + style: greyStyle, + textAlign: TextAlign.start, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ).marginOnly(top: 2), + ), + ], + ).paddingOnly(left: 10.0, top: 3.0), + ), + ) + ], + ))); + final colors = + _frontN(peer.tags, 25).map((e) => gFFI.abModel.getTagColor(e)).toList(); + return Tooltip( + message: isMobile + ? '' + : peer.tags.isNotEmpty + ? '${translate('Tags')}: ${peer.tags.join(', ')}' + : '', + child: Stack(children: [ + child, + if (colors.isNotEmpty) + Positioned( + top: 5, + right: 10, + child: CustomPaint( + painter: TagPainter(radius: 3, colors: colors), + ), + ) + ]), + ); + } + @override void dispose() { _idController.dispose(); From 935297b9e879ab86d51d2d45bbb6c56261548632 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Mon, 23 Oct 2023 04:03:05 +0530 Subject: [PATCH 082/114] fix empty peers Signed-off-by: Sahil Yeole --- flutter/lib/mobile/pages/connection_page.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flutter/lib/mobile/pages/connection_page.dart b/flutter/lib/mobile/pages/connection_page.dart index 63743638a..83ca6efd2 100644 --- a/flutter/lib/mobile/pages/connection_page.dart +++ b/flutter/lib/mobile/pages/connection_page.dart @@ -54,6 +54,7 @@ class _ConnectionPageState extends State { } } bool isPeersLoading = false; + bool isPeersLoaded = false; @override void initState() { @@ -136,6 +137,7 @@ class _ConnectionPageState extends State { await _getAllPeers(); setState(() { isPeersLoading = false; + isPeersLoaded = true; }); } @@ -208,7 +210,7 @@ class _ConnectionPageState extends State { if (textEditingValue.text == '') { return const Iterable.empty(); } - else if (peers.isEmpty) { + else if (peers.isEmpty && !isPeersLoaded) { Peer emptyPeer = Peer( id: '', username: '', From 5109802dfb14f9ac80b4c8cad2c7fac2a2d8d813 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Mon, 23 Oct 2023 04:17:28 +0530 Subject: [PATCH 083/114] update id on onchaged Signed-off-by: Sahil Yeole --- flutter/lib/mobile/pages/connection_page.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flutter/lib/mobile/pages/connection_page.dart b/flutter/lib/mobile/pages/connection_page.dart index 83ca6efd2..09532f724 100644 --- a/flutter/lib/mobile/pages/connection_page.dart +++ b/flutter/lib/mobile/pages/connection_page.dart @@ -265,6 +265,9 @@ class _ConnectionPageState extends State { enableSuggestions: false, keyboardType: TextInputType.visiblePassword, // keyboardType: TextInputType.number, + onChanged: (String text) { + _idController.id = text; + }, style: const TextStyle( fontFamily: 'WorkSans', fontWeight: FontWeight.bold, From 6797e8af52c76e100e0debfb3c3f2d0416aa4f70 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Mon, 23 Oct 2023 05:01:39 +0530 Subject: [PATCH 084/114] improve maxHeight desktop Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 859fd0d70..9b21727d9 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -332,10 +332,8 @@ class _ConnectionPageState extends State )); }, optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { - double maxHeight = 0; - for (var peer in options) { - if (maxHeight < 200) - maxHeight += 50; }; + double maxHeight = options.length * 50; + maxHeight = maxHeight > 200 ? 200 : maxHeight; return Align( alignment: Alignment.topLeft, child: ClipRRect( From c90c4a2e78e9ae806e0c01f71ec446af4a24cd9d Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Mon, 23 Oct 2023 05:03:44 +0530 Subject: [PATCH 085/114] fix empty peers desktop Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 9b21727d9..0aa47a375 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -52,6 +52,7 @@ class _ConnectionPageState extends State } } bool isPeersLoading = false; + bool isPeersLoaded = false; @override void initState() { @@ -155,6 +156,7 @@ class _ConnectionPageState extends State await _getAllPeers(); setState(() { isPeersLoading = false; + isPeersLoaded = true; }); } @@ -240,7 +242,7 @@ class _ConnectionPageState extends State if (textEditingValue.text == '') { return const Iterable.empty(); } - else if (peers.isEmpty) { + else if (peers.isEmpty && !isPeersLoaded) { Peer emptyPeer = Peer( id: '', username: '', From 1c9d139ff5e26faff8466e742919695792d76570 Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 23 Oct 2023 16:11:59 +0800 Subject: [PATCH 086/114] opt android get_home, bad code get corrent result Signed-off-by: 21pages --- libs/hbb_common/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 6f7bebdc0..6a154156b 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -569,7 +569,7 @@ impl Config { pub fn get_home() -> PathBuf { #[cfg(any(target_os = "android", target_os = "ios"))] - return Self::path(APP_HOME_DIR.read().unwrap().as_str()); + return PathBuf::from(APP_HOME_DIR.read().unwrap().as_str()); #[cfg(not(any(target_os = "android", target_os = "ios")))] { if let Some(path) = dirs_next::home_dir() { From 9ce58115abf14c470dcfa2e63eb90d23ffae24eb Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 23 Oct 2023 16:12:49 +0800 Subject: [PATCH 087/114] set timeout of hwcodec check to 30s Signed-off-by: 21pages --- libs/scrap/src/common/hwcodec.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/scrap/src/common/hwcodec.rs b/libs/scrap/src/common/hwcodec.rs index 333f85b98..eaaddbfad 100644 --- a/libs/scrap/src/common/hwcodec.rs +++ b/libs/scrap/src/common/hwcodec.rs @@ -362,13 +362,14 @@ pub fn check_config_process() { let f = || { // Clear to avoid checking process errors // But when the program is just started, the configuration file has not been updated, and the new connection will read an empty configuration + // TODO: --server start multi times on windows startup, which will clear the last config and cause concurrent file writing HwCodecConfig::clear(); if let Ok(exe) = std::env::current_exe() { if let Some(_) = exe.file_name().to_owned() { let arg = "--check-hwcodec-config"; if let Ok(mut child) = std::process::Command::new(exe).arg(arg).spawn() { - // wait up to 10 seconds - for _ in 0..10 { + // wait up to 30 seconds, it maybe slow on windows startup for poorly performing machines + for _ in 0..30 { std::thread::sleep(std::time::Duration::from_secs(1)); if let Ok(Some(_)) = child.try_wait() { break; From 0271ea7dadbb2b130b7c6a18c1043279deafea6e Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Mon, 23 Oct 2023 17:19:05 +0200 Subject: [PATCH 088/114] Update Italian language --- src/lang/it.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lang/it.rs b/src/lang/it.rs index 738dfa79e..caeeec340 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -566,5 +566,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("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"), ("selinux_tip", ""), + ("selinux_tip", "In questo dispositivo è abilitato SELinux, che potrebbe impedire il corretto funzionamento di RustDesk come lato controllato."), ].iter().cloned().collect(); } From feb6f7930e8e16d8c1523d65f8584c6f2aef4aa2 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 24 Oct 2023 05:30:43 +0530 Subject: [PATCH 089/114] common code autocomplete Signed-off-by: Sahil Yeole --- flutter/lib/common/widgets/autocomplete.dart | 196 ++++++++++++++++++ .../lib/desktop/pages/connection_page.dart | 164 +-------------- flutter/lib/mobile/pages/connection_page.dart | 163 +-------------- 3 files changed, 202 insertions(+), 321 deletions(-) create mode 100644 flutter/lib/common/widgets/autocomplete.dart diff --git a/flutter/lib/common/widgets/autocomplete.dart b/flutter/lib/common/widgets/autocomplete.dart new file mode 100644 index 000000000..9c14eab7f --- /dev/null +++ b/flutter/lib/common/widgets/autocomplete.dart @@ -0,0 +1,196 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:flutter_hbb/common/formatter/id_formatter.dart'; +import '../../../models/platform_model.dart'; +import 'package:flutter_hbb/models/peer_model.dart'; +import 'package:flutter_hbb/common.dart'; +import 'package:flutter_hbb/common/widgets/peer_card.dart'; + + + Future> getAllPeers() async { + Map recentPeers = jsonDecode(await bind.mainLoadRecentPeersSync()); + Map lanPeers = jsonDecode(await bind.mainLoadLanPeersSync()); + Map abPeers = jsonDecode(await bind.mainLoadAbSync()); + Map groupPeers = jsonDecode(await bind.mainLoadGroupSync()); + + Map combinedPeers = {}; + + void _mergePeers(Map peers) { + if (peers.containsKey("peers")) { + dynamic peerData = peers["peers"]; + + if (peerData is String) { + try { + peerData = jsonDecode(peerData); + } catch (e) { + print("Error decoding peers: $e"); + return; + } + } + + if (peerData is List) { + for (var peer in peerData) { + if (peer is Map && peer.containsKey("id")) { + String id = peer["id"]; + if (id != null && !combinedPeers.containsKey(id)) { + combinedPeers[id] = peer; + } + } + } + } + } + } + + _mergePeers(recentPeers); + _mergePeers(lanPeers); + _mergePeers(abPeers); + _mergePeers(groupPeers); + + List parsedPeers = []; + + for (var peer in combinedPeers.values) { + parsedPeers.add(Peer.fromJson(peer)); + } + return parsedPeers; + } + + class AutocompletePeerTile extends StatefulWidget { + final IDTextEditingController idController; + final Peer peer; + + const AutocompletePeerTile({ + Key? key, + required this.idController, + required this.peer, + }) : super(key: key); + + @override + _AutocompletePeerTileState createState() => _AutocompletePeerTileState(); +} + +class _AutocompletePeerTileState extends State{ + List _frontN(List list, int n) { + if (list.length <= n) { + return list; + } else { + return list.sublist(0, n); + } + } + @override + Widget build(BuildContext context){ + final double _tileRadius = 5; + final name = + '${widget.peer.username}${widget.peer.username.isNotEmpty && widget.peer.hostname.isNotEmpty ? '@' : ''}${widget.peer.hostname}'; + final greyStyle = TextStyle( + fontSize: 11, + color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6)); + final child = GestureDetector( + onTap: () { + setState(() { + widget.idController.id = widget.peer.id; + FocusScope.of(context).unfocus(); + }); + }, + child: + Container( + height: 42, + margin: EdgeInsets.only(bottom: 5), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Container( + decoration: BoxDecoration( + color: str2color('${widget.peer.id}${widget.peer.platform}', 0x7f), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(_tileRadius), + bottomLeft: Radius.circular(_tileRadius), + ), + ), + alignment: Alignment.center, + width: 42, + height: null, + child: Padding( + padding: EdgeInsets.all(6), + child: getPlatformImage(widget.peer.platform, size: 30) + ) + ), + Expanded( + child: Container( + padding: EdgeInsets.only(left: 10), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.background, + borderRadius: BorderRadius.only( + topRight: Radius.circular(_tileRadius), + bottomRight: Radius.circular(_tileRadius), + ), + ), + child: Row( + children: [ + Expanded( + child: Container( + margin: EdgeInsets.only(top: 2), + child: Container( + margin: EdgeInsets.only(top: 2), + child: Column( + children: [ + Container( + margin: EdgeInsets.only(top: 2), + child: Row(children: [ + getOnline(8, widget.peer.online), + Expanded( + child: Text( + widget.peer.alias.isEmpty ? formatID(widget.peer.id) : widget.peer.alias, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall, + )), + !widget.peer.alias.isEmpty? + Padding( + padding: const EdgeInsets.only(left: 5, right: 5), + child: Text( + "(${widget.peer.id})", + style: greyStyle, + overflow: TextOverflow.ellipsis, + ) + ) + : Container(), + ])), + Align( + alignment: Alignment.centerLeft, + child: Text( + name, + style: greyStyle, + textAlign: TextAlign.start, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ) + ))), + ], + ) + ), + ) + ], + ))); + final colors = + _frontN(widget.peer.tags, 25).map((e) => gFFI.abModel.getTagColor(e)).toList(); + return Tooltip( + message: isMobile + ? '' + : widget.peer.tags.isNotEmpty + ? '${translate('Tags')}: ${widget.peer.tags.join(', ')}' + : '', + child: Stack(children: [ + child, + if (colors.isNotEmpty) + Positioned( + top: 5, + right: 10, + child: CustomPaint( + painter: TagPainter(radius: 3, colors: colors), + ), + ) + ]), + ); + } + } \ No newline at end of file diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index ec74a8042..670f330bb 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -16,7 +16,7 @@ import 'package:flutter_hbb/models/peer_model.dart'; import '../../common.dart'; import '../../common/formatter/id_formatter.dart'; import '../../common/widgets/peer_tab_page.dart'; -import '../../common/widgets/peer_card.dart'; +import '../../common/widgets/autocomplete.dart'; import '../../models/platform_model.dart'; import '../widgets/button.dart'; @@ -152,60 +152,13 @@ class _ConnectionPageState extends State isPeersLoading = true; }); await Future.delayed(Duration(milliseconds: 100)); - await _getAllPeers(); + peers = await getAllPeers(); setState(() { isPeersLoading = false; isPeersLoaded = true; }); } - Future _getAllPeers() async { - Map recentPeers = jsonDecode(await bind.mainLoadRecentPeersSync()); - Map lanPeers = jsonDecode(await bind.mainLoadLanPeersSync()); - Map abPeers = jsonDecode(await bind.mainLoadAbSync()); - Map groupPeers = jsonDecode(await bind.mainLoadGroupSync()); - - Map combinedPeers = {}; - - void mergePeers(Map peers) { - if (peers.containsKey("peers")) { - dynamic peerData = peers["peers"]; - - if (peerData is String) { - try { - peerData = jsonDecode(peerData); - } catch (e) { - debugPrint("Error decoding peers: $e"); - return; - } - } - - if (peerData is List) { - for (var peer in peerData) { - if (peer is Map && peer.containsKey("id")) { - String id = peer["id"]; - if (id != null && !combinedPeers.containsKey(id)) { - combinedPeers[id] = peer; - } - } - } - } - } - } - - mergePeers(recentPeers); - mergePeers(lanPeers); - mergePeers(abPeers); - mergePeers(groupPeers); - - List parsedPeers = []; - - for (var peer in combinedPeers.values) { - parsedPeers.add(Peer.fromJson(peer)); - } - peers = parsedPeers; - } - /// UI for the remote ID TextField. /// Search for a peer. Widget _buildRemoteIDTextField(BuildContext context) { @@ -359,9 +312,7 @@ class _ConnectionPageState extends State : Padding( padding: const EdgeInsets.only(top: 5), child: ListView( - children: options - .map((peer) => _buildPeerTile(context, peer)) - .toList() + children: options.map((peer) => AutocompletePeerTile(idController: _idController, peer: peer)).toList(), ), ), ), @@ -397,115 +348,6 @@ class _ConnectionPageState extends State constraints: const BoxConstraints(maxWidth: 600), child: w); } - Widget _buildPeerTile( - BuildContext context, Peer peer) { - final double _tileRadius = 5; - final name = - '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; - final greyStyle = TextStyle( - fontSize: 11, - color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6)); - final child = GestureDetector( - onTap: () { - setState(() { - _idController.id = peer.id; - FocusScope.of(context).unfocus(); - }); - }, - child: - Container( - height: 42, - margin: EdgeInsets.only(bottom: 5), - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Container( - decoration: BoxDecoration( - color: str2color('${peer.id}${peer.platform}', 0x7f), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(_tileRadius), - bottomLeft: Radius.circular(_tileRadius), - ), - ), - alignment: Alignment.center, - width: 42, - height: null, - child: getPlatformImage(peer.platform, size: 30) - .paddingAll(6), - ), - Expanded( - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, - borderRadius: BorderRadius.only( - topRight: Radius.circular(_tileRadius), - bottomRight: Radius.circular(_tileRadius), - ), - ), - child: Row( - children: [ - Expanded( - child: Column( - children: [ - Row(children: [ - getOnline(8, peer.online), - Expanded( - child: Text( - peer.alias.isEmpty ? formatID(peer.id) : peer.alias, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.titleSmall, - )), - !peer.alias.isEmpty? - Padding( - padding: const EdgeInsets.only(left: 5, right: 5), - child: Text( - "(${peer.id})", - style: greyStyle, - overflow: TextOverflow.ellipsis, - ) - ) - : Container(), - ]).marginOnly(top: 2), - Align( - alignment: Alignment.centerLeft, - child: Text( - name, - style: greyStyle, - textAlign: TextAlign.start, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ).marginOnly(top: 2), - ), - ], - ).paddingOnly(left: 10.0, top: 3.0), - ), - ) - ], - ))); - final colors = - _frontN(peer.tags, 25).map((e) => gFFI.abModel.getTagColor(e)).toList(); - return Tooltip( - message: isMobile - ? '' - : peer.tags.isNotEmpty - ? '${translate('Tags')}: ${peer.tags.join(', ')}' - : '', - child: Stack(children: [ - child, - if (colors.isNotEmpty) - Positioned( - top: 5, - right: 10, - child: CustomPaint( - painter: TagPainter(radius: 3, colors: colors), - ), - ) - ]), - ); - } - Widget buildStatus() { final em = 14.0; return Container( diff --git a/flutter/lib/mobile/pages/connection_page.dart b/flutter/lib/mobile/pages/connection_page.dart index 09532f724..1c1dec8fc 100644 --- a/flutter/lib/mobile/pages/connection_page.dart +++ b/flutter/lib/mobile/pages/connection_page.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:convert'; import 'package:auto_size_text_field/auto_size_text_field.dart'; import 'package:flutter/material.dart'; @@ -12,7 +11,7 @@ import 'package:flutter_hbb/models/peer_model.dart'; import '../../common.dart'; import '../../common/widgets/login.dart'; import '../../common/widgets/peer_tab_page.dart'; -import '../../common/widgets/peer_card.dart'; +import '../../common/widgets/autocomplete.dart'; import '../../consts.dart'; import '../../models/model.dart'; import '../../models/platform_model.dart'; @@ -134,60 +133,13 @@ class _ConnectionPageState extends State { isPeersLoading = true; }); await Future.delayed(Duration(milliseconds: 100)); - await _getAllPeers(); + peers = await getAllPeers(); setState(() { isPeersLoading = false; isPeersLoaded = true; }); } - Future _getAllPeers() async { - Map recentPeers = jsonDecode(await bind.mainLoadRecentPeersSync()); - Map lanPeers = jsonDecode(await bind.mainLoadLanPeersSync()); - Map abPeers = jsonDecode(await bind.mainLoadAbSync()); - Map groupPeers = jsonDecode(await bind.mainLoadGroupSync()); - - Map combinedPeers = {}; - - void mergePeers(Map peers) { - if (peers.containsKey("peers")) { - dynamic peerData = peers["peers"]; - - if (peerData is String) { - try { - peerData = jsonDecode(peerData); - } catch (e) { - debugPrint("Error decoding peers: $e"); - return; - } - } - - if (peerData is List) { - for (var peer in peerData) { - if (peer is Map && peer.containsKey("id")) { - String id = peer["id"]; - if (id != null && !combinedPeers.containsKey(id)) { - combinedPeers[id] = peer; - } - } - } - } - } - } - - mergePeers(recentPeers); - mergePeers(lanPeers); - mergePeers(abPeers); - mergePeers(groupPeers); - - List parsedPeers = []; - - for (var peer in combinedPeers.values) { - parsedPeers.add(Peer.fromJson(peer)); - } - peers = parsedPeers; - } - /// UI for the remote ID TextField. /// Search for a peer and connect to it if the id exists. Widget _buildRemoteIDTextField() { @@ -316,7 +268,7 @@ class _ConnectionPageState extends State { ))) : ListView( padding: EdgeInsets.only(top: 5), - children: options.map((peer) => _buildPeerTile(context, peer)).toList(), + children: options.map((peer) => AutocompletePeerTile(idController: _idController, peer: peer)).toList(), )))) ); }, @@ -352,115 +304,6 @@ class _ConnectionPageState extends State { child: Container(constraints: kMobilePageConstraints, child: w)); } - Widget _buildPeerTile( - BuildContext context, Peer peer) { - final double _tileRadius = 5; - final name = - '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; - final greyStyle = TextStyle( - fontSize: 11, - color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6)); - final child = GestureDetector( - onTap: () { - setState(() { - _idController.id = peer.id; - FocusScope.of(context).unfocus(); - }); - }, - child: - Container( - height: 42, - margin: EdgeInsets.only(bottom: 5), - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Container( - decoration: BoxDecoration( - color: str2color('${peer.id}${peer.platform}', 0x7f), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(_tileRadius), - bottomLeft: Radius.circular(_tileRadius), - ), - ), - alignment: Alignment.center, - width: 42, - height: null, - child: getPlatformImage(peer.platform, size: 30) - .paddingAll(6), - ), - Expanded( - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, - borderRadius: BorderRadius.only( - topRight: Radius.circular(_tileRadius), - bottomRight: Radius.circular(_tileRadius), - ), - ), - child: Row( - children: [ - Expanded( - child: Column( - children: [ - Row(children: [ - getOnline(8, peer.online), - Expanded( - child: Text( - peer.alias.isEmpty ? formatID(peer.id) : peer.alias, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.titleSmall, - )), - !peer.alias.isEmpty? - Padding( - padding: const EdgeInsets.only(left: 5, right: 5), - child: Text( - "(${peer.id})", - style: greyStyle, - overflow: TextOverflow.ellipsis, - ) - ) - : Container(), - ]).marginOnly(top: 2), - Align( - alignment: Alignment.centerLeft, - child: Text( - name, - style: greyStyle, - textAlign: TextAlign.start, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ).marginOnly(top: 2), - ), - ], - ).paddingOnly(left: 10.0, top: 3.0), - ), - ) - ], - ))); - final colors = - _frontN(peer.tags, 25).map((e) => gFFI.abModel.getTagColor(e)).toList(); - return Tooltip( - message: isMobile - ? '' - : peer.tags.isNotEmpty - ? '${translate('Tags')}: ${peer.tags.join(', ')}' - : '', - child: Stack(children: [ - child, - if (colors.isNotEmpty) - Positioned( - top: 5, - right: 10, - child: CustomPaint( - painter: TagPainter(radius: 3, colors: colors), - ), - ) - ]), - ); - } - @override void dispose() { _idController.dispose(); From be8e8a0521ba8a9c10876ebe9be957194e61c6d6 Mon Sep 17 00:00:00 2001 From: dignow Date: Tue, 24 Oct 2023 10:51:01 +0800 Subject: [PATCH 090/114] fix, win, install cert Signed-off-by: dignow --- src/platform/windows.rs | 68 ++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/src/platform/windows.rs b/src/platform/windows.rs index f664b1aee..ad92ff97d 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1839,20 +1839,19 @@ pub fn uninstall_cert() -> ResultType<()> { mod cert { use hbb_common::{allow_err, bail, log, ResultType}; - use std::{path::Path, str::from_utf8}; + use std::{ffi::OsStr, io::Error, os::windows::ffi::OsStrExt, path::Path, str::from_utf8}; use winapi::{ shared::{ minwindef::{BYTE, DWORD, FALSE, TRUE}, ntdef::NULL, }, um::{ - errhandlingapi::GetLastError, wincrypt::{ CertAddEncodedCertificateToStore, CertCloseStore, CertDeleteCertificateFromStore, - CertEnumCertificatesInStore, CertNameToStrA, CertOpenSystemStoreW, - CryptHashCertificate, ALG_ID, CALG_SHA1, CERT_ID_SHA1_HASH, - CERT_STORE_ADD_REPLACE_EXISTING, CERT_X500_NAME_STR, PCCERT_CONTEXT, - X509_ASN_ENCODING, + CertEnumCertificatesInStore, CertNameToStrA, CertOpenStore, CryptHashCertificate, + ALG_ID, CALG_SHA1, CERT_ID_SHA1_HASH, CERT_STORE_ADD_REPLACE_EXISTING, + CERT_STORE_PROV_SYSTEM_W, CERT_SYSTEM_STORE_LOCAL_MACHINE, CERT_X500_NAME_STR, + PCCERT_CONTEXT, PKCS_7_ASN_ENCODING, X509_ASN_ENCODING, }, winreg::HKEY_LOCAL_MACHINE, }, @@ -1866,8 +1865,12 @@ mod cert { "SOFTWARE\\Microsoft\\SystemCertificates\\ROOT\\Certificates\\"; const THUMBPRINT_ALG: ALG_ID = CALG_SHA1; const THUMBPRINT_LEN: DWORD = 20; - const CERT_ISSUER_1: &str = "CN=\"WDKTestCert admin,133225435702113567\"\0"; + const CERT_ENCODING_TYPE: DWORD = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; + + lazy_static::lazy_static! { + static ref CERT_STORE_LOC: Vec = OsStr::new("ROOT\0").encode_wide().collect::>(); + } #[inline] unsafe fn compute_thumbprint(pb_encoded: *const BYTE, cb_encoded: DWORD) -> (Vec, String) { @@ -1946,24 +1949,46 @@ mod cert { fn install_cert_add_cert_store(cert_bytes: &mut [u8]) -> ResultType<()> { unsafe { - let store_handle = CertOpenSystemStoreW(0 as _, "ROOT\0".as_ptr() as _); + let store_handle = CertOpenStore( + CERT_STORE_PROV_SYSTEM_W, + 0, + 0, + CERT_SYSTEM_STORE_LOCAL_MACHINE, + CERT_STORE_LOC.as_ptr() as _, + ); if store_handle.is_null() { - bail!("Error opening certificate store: {}", GetLastError()); + bail!( + "Error opening certificate store: {}", + Error::last_os_error() + ); } - let mut cert_ctx: PCCERT_CONTEXT = std::ptr::null_mut(); + + // Create the certificate context + let cert_context = winapi::um::wincrypt::CertCreateCertificateContext( + CERT_ENCODING_TYPE, + cert_bytes.as_ptr(), + cert_bytes.len() as DWORD, + ); + if cert_context.is_null() { + bail!( + "Error creating certificate context: {}", + Error::last_os_error() + ); + } + if FALSE == CertAddEncodedCertificateToStore( store_handle, - X509_ASN_ENCODING, - cert_bytes.as_mut_ptr(), - cert_bytes.len() as _, + CERT_ENCODING_TYPE, + (*cert_context).pbCertEncoded, + (*cert_context).cbCertEncoded, CERT_STORE_ADD_REPLACE_EXISTING, - &mut cert_ctx as _, + std::ptr::null_mut(), ) { log::error!( "Failed to call CertAddEncodedCertificateToStore: {}", - GetLastError() + Error::last_os_error() ); } else { log::info!("Add cert to store successfully"); @@ -1981,9 +2006,18 @@ mod cert { let mut buf = [0u8; 1024]; unsafe { - let store_handle = CertOpenSystemStoreW(0 as _, "ROOT\0".as_ptr() as _); + let store_handle = CertOpenStore( + CERT_STORE_PROV_SYSTEM_W, + 0, + 0, + CERT_SYSTEM_STORE_LOCAL_MACHINE, + CERT_STORE_LOC.as_ptr() as _, + ); if store_handle.is_null() { - bail!("Error opening certificate store: {}", GetLastError()); + bail!( + "Error opening certificate store: {}", + Error::last_os_error() + ); } let mut vec_ctx = Vec::new(); From f438176544503bd3455e9e6221ff807f74a4ea6c Mon Sep 17 00:00:00 2001 From: dignow Date: Tue, 24 Oct 2023 11:41:01 +0800 Subject: [PATCH 091/114] fix potential crash when uninstalling cert Signed-off-by: dignow --- src/platform/windows.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/platform/windows.rs b/src/platform/windows.rs index ad92ff97d..3b44cbc11 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -2020,7 +2020,6 @@ mod cert { ); } - let mut vec_ctx = Vec::new(); let mut cert_ctx: PCCERT_CONTEXT = CertEnumCertificatesInStore(store_handle, NULL as _); while !cert_ctx.is_null() { // https://stackoverflow.com/a/66432736 @@ -2032,11 +2031,9 @@ mod cert { buf.len() as _, ); if cb_size != 1 { - let mut add_ctx = false; if let Ok(issuer) = from_utf8(&buf[..cb_size as _]) { for iss in issuers_to_rm.iter() { if issuer == *iss { - add_ctx = true; let (_, thumbprint) = compute_thumbprint( (*cert_ctx).pbCertEncoded, (*cert_ctx).cbCertEncoded, @@ -2044,18 +2041,15 @@ mod cert { if !thumbprint.is_empty() { thumbprints.push(thumbprint); } + // Delete current cert context and re-enumerate. + CertDeleteCertificateFromStore(cert_ctx); + cert_ctx = CertEnumCertificatesInStore(store_handle, NULL as _); } } } - if add_ctx { - vec_ctx.push(cert_ctx); - } } cert_ctx = CertEnumCertificatesInStore(store_handle, cert_ctx); } - for ctx in vec_ctx { - CertDeleteCertificateFromStore(ctx); - } CertCloseStore(store_handle, 0); } @@ -2067,7 +2061,8 @@ mod cert { let reg_cert_key = unsafe { open_reg_cert_store()? }; log::info!("Found {} certs to remove", thumbprints.len()); for thumbprint in thumbprints.iter() { - allow_err!(reg_cert_key.delete_subkey(thumbprint)); + // Deleting cert from registry may fail, because the CertDeleteCertificateFromStore() is called before. + let _ = reg_cert_key.delete_subkey(thumbprint); } Ok(()) } From d8355371e3784d31c8b3bf27fbaab3c44857192e Mon Sep 17 00:00:00 2001 From: solokot Date: Tue, 24 Oct 2023 08:42:17 +0300 Subject: [PATCH 092/114] Update ru.rs --- src/lang/ru.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 82c9a9601..e7d90d2b8 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -565,6 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Открыть в новом окне"), ("Show displays as individual windows", "Показывать дисплеи в отдельных окнах"), ("Use all my displays for the remote session", "Использовать все мои дисплеи для удалённого сеанса"), - ("selinux_tip", ""), + ("selinux_tip", "На вашем устройстве включён SELinux, что может помешать правильной работе RustDesk на контролируемой стороне."), ].iter().cloned().collect(); } From 81fe90f6057b34babd550d3d474d5a6aa12981e2 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 24 Oct 2023 22:14:01 +0530 Subject: [PATCH 093/114] add ui for new list view Signed-off-by: Sahil Yeole --- flutter/lib/common/widgets/peers_view.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/flutter/lib/common/widgets/peers_view.dart b/flutter/lib/common/widgets/peers_view.dart index c058dd4dc..78464921f 100644 --- a/flutter/lib/common/widgets/peers_view.dart +++ b/flutter/lib/common/widgets/peers_view.dart @@ -191,9 +191,11 @@ class _PeersViewState extends State<_PeersView> with WindowListener { return isDesktop ? Obx( () => SizedBox( - width: 220, + width: peerCardUiType.value != PeerUiType.list + ? 220 + : MediaQuery.of(context).size.width - 227, height: - peerCardUiType.value == PeerUiType.grid ? 140 : 42, + peerCardUiType.value == PeerUiType.grid ? 140 : peerCardUiType.value != PeerUiType.list ? 42 : 45, child: visibilityChild, ), ) From 94e51a804126859dbda99b8f76df5b2760c6a684 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 24 Oct 2023 22:14:59 +0530 Subject: [PATCH 094/114] update enum for list view Signed-off-by: Sahil Yeole --- flutter/lib/common/widgets/peer_card.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index 922f88225..a071d8f40 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -19,7 +19,7 @@ import 'dart:math' as math; typedef PopupMenuEntryBuilder = Future>> Function(BuildContext); -enum PeerUiType { grid, list } +enum PeerUiType { grid, tile, list } final peerCardUiType = PeerUiType.grid.obs; From d9e1b2df7fb80559a7e5b47b2410ba6e355c984c Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 24 Oct 2023 22:33:51 +0530 Subject: [PATCH 095/114] update peer view type options Signed-off-by: Sahil Yeole --- flutter/lib/common/widgets/peer_tab_page.dart | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index b5143eb82..63d9e18f8 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -216,21 +216,24 @@ class _PeerTabPageState extends State Widget _createPeerViewTypeSwitch(BuildContext context) { final textColor = Theme.of(context).textTheme.titleLarge?.color; - final types = [PeerUiType.grid, PeerUiType.list]; + final types = [PeerUiType.grid, PeerUiType.tile, PeerUiType.list]; return Obx(() => _hoverAction( context: context, onTap: () async { - final type = types - .elementAt(peerCardUiType.value == types.elementAt(0) ? 1 : 0); + final currentIndex = types.indexOf(peerCardUiType.value); + final newIndex = (currentIndex + 1) % types.length; // cycle through types + final type = types[newIndex]; await bind.setLocalFlutterOption( k: 'peer-card-ui-type', v: type.index.toString()); peerCardUiType.value = type; }, child: Tooltip( message: peerCardUiType.value == PeerUiType.grid - ? translate('List View') - : translate('Grid View'), + ? translate('Small tiles') + : peerCardUiType.value == PeerUiType.tile + ? translate('List') + : translate('Big tiles'), child: Icon( peerCardUiType.value == PeerUiType.grid ? Icons.view_list_rounded From 1e059c56499c601370fde43ed353df5496690e15 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 24 Oct 2023 23:15:42 +0530 Subject: [PATCH 096/114] update peer view type icons Signed-off-by: Sahil Yeole --- flutter/lib/common/widgets/peer_tab_page.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index 63d9e18f8..4e75af636 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -237,7 +237,9 @@ class _PeerTabPageState extends State child: Icon( peerCardUiType.value == PeerUiType.grid ? Icons.view_list_rounded - : Icons.grid_view_rounded, + : peerCardUiType.value == PeerUiType.tile + ? Icons.view_agenda_rounded + : Icons.grid_view_rounded, size: 18, color: textColor, )))); From 3f3489b292ee2580a90b02cb9d1712ee5afe4e32 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Tue, 24 Oct 2023 23:19:43 +0530 Subject: [PATCH 097/114] update peer view type tooltip Signed-off-by: Sahil Yeole --- flutter/lib/common/widgets/peer_tab_page.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index 4e75af636..6a2a5347a 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -230,10 +230,10 @@ class _PeerTabPageState extends State }, child: Tooltip( message: peerCardUiType.value == PeerUiType.grid - ? translate('Small tiles') + ? translate('Small Tiles') : peerCardUiType.value == PeerUiType.tile ? translate('List') - : translate('Big tiles'), + : translate('Big Tiles'), child: Icon( peerCardUiType.value == PeerUiType.grid ? Icons.view_list_rounded From a52caaec7546a93de851ef1fcf01d301825dd220 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Wed, 25 Oct 2023 01:26:41 +0530 Subject: [PATCH 098/114] fix list view for group tab Signed-off-by: Sahil Yeole --- flutter/lib/common/widgets/peers_view.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/flutter/lib/common/widgets/peers_view.dart b/flutter/lib/common/widgets/peers_view.dart index 78464921f..48fced275 100644 --- a/flutter/lib/common/widgets/peers_view.dart +++ b/flutter/lib/common/widgets/peers_view.dart @@ -9,6 +9,7 @@ import 'package:get/get.dart'; import 'package:provider/provider.dart'; import 'package:visibility_detector/visibility_detector.dart'; import 'package:window_manager/window_manager.dart'; +import 'package:flutter_hbb/models/peer_tab_model.dart'; import '../../common.dart'; import '../../models/peer_model.dart'; @@ -188,12 +189,16 @@ class _PeersViewState extends State<_PeersView> with WindowListener { onVisibilityChanged: onVisibilityChanged, child: widget.peerCardBuilder(peer), ); + final windowWidth = MediaQuery.of(context).size.width; + final model = Provider.of(context); return isDesktop ? Obx( () => SizedBox( width: peerCardUiType.value != PeerUiType.list ? 220 - : MediaQuery.of(context).size.width - 227, + : model.currentTab == PeerTabIndex.group.index? + windowWidth - 390 : + windowWidth - 227, height: peerCardUiType.value == PeerUiType.grid ? 140 : peerCardUiType.value != PeerUiType.list ? 42 : 45, child: visibilityChild, From ce300aa75fbc5a5a95bc80ddcc11852dbf4ef62d Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Wed, 25 Oct 2023 02:05:17 +0530 Subject: [PATCH 099/114] remove unused onSubmitted Signed-off-by: Sahil Yeole --- flutter/lib/desktop/pages/connection_page.dart | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 670f330bb..cab9b12f7 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -271,18 +271,6 @@ class _ConnectionPageState extends State onChanged: (v) { _idController.id = v; }, - onSubmitted: (s) { - if (s == '') { - return; - } - try { - final id = int.parse(s); - _idController.id = s; - onConnect(); - } catch (_) { - return; - } - }, )); }, optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { From 2cdfeb8dd0bebfad34c17bdf4e3c44ef29358fcd Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Wed, 25 Oct 2023 02:36:23 +0530 Subject: [PATCH 100/114] fix id field ui not updating on peer card connection Signed-off-by: Sahil Yeole --- flutter/lib/common.dart | 4 ++++ flutter/lib/desktop/pages/connection_page.dart | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 0ab790720..9c8404c56 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -2024,6 +2024,10 @@ connect( final idController = Get.find(); idController.text = formatID(id); } + if (Get.isRegistered()){ + final fieldTextEditingController = Get.find(); + fieldTextEditingController.text = formatID(id); + } } catch (_) {} } id = id.replaceAll(' ', ''); diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index cab9b12f7..a40e8abe0 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -81,6 +81,9 @@ class _ConnectionPageState extends State if (Get.isRegistered()) { Get.delete(); } + if (Get.isRegistered()){ + Get.delete(); + } super.dispose(); } @@ -235,6 +238,7 @@ class _ConnectionPageState extends State VoidCallback onFieldSubmitted, ) { fieldTextEditingController.text = _idController.text; + Get.put(fieldTextEditingController); fieldFocusNode.addListener(() async { _idInputFocused.value = fieldFocusNode.hasFocus; if (fieldFocusNode.hasFocus && !isPeersLoading){ From fcf3577f67c416a87902e5adfb7d37f5ad0ed164 Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 25 Oct 2023 09:20:51 +0800 Subject: [PATCH 101/114] fix, check session's keyboard mode on conn Signed-off-by: fufesou --- flutter/lib/consts.dart | 4 +++ .../lib/desktop/widgets/remote_toolbar.dart | 30 +++++++--------- flutter/lib/models/model.dart | 34 +++++++++++++++++++ 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index e3339c1ec..ccd8fbaac 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -11,6 +11,10 @@ const int kMainWindowId = 0; const kAllDisplayValue = -1; +const kKeyLegacyMode = 'legacy'; +const kKeyMapMode = 'map'; +const kKeyTranslateMode = 'translate'; + const String kPeerPlatformWindows = "Windows"; const String kPeerPlatformLinux = "Linux"; const String kPeerPlatformMacOS = "Mac OS"; diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 1cfa36145..1f161ec42 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -26,10 +26,6 @@ import '../../common/shared_state.dart'; import './popup_menu.dart'; import './kb_layout_type_chooser.dart'; -const _kKeyLegacyMode = 'legacy'; -const _kKeyMapMode = 'map'; -const _kKeyTranslateMode = 'translate'; - class ToolbarState { final kStoreKey = 'remoteMenubarState'; late RxBool show; @@ -1406,18 +1402,16 @@ class _KeyboardMenu extends StatelessWidget { Widget build(BuildContext context) { var ffiModel = Provider.of(context); if (!ffiModel.keyboard) return Offstage(); + // If use flutter to grab keys, we can only use one mode. + // Map mode and Legacy mode, at least one of them is supported. String? modeOnly; if (stateGlobal.grabKeyboard) { if (bind.sessionIsKeyboardModeSupported( - sessionId: ffi.sessionId, mode: _kKeyMapMode)) { - bind.sessionSetKeyboardMode( - sessionId: ffi.sessionId, value: _kKeyMapMode); - modeOnly = _kKeyMapMode; + sessionId: ffi.sessionId, mode: kKeyMapMode)) { + modeOnly = kKeyMapMode; } else if (bind.sessionIsKeyboardModeSupported( - sessionId: ffi.sessionId, mode: _kKeyLegacyMode)) { - bind.sessionSetKeyboardMode( - sessionId: ffi.sessionId, value: _kKeyLegacyMode); - modeOnly = _kKeyLegacyMode; + sessionId: ffi.sessionId, mode: kKeyLegacyMode)) { + modeOnly = kKeyLegacyMode; } } return _IconSubmenuButton( @@ -1439,13 +1433,13 @@ class _KeyboardMenu extends StatelessWidget { keyboardMode(String? modeOnly) { return futureBuilder(future: () async { return await bind.sessionGetKeyboardMode(sessionId: ffi.sessionId) ?? - _kKeyLegacyMode; + kKeyLegacyMode; }(), hasData: (data) { final groupValue = data as String; List modes = [ - InputModeMenu(key: _kKeyLegacyMode, menu: 'Legacy mode'), - InputModeMenu(key: _kKeyMapMode, menu: 'Map mode'), - InputModeMenu(key: _kKeyTranslateMode, menu: 'Translate mode'), + InputModeMenu(key: kKeyLegacyMode, menu: 'Legacy mode'), + InputModeMenu(key: kKeyMapMode, menu: 'Map mode'), + InputModeMenu(key: kKeyTranslateMode, menu: 'Translate mode'), ]; List list = []; final enabled = !ffi.ffiModel.viewOnly; @@ -1463,12 +1457,12 @@ class _KeyboardMenu extends StatelessWidget { continue; } - if (pi.isWayland && mode.key != _kKeyMapMode) { + if (pi.isWayland && mode.key != kKeyMapMode) { continue; } var text = translate(mode.menu); - if (mode.key == _kKeyTranslateMode) { + if (mode.key == kKeyTranslateMode) { text = '$text beta'; } list.add(RdoMenuButton( diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 0d257eaf0..c8675dfa7 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -703,6 +703,10 @@ class FfiModel with ChangeNotifier { _pi.isSet.value = true; stateGlobal.resetLastResolutionGroupValues(peerId); + if (isDesktop) { + checkDesktopKeyboardMode(); + } + notifyListeners(); if (!isCache) { @@ -710,6 +714,36 @@ class FfiModel with ChangeNotifier { } } + checkDesktopKeyboardMode() async { + final curMode = await bind.sessionGetKeyboardMode(sessionId: sessionId); + if (curMode != null) { + if (bind.sessionIsKeyboardModeSupported( + sessionId: sessionId, mode: curMode)) { + return; + } + } + + // If current keyboard mode is not supported, change to another one. + + if (stateGlobal.grabKeyboard) { + for (final mode in [kKeyMapMode, kKeyLegacyMode]) { + if (bind.sessionIsKeyboardModeSupported( + sessionId: sessionId, mode: mode)) { + bind.sessionSetKeyboardMode(sessionId: sessionId, value: mode); + break; + } + } + } else { + for (final mode in [kKeyMapMode, kKeyTranslateMode, kKeyLegacyMode]) { + if (bind.sessionIsKeyboardModeSupported( + sessionId: sessionId, mode: mode)) { + bind.sessionSetKeyboardMode(sessionId: sessionId, value: mode); + break; + } + } + } + } + tryUseAllMyDisplaysForTheRemoteSession(String peerId) async { if (bind.sessionGetUseAllMyDisplaysForTheRemoteSession( sessionId: sessionId) != From 30580b2c57f266f6f54f04cd064c49fd34241e3b Mon Sep 17 00:00:00 2001 From: RustDesk <71636191+rustdesk@users.noreply.github.com> Date: Wed, 25 Oct 2023 13:15:15 +0800 Subject: [PATCH 102/114] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c00bc88f0..502d10b28 100644 --- a/README.md +++ b/README.md @@ -170,12 +170,12 @@ Please ensure that you are running these commands from the root of the RustDesk - **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs functions for file transfer, and some other utility functions - **[libs/scrap](https://github.com/rustdesk/rustdesk/tree/master/libs/scrap)**: screen capture - **[libs/enigo](https://github.com/rustdesk/rustdesk/tree/master/libs/enigo)**: platform specific keyboard/mouse control -- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: GUI +- **[src/ui](https://github.com/rustdesk/rustdesk/tree/master/src/ui)**: obsolete Sciter UI (deprecated) - **[src/server](https://github.com/rustdesk/rustdesk/tree/master/src/server)**: audio/clipboard/input/video services, and network connections - **[src/client.rs](https://github.com/rustdesk/rustdesk/tree/master/src/client.rs)**: start a peer connection - **[src/rendezvous_mediator.rs](https://github.com/rustdesk/rustdesk/tree/master/src/rendezvous_mediator.rs)**: Communicate with [rustdesk-server](https://github.com/rustdesk/rustdesk-server), wait for remote direct (TCP hole punching) or relayed connection - **[src/platform](https://github.com/rustdesk/rustdesk/tree/master/src/platform)**: platform specific code -- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter code for mobile +- **[flutter](https://github.com/rustdesk/rustdesk/tree/master/flutter)**: Flutter code for desktop and mobile - **[flutter/web/js](https://github.com/rustdesk/rustdesk/tree/master/flutter/web/js)**: JavaScript for Flutter web client ## Snapshots From 39b5a670404ec00275f05d12aeac900cbbba4a26 Mon Sep 17 00:00:00 2001 From: RustDesk <71636191+rustdesk@users.noreply.github.com> Date: Wed, 25 Oct 2023 13:19:37 +0800 Subject: [PATCH 103/114] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 502d10b28..924cd1786 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Go through [DEVCONTAINER.md](docs/DEVCONTAINER.md) for more info. ## Dependencies -Desktop versions use [Sciter](https://sciter.com/) or Flutter for GUI, this tutorial is for Sciter only. +Desktop versions use Flutter or Sciter (deprecated) for GUI, this tutorial is for Sciter only, since it is easier and more friendly to starter. Check out our [CI](https://github.com/rustdesk/rustdesk/blob/master/.github/workflows/flutter-build.yml) for building Flutter version. Please download Sciter dynamic library yourself. From cadbae31e41deba0ae39ff9056c0921d855b8d12 Mon Sep 17 00:00:00 2001 From: flusheDData <116861809+flusheDData@users.noreply.github.com> Date: Wed, 25 Oct 2023 10:19:17 +0200 Subject: [PATCH 104/114] Update es.rs selinux_tip translation --- src/lang/es.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/es.rs b/src/lang/es.rs index 426e80a8e..32635973f 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -565,6 +565,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Open in new window", "Abrir en una nueva ventana"), ("Show displays as individual windows", "Mostrar pantallas como ventanas individuales"), ("Use all my displays for the remote session", "Usar todas mis pantallas para la sesión remota"), - ("selinux_tip", ""), + ("selinux_tip", "SELinux está activado en tu dispositivo, lo que puede hacer que RustDesk no se ejecute correctamente como lado controlado."), ].iter().cloned().collect(); } From cc35328f28d5f309c50df57ab171af17bf57e413 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Thu, 26 Oct 2023 04:02:34 +0530 Subject: [PATCH 105/114] add dropdown for peer view types Signed-off-by: Sahil Yeole --- flutter/lib/common/widgets/peer_tab_page.dart | 104 +++++++++++++----- 1 file changed, 76 insertions(+), 28 deletions(-) diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index 6a2a5347a..fb7ef39b2 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -215,34 +215,7 @@ class _PeerTabPageState extends State } Widget _createPeerViewTypeSwitch(BuildContext context) { - final textColor = Theme.of(context).textTheme.titleLarge?.color; - final types = [PeerUiType.grid, PeerUiType.tile, PeerUiType.list]; - - return Obx(() => _hoverAction( - context: context, - onTap: () async { - final currentIndex = types.indexOf(peerCardUiType.value); - final newIndex = (currentIndex + 1) % types.length; // cycle through types - final type = types[newIndex]; - await bind.setLocalFlutterOption( - k: 'peer-card-ui-type', v: type.index.toString()); - peerCardUiType.value = type; - }, - child: Tooltip( - message: peerCardUiType.value == PeerUiType.grid - ? translate('Small Tiles') - : peerCardUiType.value == PeerUiType.tile - ? translate('List') - : translate('Big Tiles'), - child: Icon( - peerCardUiType.value == PeerUiType.grid - ? Icons.view_list_rounded - : peerCardUiType.value == PeerUiType.tile - ? Icons.view_agenda_rounded - : Icons.grid_view_rounded, - size: 18, - color: textColor, - )))); + return PeerViewDropdown(); } Widget _createMultiSelection() { @@ -782,6 +755,81 @@ class _PeerSearchBarState extends State { } } +class PeerViewDropdown extends StatefulWidget { + const PeerViewDropdown({super.key}); + + @override + State createState() => _PeerViewDropdownState(); +} + +class _PeerViewDropdownState extends State { + @override + Widget build(BuildContext context) { + final List types = [PeerUiType.grid, PeerUiType.tile, PeerUiType.list]; + final style = TextStyle( + color: Theme.of(context).textTheme.titleLarge?.color, + fontSize: MenuConfig.fontSize, + fontWeight: FontWeight.normal); + List items = List.empty(growable: true); + items.add(PopupMenuItem( + height: 36, + enabled: false, + child: Text(translate("Change View"), style: style))); + for (var e in PeerUiType.values) { + items.add(PopupMenuItem( + height: 36, + child: Obx(() => Center( + child: SizedBox( + height: 36, + child: getRadio( + Text(translate( + types.indexOf(e) == 0 ? 'Big Tiles' : types.indexOf(e) == 1 ? 'Small Tiles' : 'List' + ), style: style), + e, + peerCardUiType.value, + dense: true, + (PeerUiType? v) async { + if (v != null) { + peerCardUiType.value = v; + await bind.setLocalFlutterOption( + k: "peer-card-ui-type", + v: peerCardUiType.value.index.toString(), + ); + }} + ), + ), + )))); + } + + var menuPos = RelativeRect.fromLTRB(0, 0, 0, 0); + return _hoverAction( + context: context, + child: Tooltip( + message: translate('Change View'), + child: Icon( + peerCardUiType.value == PeerUiType.grid + ? Icons.grid_view_rounded + : peerCardUiType.value == PeerUiType.tile + ? Icons.view_list_rounded + : Icons.view_agenda_rounded, + size: 18, + )), + onTapDown: (details) { + final x = details.globalPosition.dx; + final y = details.globalPosition.dy; + menuPos = RelativeRect.fromLTRB(x, y, x, y); + }, + onTap: () => showMenu( + context: context, + position: menuPos, + items: items, + elevation: 8, + ), + ); + } +} + + class PeerSortDropdown extends StatefulWidget { const PeerSortDropdown({super.key}); From 8fe64755ecdccfa4e027b9ad74dd4fca79dd2534 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Thu, 26 Oct 2023 04:46:24 +0530 Subject: [PATCH 106/114] fix icon ui not updating Signed-off-by: Sahil Yeole --- flutter/lib/common/widgets/peer_tab_page.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index fb7ef39b2..8510adee3 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -791,6 +791,7 @@ class _PeerViewDropdownState extends State { (PeerUiType? v) async { if (v != null) { peerCardUiType.value = v; + setState(() {}); await bind.setLocalFlutterOption( k: "peer-card-ui-type", v: peerCardUiType.value.index.toString(), From c522987b6f4f65f10005b26920948505a873dad2 Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Thu, 26 Oct 2023 05:16:27 +0530 Subject: [PATCH 107/114] fix list view on ab when id panel Signed-off-by: Sahil Yeole --- flutter/lib/common/widgets/peers_view.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/flutter/lib/common/widgets/peers_view.dart b/flutter/lib/common/widgets/peers_view.dart index 48fced275..24949b94a 100644 --- a/flutter/lib/common/widgets/peers_view.dart +++ b/flutter/lib/common/widgets/peers_view.dart @@ -191,14 +191,15 @@ class _PeersViewState extends State<_PeersView> with WindowListener { ); final windowWidth = MediaQuery.of(context).size.width; final model = Provider.of(context); + final hideAbTagsPanel = bind.mainGetLocalOption(key: "hideAbTagsPanel").isNotEmpty; return isDesktop ? Obx( () => SizedBox( width: peerCardUiType.value != PeerUiType.list ? 220 - : model.currentTab == PeerTabIndex.group.index? - windowWidth - 390 : - windowWidth - 227, + : model.currentTab == PeerTabIndex.group.index || (model.currentTab == PeerTabIndex.ab.index && !hideAbTagsPanel) + ? windowWidth - 390 : + windowWidth - 227, height: peerCardUiType.value == PeerUiType.grid ? 140 : peerCardUiType.value != PeerUiType.list ? 42 : 45, child: visibilityChild, From 55f3b93958e65982928e8ba2edccca94c0b145cb Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Thu, 26 Oct 2023 05:25:54 +0530 Subject: [PATCH 108/114] fix peer view menu position Signed-off-by: Sahil Yeole --- flutter/lib/common/widgets/peer_tab_page.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index 8510adee3..e3b57c09b 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -763,6 +763,8 @@ class PeerViewDropdown extends StatefulWidget { } class _PeerViewDropdownState extends State { + RelativeRect menuPos = RelativeRect.fromLTRB(0, 0, 0, 0); + @override Widget build(BuildContext context) { final List types = [PeerUiType.grid, PeerUiType.tile, PeerUiType.list]; @@ -802,7 +804,6 @@ class _PeerViewDropdownState extends State { )))); } - var menuPos = RelativeRect.fromLTRB(0, 0, 0, 0); return _hoverAction( context: context, child: Tooltip( @@ -818,7 +819,9 @@ class _PeerViewDropdownState extends State { onTapDown: (details) { final x = details.globalPosition.dx; final y = details.globalPosition.dy; - menuPos = RelativeRect.fromLTRB(x, y, x, y); + setState(() { + menuPos = RelativeRect.fromLTRB(x, y, x, y); + }); }, onTap: () => showMenu( context: context, From 23b911297e3e19bc3b7e494d3a19f92445eb21eb Mon Sep 17 00:00:00 2001 From: Sahil Yeole Date: Thu, 26 Oct 2023 05:39:15 +0530 Subject: [PATCH 109/114] add langs for change peer view menu Signed-off-by: Sahil Yeole --- src/lang/ar.rs | 4 ++++ src/lang/ca.rs | 4 ++++ src/lang/cn.rs | 4 ++++ src/lang/cs.rs | 4 ++++ src/lang/da.rs | 4 ++++ src/lang/de.rs | 4 ++++ src/lang/el.rs | 4 ++++ src/lang/eo.rs | 4 ++++ src/lang/es.rs | 4 ++++ src/lang/fa.rs | 4 ++++ src/lang/fr.rs | 4 ++++ src/lang/hu.rs | 4 ++++ src/lang/id.rs | 4 ++++ src/lang/it.rs | 4 ++++ src/lang/ja.rs | 4 ++++ src/lang/ko.rs | 4 ++++ src/lang/kz.rs | 4 ++++ src/lang/lt.rs | 4 ++++ src/lang/lv.rs | 4 ++++ src/lang/nl.rs | 4 ++++ src/lang/pl.rs | 4 ++++ src/lang/pt_PT.rs | 4 ++++ src/lang/ptbr.rs | 4 ++++ src/lang/ro.rs | 4 ++++ src/lang/ru.rs | 4 ++++ src/lang/sk.rs | 4 ++++ src/lang/sl.rs | 4 ++++ src/lang/sq.rs | 4 ++++ src/lang/sr.rs | 4 ++++ src/lang/sv.rs | 4 ++++ src/lang/template.rs | 4 ++++ src/lang/th.rs | 4 ++++ src/lang/tr.rs | 4 ++++ src/lang/tw.rs | 4 ++++ src/lang/ua.rs | 4 ++++ src/lang/vn.rs | 4 ++++ 36 files changed, 144 insertions(+) diff --git a/src/lang/ar.rs b/src/lang/ar.rs index 425f49d3a..0e2a1c7f1 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 8057430e5..9d408bf04 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 0be9738e8..971a966fe 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "在单个窗口中打开显示器"), ("Use all my displays for the remote session", "将我的所有显示器用于远程会话"), ("selinux_tip", "SELinux 处于启用状态,RustDesk 可能无法作为被控正常运行。"), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index c7e620665..12e462318 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Zobrazit obrazovky jako jednotlivá okna"), ("Use all my displays for the remote session", "Použít všechny mé obrazovky pro vzdálenou relaci"), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 634c7e8a9..7bc24274f 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 9bc00212f..1b207db52 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Jeden Bildschirm in einem eigenen Fenster anzeigen"), ("Use all my displays for the remote session", "Alle meine Bildschirme für die Fernsitzung verwenden"), ("selinux_tip", "SELinux ist auf Ihrem Gerät aktiviert, was dazu führen kann, dass RustDesk als kontrollierte Seite nicht richtig läuft."), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index baf16f82e..525c8df36 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 5c3c3eec1..6ce06de36 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 32635973f..e843ab0da 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Mostrar pantallas como ventanas individuales"), ("Use all my displays for the remote session", "Usar todas mis pantallas para la sesión remota"), ("selinux_tip", "SELinux está activado en tu dispositivo, lo que puede hacer que RustDesk no se ejecute correctamente como lado controlado."), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 28acc2c13..0ee786919 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index a2bc13a77..f9cd3e153 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index e56cad01e..b7db1f6c6 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index f0306b962..5b353eb20 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Tampilkan dengan jendela terpisah"), ("Use all my displays for the remote session", "Gunakan semua layar untuk sesi remote"), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index caeeec340..cf00bcfab 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -567,5 +567,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("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."), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 51496107f..99c47a7bc 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 49cfd2931..641b20b7d 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 5fc4a4795..3d9065756 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 2c3551989..53f79603f 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index 47aa9c22d..f5718fa99 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -566,5 +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"), ("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."), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 0365206a9..e07cdbb03 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Beeldschermen weergeven als afzonderlijke vensters"), ("Use all my displays for the remote session", "Gebruik al mijn beeldschermen voor de externe sessie"), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index f82cd4588..74b82f8e8 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Pokaż ekrany w osobnych oknach"), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 979add253..53b5458ea 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index fac32ccf1..2e59b1d0d 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 83392ed77..6a0ccd119 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index e7d90d2b8..b2b0882c7 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Показывать дисплеи в отдельных окнах"), ("Use all my displays for the remote session", "Использовать все мои дисплеи для удалённого сеанса"), ("selinux_tip", "На вашем устройстве включён SELinux, что может помешать правильной работе RustDesk на контролируемой стороне."), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 07029c213..2615c7614 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 83594ea75..6b805897b 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index f9f49345d..813b28af7 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 956be5e33..0c6c2b42f 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 7a1faa19a..4d5561087 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 6b6f28e5f..9e647254b 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 89b753bc6..5f35ba4e5 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index b1f3f3cd2..9ba3d1e9d 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index cb7d7516a..f70c3d284 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 05a74f633..610777855 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Відображати дисплеї в якості окремих вікон"), ("Use all my displays for the remote session", "Використовувати всі мої дисплеї для віддаленого сеансу"), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 9c259b8fa..f166f2482 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -566,5 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), + ("Change View", ""), + ("Big Tiles", ""), + ("Small Tiles", ""), + ("List", ""), ].iter().cloned().collect(); } From f853f20b0c6a9456b0f2b02b0b9a72c4bb146351 Mon Sep 17 00:00:00 2001 From: solokot Date: Thu, 26 Oct 2023 07:54:13 +0300 Subject: [PATCH 110/114] Update ru.rs --- src/lang/ru.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lang/ru.rs b/src/lang/ru.rs index b2b0882c7..cee936257 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Показывать дисплеи в отдельных окнах"), ("Use all my displays for the remote session", "Использовать все мои дисплеи для удалённого сеанса"), ("selinux_tip", "На вашем устройстве включён SELinux, что может помешать правильной работе RustDesk на контролируемой стороне."), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), - ("List", ""), + ("Change View", "Вид"), + ("Big Tiles", "Большие значки"), + ("Small Tiles", "Маленькие значки"), + ("List", "Список"), ].iter().cloned().collect(); } From 0fe80e8e1f244a134423f5b2409e05635bb5c842 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Thu, 26 Oct 2023 13:09:19 +0800 Subject: [PATCH 111/114] unify text style --- flutter/lib/common/widgets/peer_tab_page.dart | 6 +++--- src/lang/ar.rs | 6 +++--- src/lang/ca.rs | 6 +++--- src/lang/cn.rs | 6 +++--- src/lang/cs.rs | 6 +++--- src/lang/da.rs | 6 +++--- src/lang/de.rs | 6 +++--- src/lang/el.rs | 6 +++--- src/lang/eo.rs | 6 +++--- src/lang/es.rs | 6 +++--- src/lang/fa.rs | 6 +++--- src/lang/fr.rs | 6 +++--- src/lang/hu.rs | 6 +++--- src/lang/id.rs | 6 +++--- src/lang/it.rs | 6 +++--- src/lang/ja.rs | 6 +++--- src/lang/ko.rs | 6 +++--- src/lang/kz.rs | 6 +++--- src/lang/lt.rs | 6 +++--- src/lang/lv.rs | 6 +++--- src/lang/nl.rs | 6 +++--- src/lang/pl.rs | 6 +++--- src/lang/pt_PT.rs | 6 +++--- src/lang/ptbr.rs | 6 +++--- src/lang/ro.rs | 6 +++--- src/lang/ru.rs | 6 +++--- src/lang/sk.rs | 6 +++--- src/lang/sl.rs | 6 +++--- src/lang/sq.rs | 6 +++--- src/lang/sr.rs | 6 +++--- src/lang/sv.rs | 6 +++--- src/lang/template.rs | 6 +++--- src/lang/th.rs | 6 +++--- src/lang/tr.rs | 6 +++--- src/lang/tw.rs | 6 +++--- src/lang/ua.rs | 6 +++--- src/lang/vn.rs | 6 +++--- 37 files changed, 111 insertions(+), 111 deletions(-) diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index e3b57c09b..d472d086f 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -776,7 +776,7 @@ class _PeerViewDropdownState extends State { items.add(PopupMenuItem( height: 36, enabled: false, - child: Text(translate("Change View"), style: style))); + child: Text(translate("Change view"), style: style))); for (var e in PeerUiType.values) { items.add(PopupMenuItem( height: 36, @@ -785,7 +785,7 @@ class _PeerViewDropdownState extends State { height: 36, child: getRadio( Text(translate( - types.indexOf(e) == 0 ? 'Big Tiles' : types.indexOf(e) == 1 ? 'Small Tiles' : 'List' + types.indexOf(e) == 0 ? 'Big tiles' : types.indexOf(e) == 1 ? 'Small tiles' : 'List' ), style: style), e, peerCardUiType.value, @@ -807,7 +807,7 @@ class _PeerViewDropdownState extends State { return _hoverAction( context: context, child: Tooltip( - message: translate('Change View'), + message: translate('Change view'), child: Icon( peerCardUiType.value == PeerUiType.grid ? Icons.grid_view_rounded diff --git a/src/lang/ar.rs b/src/lang/ar.rs index 0e2a1c7f1..a63e786d1 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 9d408bf04..ff43d0ef4 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 971a966fe..c544d225c 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "在单个窗口中打开显示器"), ("Use all my displays for the remote session", "将我的所有显示器用于远程会话"), ("selinux_tip", "SELinux 处于启用状态,RustDesk 可能无法作为被控正常运行。"), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 12e462318..3ac90b7b5 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Zobrazit obrazovky jako jednotlivá okna"), ("Use all my displays for the remote session", "Použít všechny mé obrazovky pro vzdálenou relaci"), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 7bc24274f..40f1fbfb0 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 1b207db52..9696b62b2 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Jeden Bildschirm in einem eigenen Fenster anzeigen"), ("Use all my displays for the remote session", "Alle meine Bildschirme für die Fernsitzung verwenden"), ("selinux_tip", "SELinux ist auf Ihrem Gerät aktiviert, was dazu führen kann, dass RustDesk als kontrollierte Seite nicht richtig läuft."), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index 525c8df36..72a4c492c 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 6ce06de36..1d91e7b7f 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index e843ab0da..26bb408ac 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Mostrar pantallas como ventanas individuales"), ("Use all my displays for the remote session", "Usar todas mis pantallas para la sesión remota"), ("selinux_tip", "SELinux está activado en tu dispositivo, lo que puede hacer que RustDesk no se ejecute correctamente como lado controlado."), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 0ee786919..69f883b89 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index f9cd3e153..e15bc38ba 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index b7db1f6c6..f18013423 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 5b353eb20..ce9e359b1 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Tampilkan dengan jendela terpisah"), ("Use all my displays for the remote session", "Gunakan semua layar untuk sesi remote"), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index cf00bcfab..0c0989764 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -567,9 +567,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("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."), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 99c47a7bc..9c60683f3 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 641b20b7d..189fa640a 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 3d9065756..b6475c5f9 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 53f79603f..ebeebaaa0 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index f5718fa99..033b45d0d 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -566,9 +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"), ("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."), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index e07cdbb03..9d8445825 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Beeldschermen weergeven als afzonderlijke vensters"), ("Use all my displays for the remote session", "Gebruik al mijn beeldschermen voor de externe sessie"), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 74b82f8e8..0c474aea0 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Pokaż ekrany w osobnych oknach"), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 53b5458ea..77c451035 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 2e59b1d0d..4fedb1636 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 6a0ccd119..700cf452f 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index b2b0882c7..e926b583d 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Показывать дисплеи в отдельных окнах"), ("Use all my displays for the remote session", "Использовать все мои дисплеи для удалённого сеанса"), ("selinux_tip", "На вашем устройстве включён SELinux, что может помешать правильной работе RustDesk на контролируемой стороне."), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 2615c7614..c6f6d5724 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 6b805897b..4e0c394d6 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index 813b28af7..2b37c35b2 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index 0c6c2b42f..63d0190ef 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 4d5561087..c8b2f22a6 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 9e647254b..b358f3709 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 5f35ba4e5..606993498 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 9ba3d1e9d..ecab140e3 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index f70c3d284..d5a233f02 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 610777855..f8bf4c278 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", "Відображати дисплеї в якості окремих вікон"), ("Use all my displays for the remote session", "Використовувати всі мої дисплеї для віддаленого сеансу"), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index f166f2482..103ef2663 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -566,9 +566,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Show displays as individual windows", ""), ("Use all my displays for the remote session", ""), ("selinux_tip", ""), - ("Change View", ""), - ("Big Tiles", ""), - ("Small Tiles", ""), + ("Change view", ""), + ("Big tiles", ""), + ("Small tiles", ""), ("List", ""), ].iter().cloned().collect(); } From 17285720f1b8b09bed046bd015ecd3749145a344 Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 26 Oct 2023 16:11:08 +0800 Subject: [PATCH 112/114] fix, dialog blocks tabs on the remote page Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 39 ++++++++++++++++++---- src/flutter_ffi.rs | 1 + 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index cb9cf49c9..6d0ba09cd 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -80,7 +80,7 @@ class _RemotePageState extends State late RxBool _keyboardEnabled; final Map _renderTextures = {}; - final _blockableOverlayState = BlockableOverlayState(); + var _blockableOverlayState = BlockableOverlayState(); final FocusNode _rawKeyFocusNode = FocusNode(debugLabel: "rawkeyFocusNode"); @@ -253,9 +253,9 @@ class _RemotePageState extends State onEnterOrLeaveImageCleaner: () => _onEnterOrLeaveImage4Toolbar = null, setRemoteState: setState, ); - return Scaffold( - backgroundColor: Theme.of(context).colorScheme.background, - body: Stack( + + bodyWidget() { + return Stack( children: [ Container( color: Colors.black, @@ -281,7 +281,7 @@ class _RemotePageState extends State }, inputModel: _ffi.inputModel, child: getBodyForDesktop(context))), - Obx(() => Stack( + Stack( children: [ _ffi.ffiModel.pi.isSet.isTrue && _ffi.ffiModel.waitForFirstImage.isTrue @@ -298,9 +298,34 @@ class _RemotePageState extends State : remoteToolbar(context), _ffi.ffiModel.pi.isSet.isFalse ? emptyOverlay() : Offstage(), ], - )), + ), ], - ), + ); + } + + return Scaffold( + backgroundColor: Theme.of(context).colorScheme.background, + body: Obx(() { + final imageReady = _ffi.ffiModel.pi.isSet.isTrue && + _ffi.ffiModel.waitForFirstImage.isFalse; + if (imageReady) { + // dismissAll() is ensure the state is clean. + // It's ok to call dismissAll() here. + _ffi.dialogManager.dismissAll(); + // Recreate the block state to refresh the state. + _blockableOverlayState = BlockableOverlayState(); + _blockableOverlayState.applyFfi(_ffi); + // Block the whole bodyWidget() when dialog shows. + return BlockableOverlay( + underlying: bodyWidget(), + state: _blockableOverlayState, + ); + } else { + // _blockableOverlayState is not recreated here. + // The block state for the toolbar will not work on reconnecting, but it's ok. + return bodyWidget(); + } + }), ); } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 9661aa8b3..1484d2440 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -210,6 +210,7 @@ pub fn session_reconnect(session_id: SessionID, force_relay: bool) { if let Some(session) = sessions::get_session_by_session_id(&session_id) { session.reconnect(force_relay); } + session_on_waiting_for_image_dialog_show(session_id); } pub fn session_toggle_option(session_id: SessionID, value: String) { From 53e310ff77b861e202ef4985fa2b6c2b0ff4a394 Mon Sep 17 00:00:00 2001 From: 21pages Date: Thu, 26 Oct 2023 16:05:49 +0800 Subject: [PATCH 113/114] fix close on taskbar Signed-off-by: 21pages --- .../lib/desktop/widgets/tabbar_widget.dart | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 08b0ce277..7f1449ca4 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -448,6 +448,7 @@ class DesktopTab extends StatelessWidget { isMainWindow: isMainWindow, tabType: tabType, state: state, + tabController: controller, tail: tail, showMinimize: showMinimize, showMaximize: showMaximize, @@ -463,6 +464,7 @@ class WindowActionPanel extends StatefulWidget { final bool isMainWindow; final DesktopTabType tabType; final Rx state; + final DesktopTabController tabController; final bool showMinimize; final bool showMaximize; @@ -475,6 +477,7 @@ class WindowActionPanel extends StatefulWidget { required this.isMainWindow, required this.tabType, required this.state, + required this.tabController, this.tail, this.showMinimize = true, this.showMaximize = true, @@ -580,9 +583,32 @@ class WindowActionPanelState extends State void onWindowClose() async { mainWindowClose() async => await windowManager.hide(); notMainWindowClose(WindowController controller) async { - await controller.hide(); - await rustDeskWinManager - .call(WindowType.Main, kWindowEventHide, {"id": kWindowId!}); + if (widget.tabController.length == 0) { + debugPrint("close emtpy multiwindow, hide"); + await controller.hide(); + await rustDeskWinManager + .call(WindowType.Main, kWindowEventHide, {"id": kWindowId!}); + } else { + debugPrint("close not emtpy multiwindow from taskbar"); + if (Platform.isWindows) { + await controller.show(); + await controller.focus(); + final res = await widget.onClose?.call() ?? true; + if (res) { + Future.delayed(Duration.zero, () async { + // onWindowClose will be called again to hide + await WindowController.fromWindowId(kWindowId!).close(); + }); + } + } else { + // ubuntu22.04 windowOnTop not work from taskbar + widget.tabController.clear(); + Future.delayed(Duration.zero, () async { + // onWindowClose will be called again to hide + await WindowController.fromWindowId(kWindowId!).close(); + }); + } + } } macOSWindowClose( From ee3750121ce16f57f0063eced87dce4d9995feca Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 26 Oct 2023 17:03:54 +0800 Subject: [PATCH 114/114] fix comments Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_page.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_page.dart b/flutter/lib/desktop/pages/remote_page.dart index 6d0ba09cd..ffc29b02f 100644 --- a/flutter/lib/desktop/pages/remote_page.dart +++ b/flutter/lib/desktop/pages/remote_page.dart @@ -309,20 +309,20 @@ class _RemotePageState extends State final imageReady = _ffi.ffiModel.pi.isSet.isTrue && _ffi.ffiModel.waitForFirstImage.isFalse; if (imageReady) { - // dismissAll() is ensure the state is clean. + // `dismissAll()` is to ensure that the state is clean. // It's ok to call dismissAll() here. _ffi.dialogManager.dismissAll(); // Recreate the block state to refresh the state. _blockableOverlayState = BlockableOverlayState(); _blockableOverlayState.applyFfi(_ffi); - // Block the whole bodyWidget() when dialog shows. + // Block the whole `bodyWidget()` when dialog shows. return BlockableOverlay( underlying: bodyWidget(), state: _blockableOverlayState, ); } else { - // _blockableOverlayState is not recreated here. - // The block state for the toolbar will not work on reconnecting, but it's ok. + // `_blockableOverlayState` is not recreated here. + // The toolbar's block state won't work properly when reconnecting, but that's okay. return bodyWidget(); } }),